Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 11 Mar 2016 16:58:46 +0100
changeset 288453 6730d93dde8d2f53ee62cd19c54238ea739b57f3
parent 288452 bfedd977e27850b817f541d048754fe5a9bd9a41 (current diff)
parent 288257 f907faa919be95dd411706b0c69a1acad340f81d (diff)
child 288454 fd24de5fb7db406838f419b4780f809cf012e0a1
push id73422
push userryanvm@gmail.com
push dateSat, 12 Mar 2016 20:24:46 +0000
treeherdermozilla-inbound@d1d47ba19ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to fx-team
browser/components/extensions/ext-bookmarks.js
dom/base/nsGlobalWindow.cpp
dom/bluetooth/common/BluetoothUuid.cpp
dom/bluetooth/common/BluetoothUuid.h
js/src/threading/ExclusiveData.cpp
memory/build/Makefile.in
memory/replace/jemalloc/Makefile.in
mobile/android/confvars.sh
old-configure.in
testing/firefox-ui/tests/MANIFEST.in
testing/firefox-ui/tests/firefox_ui_tests/__init__.py
testing/firefox-ui/tests/firefox_ui_tests/functional/keyboard_shortcuts/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/functional/keyboard_shortcuts/test_browser_window.py
testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_access_locationbar.py
testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_escape_autocomplete.py
testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_favicon_in_autocomplete.py
testing/firefox-ui/tests/firefox_ui_tests/functional/locationbar/test_suggest_bookmarks.py
testing/firefox-ui/tests/firefox_ui_tests/functional/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/functional/private_browsing/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/functional/private_browsing/test_about_private_browsing.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_dv_certificate.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_enable_privilege.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_ev_certificate.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_mixed_content_page.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_mixed_script_content_blocking.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_no_certificate.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_safe_browsing_notification.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_safe_browsing_warning_pages.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_security_notification.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_ssl_disabled_error_page.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_ssl_status_after_restart.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_submit_unencrypted_info_warning.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_unknown_issuer.py
testing/firefox-ui/tests/firefox_ui_tests/functional/security/test_untrusted_connection_error_page.py
testing/firefox-ui/tests/firefox_ui_tests/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_about_window.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_appinfo.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_l10n.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_menubar.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_page_info_window.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_places.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_prefs.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_security.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_software_update.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_tabbar.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_toolbars.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_update_wizard.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_utils.py
testing/firefox-ui/tests/firefox_ui_tests/puppeteer/test_windows.py
testing/firefox-ui/tests/firefox_ui_tests/resources/cookies/cookie_single.html
testing/firefox-ui/tests/firefox_ui_tests/resources/images/firefox_favicon.ico
testing/firefox-ui/tests/firefox_ui_tests/resources/images/mozilla_favicon.ico
testing/firefox-ui/tests/firefox_ui_tests/resources/images/mozilla_logo.jpg
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla.html
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla_community.html
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla_contribute.html
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla_governance.html
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla_grants.html
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla_mission.html
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla_organizations.html
testing/firefox-ui/tests/firefox_ui_tests/resources/layout/mozilla_projects.html
testing/firefox-ui/tests/firefox_ui_tests/resources/private_browsing/about.html
testing/firefox-ui/tests/firefox_ui_tests/resources/security/enable_privilege.html
testing/firefox-ui/tests/firefox_ui_tests/update/direct/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/update/direct/test_direct_update.py
testing/firefox-ui/tests/firefox_ui_tests/update/fallback/manifest.ini
testing/firefox-ui/tests/firefox_ui_tests/update/fallback/test_fallback_update.py
testing/firefox-ui/tests/setup.py
testing/mozharness/configs/android/android_panda_releng.py
testing/mozharness/configs/android/android_panda_talos_releng.py
testing/mozharness/configs/hazards/build_b2g.py
testing/mozharness/scripts/android_panda.py
testing/mozharness/scripts/android_panda_talos.py
testing/mozharness/scripts/hazard_build.py
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -38,19 +38,18 @@ TreeWalker::
 
 TreeWalker::
   TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) :
   mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode),
   mARIAOwnsIdx(0),
   mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags),
   mPhase(eAtStart)
 {
+  MOZ_ASSERT(mFlags & eWalkCache, "This constructor cannot be used for tree creation");
   MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
-  MOZ_ASSERT(mDoc->GetAccessibleOrContainer(aAnchorNode) == mContext,
-             "Unexpected anchor node was given");
 
   mChildFilter |= mContext->NoXBLKids() ?
     nsIContent::eAllButXBL : nsIContent::eAllChildren;
 
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::~TreeWalker()
@@ -106,17 +105,17 @@ TreeWalker::Seek(nsIContent* aChildNode)
       return true;
     }
   } while (true);
 
   return false;
 }
 
 Accessible*
-TreeWalker::Next()
+TreeWalker::Next(nsIContent* aStopNode)
 {
   if (mStateStack.IsEmpty()) {
     if (mPhase == eAtEnd) {
       return nullptr;
     }
 
     if (mPhase == eAtDOM || mPhase == eAtARIAOwns) {
       mPhase = eAtARIAOwns;
@@ -135,70 +134,72 @@ TreeWalker::Next()
     }
 
     mPhase = eAtDOM;
     PushState(mAnchorNode, true);
   }
 
   dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
+    if (aStopNode && top->Get() == aStopNode) {
+      return nullptr;
+    }
+
     while (nsIContent* childNode = top->GetNextChild()) {
       bool skipSubtree = false;
-      Accessible* child = nullptr;
-      if (mFlags & eWalkCache) {
-        child = mDoc->GetAccessible(childNode);
-      }
-      else if (mContext->IsAcceptableChild(childNode)) {
-        child = GetAccService()->
-          GetOrCreateAccessible(childNode, mContext, &skipSubtree);
-      }
-
-      // Ignore the accessible and its subtree if it was repositioned by means
-      // of aria-owns.
+      Accessible* child = AccessibleFor(childNode, mFlags, &skipSubtree);
       if (child) {
-        if (child->IsRelocated()) {
-          continue;
-        }
         return child;
       }
 
-      // Walk down into subtree to find accessibles.
+      // Walk down the subtree if allowed, otherwise check if we have reached
+      // a stop node.
       if (!skipSubtree && childNode->IsElement()) {
         top = PushState(childNode, true);
       }
+      else if (childNode == aStopNode) {
+        return nullptr;
+      }
     }
     top = PopState();
   }
 
   // If we traversed the whole subtree of the anchor node. Move to next node
-  // relative anchor node within the context subtree if possible.
-  if (mFlags != eWalkContextTree)
-    return Next();
+  // relative anchor node within the context subtree if asked.
+  if (mFlags != eWalkContextTree) {
+    // eWalkCache flag presence indicates that the search is scoped to the
+    // anchor (no ARIA owns stuff).
+    if (mFlags & eWalkCache) {
+      mPhase = eAtEnd;
+      return nullptr;
+    }
+    return Next(aStopNode);
+  }
 
   nsINode* contextNode = mContext->GetNode();
   while (mAnchorNode != contextNode) {
     nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
     if (!parentNode || !parentNode->IsElement())
       return nullptr;
 
     nsIContent* parent = parentNode->AsElement();
     top = PushState(parent, true);
     if (top->Seek(mAnchorNode)) {
       mAnchorNode = parent;
-      return Next();
+      return Next(aStopNode);
     }
 
     // XXX We really should never get here, it means we're trying to find an
     // accessible for a dom node where iterating over its parent's children
     // doesn't return it. However this sometimes happens when we're asked for
     // the nearest accessible to place holder content which we ignore.
     mAnchorNode = parent;
   }
 
-  return Next();
+  return Next(aStopNode);
 }
 
 Accessible*
 TreeWalker::Prev()
 {
   if (mStateStack.IsEmpty()) {
     if (mPhase == eAtStart || mPhase == eAtDOM) {
       mPhase = eAtStart;
@@ -223,27 +224,20 @@ TreeWalker::Prev()
       mPhase = eAtDOM;
       PushState(mAnchorNode, false);
     }
   }
 
   dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
     while (nsIContent* childNode = top->GetPreviousChild()) {
+      // No accessible creation on the way back.
       bool skipSubtree = false;
-
-      // No accessible creation on the way back.
-      Accessible* child = mDoc->GetAccessible(childNode);
-
-      // Ignore the accessible and its subtree if it was repositioned by means of
-      // aria-owns.
+      Accessible* child = AccessibleFor(childNode, eWalkCache, &skipSubtree);
       if (child) {
-        if (child->IsRelocated()) {
-          continue;
-        }
         return child;
       }
 
       // Walk down into subtree to find accessibles.
       if (!skipSubtree && childNode->IsElement()) {
         top = PushState(childNode, true);
       }
     }
@@ -273,15 +267,37 @@ TreeWalker::Prev()
 
     mAnchorNode = parent;
   }
 
   mPhase = eAtStart;
   return nullptr;
 }
 
+Accessible*
+TreeWalker::AccessibleFor(nsIContent* aNode, uint32_t aFlags, bool* aSkipSubtree)
+{
+  Accessible* child = nullptr;
+  if (aFlags & eWalkCache) {
+    child = mDoc->GetAccessible(aNode);
+  }
+  else if (mContext->IsAcceptableChild(aNode)) {
+    child = GetAccService()->
+      GetOrCreateAccessible(aNode, mContext, aSkipSubtree);
+  }
+
+  // Ignore the accessible and its subtree if it was repositioned by means
+  // of aria-owns.
+  if (child && child->IsRelocated()) {
+    *aSkipSubtree = true;
+    return nullptr;
+  }
+
+  return child;
+}
+
 dom::AllChildrenIterator*
 TreeWalker::PopState()
 {
   size_t length = mStateStack.Length();
   mStateStack.RemoveElementAt(length - 1);
-  return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1];
+  return mStateStack.IsEmpty() ? nullptr : &mStateStack.LastElement();
 }
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -40,45 +40,51 @@ public:
   /**
    * Used to navigate the accessible children relative to the anchor.
    *
    * @param aContext [in] container accessible for the given node, used to
    *                   define accessible context
    * @param aAnchorNode [in] the node the search will be prepared relative to
    * @param aFlags   [in] flags (see enum above)
    */
-  TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags = 0);
+  TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags = eWalkCache);
 
   ~TreeWalker();
 
   /**
    * Clears the tree walker state and resets it to the given child within
    * the anchor.
    */
   bool Seek(nsIContent* aChildNode);
 
   /**
    * Return the next/prev accessible.
    *
    * @note Returned accessible is bound to the document, if the accessible is
    *       rejected during tree creation then the caller should be unbind it
    *       from the document.
    */
-  Accessible* Next();
+  Accessible* Next(nsIContent* aStopNode = nullptr);
   Accessible* Prev();
 
   Accessible* Context() const { return mContext; }
   DocAccessible* Document() const { return mDoc; }
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
   TreeWalker& operator =(const TreeWalker&);
 
   /**
+   * Return an accessible for the given node if any.
+   */
+  Accessible* AccessibleFor(nsIContent* aNode, uint32_t aFlags,
+                            bool* aSkipSubtree);
+
+  /**
    * Create new state for the given node and push it on top of stack / at bottom
    * of stack.
    *
    * @note State stack is used to navigate up/down the DOM subtree during
    *        accessible children search.
    */
   dom::AllChildrenIterator* PushState(nsIContent* aContent,
                                       bool aStartAtBeginning)
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -1790,44 +1790,19 @@ DocAccessible::UpdateTreeOnRemoval(Acces
 
   uint32_t updateFlags = eNoAccessible;
   RefPtr<AccReorderEvent> reorderEvent = new AccReorderEvent(aContainer);
   AutoTreeMutation mut(aContainer);
 
   if (child) {
     updateFlags |= UpdateTreeInternal(child, false, reorderEvent);
   } else {
-    // aChildNode may not coorespond to a particular accessible, to handle
-    // this we go through all the children of aContainer.  Then if a child
-    // has aChildNode as an ancestor, or does not have the node for
-    // aContainer as an ancestor remove that child of aContainer.  Note that
-    // when we are called aChildNode may already have been removed from the DOM
-    // so we can't expect it to have a parent or what was it's parent to have
-    // it as a child.
-    nsINode* containerNode = aContainer->GetNode();
-    for (uint32_t idx = 0; idx < aContainer->ContentChildCount();) {
-      Accessible* child = aContainer->ContentChildAt(idx);
-
-      // If accessible doesn't have its own content then we assume parent
-      // will handle its update.  If child is DocAccessible then we don't
-      // handle updating it here either.
-      if (!child->HasOwnContent() || child->IsDoc()) {
-        idx++;
-        continue;
-      }
-
-      nsINode* childNode = child->GetContent();
-      while (childNode != aChildNode && childNode != containerNode &&
-             (childNode = childNode->GetParentNode()));
-
-      if (childNode != containerNode) {
-        updateFlags |= UpdateTreeInternal(child, false, reorderEvent);
-      } else {
-        idx++;
-      }
+    TreeWalker walker(aContainer, aChildNode, TreeWalker::eWalkCache);
+    while (Accessible* child = walker.Next()) {
+      updateFlags |= UpdateTreeInternal(child, false, reorderEvent);
     }
   }
 
   // Content insertion/removal is not cause of accessible tree change.
   if (updateFlags == eNoAccessible)
     return;
 
   MaybeNotifyOfValueChange(aContainer);
--- a/accessible/tests/mochitest/events/test_aria_menu.html
+++ b/accessible/tests/mochitest/events/test_aria_menu.html
@@ -148,16 +148,17 @@
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Do tests
 
     var gQueue = null;
 
     //gA11yEventDumpToConsole = true; // debuging
+    //enableLogging("tree,verbose");
 
     function doTests()
     {
       gQueue = new eventQueue();
 
       gQueue.push(new focusMenu("menubar2", "menu-help"));
       gQueue.push(new focusMenu("menubar", "menu-file", "menubar2"));
       gQueue.push(new showMenu("menupopup-file", "menu-file", kViaDisplayStyle));
--- a/accessible/tests/mochitest/treeupdate/test_ariaowns.html
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -467,16 +467,53 @@
       }
 
       this.getID = function rearrangeARIAOwns_getID()
       {
         return `Rearrange @aria-owns attribute to '${aAttr}'`;
       }
     }
 
+    function removeNotARIAOwnedEl(aContainer, aChild)
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_REORDER, aContainer)
+      ];
+
+      this.invoke = function removeNotARIAOwnedEl_invoke()
+      {
+        dumpTree(aContainer, "before");
+        var tree = {
+          SECTION: [
+            { TEXT_LEAF: [ ] },
+            { GROUPING: [ ] }
+          ]
+        };
+        testAccessibleTree(aContainer, tree);
+
+        getNode(aContainer).removeChild(getNode(aChild));
+      }
+
+      this.finalCheck = function removeNotARIAOwnedEl_finalCheck()
+      {
+        dumpTree(aContainer, "after");
+        var tree = {
+          SECTION: [
+            { GROUPING: [ ] }
+          ]
+        };
+        testAccessibleTree(aContainer, tree);
+      }
+
+      this.getID = function removeNotARIAOwnedEl_getID()
+      {
+        return `remove not ARIA owned child`;
+      }
+    }
+
 
     ////////////////////////////////////////////////////////////////////////////
     // Test
     ////////////////////////////////////////////////////////////////////////////
 
     //gA11yEventDumpToConsole = true;
     //enableLogging("tree,verbose"); // debug stuff
 
@@ -511,16 +548,18 @@
         "t5_container", "t5_checkbox t5_radio t5_button",
         [ "t5_checkbox", "t5_radio", "t5_button" ],
         [ "CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON" ]));
       gQueue.push(new rearrangeARIAOwns(
         "t5_container", "t5_radio t5_button t5_checkbox",
         [ "t5_radio", "t5_button" ],
         [ "RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON" ]));
 
+      gQueue.push(new removeNotARIAOwnedEl("t6_container", "t6_span"));
+
       gQueue.invoke(); // SimpleTest.finish() will be called in the end
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
 
   </script>
 </head>
@@ -558,11 +597,16 @@
     <div id="t4_child2" role="radio"></div>
   </div>
 
   <div id="t5_container">
     <div role="button" id="t5_button"></div>
     <div role="checkbox" id="t5_checkbox"></div>
     <div role="radio" id="t5_radio"></div>
   </div>
+
+  <div id="t6_container" aria-owns="t6_fake">
+    <span id="t6_span">hey</span>
+  </div>
+  <div id="t6_fake" role="group"></div>
 </body>
 
 </html>
--- a/addon-sdk/source/lib/sdk/system/environment.js
+++ b/addon-sdk/source/lib/sdk/system/environment.js
@@ -7,58 +7,27 @@
 module.metadata = {
   "stability": "stable"
 };
 
 const { Cc, Ci } = require('chrome');
 const { get, set, exists } = Cc['@mozilla.org/process/environment;1'].
                              getService(Ci.nsIEnvironment);
 
-exports.env = Proxy.create({
-  // XPCOM does not provides a way to enumerate environment variables, so we
-  // just don't support enumeration.
-  getPropertyNames: () => [],
-  getOwnPropertyNames: () => [],
-  enumerate: () => [],
-  keys: () => [],
-  // We do not support freezing, cause it would make it impossible to set new
-  // environment variables.
-  fix: () => undefined,
-  // We present all environment variables as own properties of this object,
-  // so we just delegate this call to `getOwnPropertyDescriptor`.
-  getPropertyDescriptor: function(name) {
-    return this.getOwnPropertyDescriptor(name);
-  },
-  // If environment variable with this name is defined, we generate proprety
-  // descriptor for it, otherwise fall back to `undefined` so that for consumer
-  // this property does not exists.
-  getOwnPropertyDescriptor: function(name) {
-    return !exists(name) ? undefined : {
-      value: get(name),
-      enumerable: false,    // Non-enumerable as we don't support enumeration.
-      configurable: true,   // Configurable as it may be deleted.
-      writable: true        // Writable as we do support set.
-    }
-  },
-
-  // New environment variables can be defined just by defining properties
-  // on this object.
-  defineProperty: (name, { value }) => set(name, value),
-  delete: function(name) {
-    set(name, null);
+exports.env = new Proxy({}, {
+  deleteProperty(target, property) {
+    set(property, null);
     return true;
   },
 
-  // We present all properties as own, there for we just delegate to `hasOwn`.
-  has: function(name) {
-    return this.hasOwn(name);
+  get(target, property, receiver) {
+    return get(property) || undefined;
   },
-  // We do support checks for existence of an environment variable, via `in`
-  // operator on this object.
-  hasOwn: name => exists(name),
 
-  // On property get / set we do read / write appropriate environment variables,
-  // please note though, that variables with names of standard object properties
-  // intentionally (so that this behaves as normal object) can not be
-  // read / set.
-  get: (proxy, name) => Object.prototype[name] || get(name) || undefined,
-  set: (proxy, name, value) => Object.prototype[name] || set(name, value)
+  has(target, property) {
+    return exists(property);
+  },
+
+  set(target, property, value, receiver) {
+    set(property, value);
+    return true;
+  }
 });
--- a/addon-sdk/source/test/addons/e10s-content/lib/test-content-script.js
+++ b/addon-sdk/source/test/addons/e10s-content/lib/test-content-script.js
@@ -254,32 +254,16 @@ exports["test Object Listener 2"] = crea
   ).replace("TOKEN", testHost));
 
 });
 
 var html = '<input id="input" type="text" /><input id="input3" type="checkbox" />' +
              '<input id="input2" type="checkbox" />';
 
 exports.testStringOverload = createProxyTest(html, function (helper, assert) {
-  // Proxy - toString error
-  let originalString = "string";
-  let p = Proxy.create({
-    get: function(receiver, name) {
-      if (name == "binded")
-        return originalString.toString.bind(originalString);
-      return originalString[name];
-    }
-  });
-  assert.throws(function () {
-    p.toString();
-  },
-  /toString method called on incompatible Proxy/,
-  "toString can't be called with this being the proxy");
-  assert.equal(p.binded(), "string", "but it works if we bind this to the original string");
-
   helper.createWorker(
     'new ' + function ContentScriptScope() {
       // RightJS is hacking around String.prototype, and do similar thing:
       // Pass `this` from a String prototype method.
       // It is funny because typeof this == "object"!
       // So that when we pass `this` to a native method,
       // our proxy code can fail on another even more crazy thing.
       // See following test to see what fails around proxies.
--- a/addon-sdk/source/test/test-content-script.js
+++ b/addon-sdk/source/test/test-content-script.js
@@ -254,32 +254,16 @@ exports["test Object Listener 2"] = crea
   ).replace("TOKEN", testHost));
 
 });
 
 var html = '<input id="input" type="text" /><input id="input3" type="checkbox" />' +
              '<input id="input2" type="checkbox" />';
 
 exports.testStringOverload = createProxyTest(html, function (helper, assert) {
-  // Proxy - toString error
-  let originalString = "string";
-  let p = Proxy.create({
-    get: function(receiver, name) {
-      if (name == "binded")
-        return originalString.toString.bind(originalString);
-      return originalString[name];
-    }
-  });
-  assert.throws(function () {
-    p.toString();
-  },
-  /toString method called on incompatible Proxy/,
-  "toString can't be called with this being the proxy");
-  assert.equal(p.binded(), "string", "but it works if we bind this to the original string");
-
   helper.createWorker(
     'new ' + function ContentScriptScope() {
       // RightJS is hacking around String.prototype, and do similar thing:
       // Pass `this` from a String prototype method.
       // It is funny because typeof this == "object"!
       // So that when we pass `this` to a native method,
       // our proxy code can fail on another even more crazy thing.
       // See following test to see what fails around proxies.
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1049,16 +1049,20 @@ pref("dom.wakelock.enabled", true);
 
 // Enable webapps add-ons
 pref("dom.apps.customization.enabled", true);
 pref("dom.apps.reviewer_paths", "/reviewers/,/extension/reviewers/");
 
 // New implementation to unify touch-caret and selection-carets.
 pref("layout.accessiblecaret.enabled", true);
 
+// Show the selection bars at the two ends of the selection highlight. Required
+// by the spec in bug 921965.
+pref("layout.accessiblecaret.bar.enabled", true);
+
 // APZ on real devices supports long tap events.
 #ifdef MOZ_WIDGET_GONK
 pref("layout.accessiblecaret.use_long_tap_injector", false);
 #endif
 
 // Enable sync and mozId with Firefox Accounts.
 pref("services.sync.fxaccounts.enabled", true);
 pref("identity.fxaccounts.enabled", true);
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -20,17 +20,16 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/bran
 MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_COMMON=1
 
 MOZ_WEBSMS_BACKEND=1
 MOZ_NO_SMART_CARDS=1
 MOZ_APP_STATIC_INI=1
 NSS_DISABLE_DBM=1
 MOZ_NO_EV_CERTS=1
-MOZ_DISABLE_EXPORT_JS=1
 
 MOZ_WEBSPEECH=1
 if test -n "$NIGHTLY_BUILD"; then
 MOZ_WEBSPEECH_MODELS=1
 MOZ_WEBSPEECH_POCKETSPHINX=1
 fi
 MOZ_WEBSPEECH_TEST_BACKEND=1
 
--- a/b2g/graphene/confvars.sh
+++ b/b2g/graphene/confvars.sh
@@ -28,17 +28,16 @@ MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_COMMON=1
 MOZ_CAPTIVEDETECT=1
 
 MOZ_WEBSMS_BACKEND=1
 MOZ_NO_SMART_CARDS=1
 MOZ_APP_STATIC_INI=1
 NSS_NO_LIBPKIX=1
 NSS_DISABLE_DBM=1
-MOZ_DISABLE_EXPORT_JS=1
 
 if test "$OS_TARGET" = "Android"; then
 MOZ_CAPTURE=1
 MOZ_RAW=1
 MOZ_AUDIO_CHANNEL_MANAGER=1
 fi
 
 MOZ_MEDIA_NAVIGATOR=1
--- a/browser/components/extensions/ext-bookmarks.js
+++ b/browser/components/extensions/ext-bookmarks.js
@@ -214,9 +214,8 @@ extensions.registerSchemaAPI("bookmarks"
                           .catch(error => Promise.reject({message: error.message}));
         } catch (e) {
           return Promise.reject({message: `Invalid bookmark: ${JSON.stringify(info)}`});
         }
       },
     },
   };
 });
-
--- a/browser/components/sessionstore/SessionStorage.jsm
+++ b/browser/components/sessionstore/SessionStorage.jsm
@@ -103,18 +103,17 @@ var SessionStorageInternal = {
    */
   restore: function (aDocShell, aStorageData) {
     for (let origin of Object.keys(aStorageData)) {
       let data = aStorageData[origin];
 
       let principal;
 
       try {
-        let attrs = ChromeUtils.createDefaultOriginAttributes();
-        attrs.userContextId = aDocShell.userContextId;
+        let attrs = aDocShell.getOriginAttributes();
         let originURI = Services.io.newURI(origin, null, null);
         principal = Services.scriptSecurityManager.createCodebasePrincipal(originURI, attrs);
       } catch (e) {
         console.error(e);
         continue;
       }
 
       let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
--- a/browser/config/tooltool-manifests/win32/clang.manifest
+++ b/browser/config/tooltool-manifests/win32/clang.manifest
@@ -1,23 +1,30 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
+"size": 78886322,
+"digest": "9c2c40637de27a0852aa1166f2a08159908b23f7a55855c933087c541461bbb2a1ec9e0522df0d2b9da2b2c343b673dbb5a2fa8d30216fe8acee1eb1383336ea",
+"algorithm": "sha512",
+"filename": "rustc-beta-i686-pc-windows-msvc.tar.bz2",
+"unpack": true
+},
+{
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
 },
 {
-"version": "clang 3.9.0/r259916",
-"size": 164660139,
-"digest": "7db5f16921c10023152e6a7765c6d31dfefc91a8742a14b6279bd253f86a683d8d951b17608aa200978f8cd433ead32e0ae9b53778566d2994e1db7af1df4cc4",
+"version": "clang 3.9.0/r262971",
+"size": 169861843,
+"digest": "8caa5a89aea981b618233d39f01bb934b79b85ee8167104bfa4f07936145df5e8ca5e8e007123d75ccc12d2baa926ffc827b40bf793fa9d4bc2670fa519b0ec0",
 "algorithm": "sha512",
 "filename": "clang32.tar.bz2",
 "unpack": true
 }
 ]
--- a/browser/config/tooltool-manifests/win64/clang.manifest
+++ b/browser/config/tooltool-manifests/win64/clang.manifest
@@ -1,23 +1,31 @@
 [
 {
 "size": 266240,
 "digest": "bb345b0e700ffab4d09436981f14b5de84da55a3f18a7f09ebc4364a4488acdeab8d46f447b12ac70f2da1444a68b8ce8b8675f0dae2ccf845e966d1df0f0869",
 "algorithm": "sha512",
 "filename": "mozmake.exe"
 },
 {
+"size": 80157273,
+"digest": "c4704dcc6774b9f3baaa9313192d26e36bfba2d4380d0518ee7cb89153d9adfe63f228f0ac29848f02948eb1ab7e6624ba71210f0121196d2b54ecebd640d1e6",
+"algorithm": "sha512",
+"visibility": "public",
+"filename": "rustc.tar.bz2",
+"unpack": true
+},
+{
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
 },
 {
-"version": "clang 3.9.0/r259916",
-"size": 168551971,
-"digest": "af127aba2ed881bad6e83fd162125038f2450f7b6de64efe84d1281052225ec92db6d96d6ade6ac2642f1b00761b3be5725f79c41953dc885a81185097cc81a5",
+"version": "clang 3.9.0/r262971",
+"size": 173306045,
+"digest": "806413640a964dad44c0c6055d2a89a1075730fb6f659ff37341378a14a7dc032e672941765225608b71f6b385ac721ed36bfa04eb38c211b07e2776cb72a0ee",
 "algorithm": "sha512",
 "filename": "clang64.tar.bz2",
 "unpack": true
 }
 ]
--- a/browser/confvars.sh
+++ b/browser/confvars.sh
@@ -21,17 +21,16 @@ if test "$OS_ARCH" = "WINNT"; then
     fi
   fi
 fi
 
 # Enable building ./signmar and running libmar signature tests
 MOZ_ENABLE_SIGNMAR=1
 
 MOZ_CHROME_FILE_FORMAT=omni
-MOZ_DISABLE_EXPORT_JS=1
 MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_CRYPTO=1
 MOZ_SERVICES_HEALTHREPORT=1
 MOZ_SERVICES_SYNC=1
 MOZ_SERVICES_CLOUDSYNC=1
 MOZ_APP_VERSION=$FIREFOX_VERSION
 MOZ_APP_VERSION_DISPLAY=$FIREFOX_VERSION_DISPLAY
--- a/browser/extensions/pocket/bootstrap.js
+++ b/browser/extensions/pocket/bootstrap.js
@@ -103,18 +103,19 @@ PocketAboutPage.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
   getURIFlags: function(aURI) {
     return Ci.nsIAboutModule.ALLOW_SCRIPT |
            Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
            Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT |
            Ci.nsIAboutModule.MAKE_UNLINKABLE;
   },
 
-  newChannel: function(aURI) {
-    let channel = Services.io.newChannel(this.chromeURL, null, null);
+  newChannel: function(aURI, aLoadInfo) {
+    let channel = Services.io.newChannelFromURIWithLoadInfo(this.chromeURL,
+                                                            aLoadInfo);
     channel.originalURI = aURI;
     return channel;
   },
 
   createInstance: function(outer, iid) {
     if (outer != null) {
       throw Cr.NS_ERROR_NO_AGGREGATION;
     }
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -496,16 +496,18 @@
 @RESPATH@/components/nsPrompter.manifest
 @RESPATH@/components/nsPrompter.js
 #ifdef MOZ_SERVICES_HEALTHREPORT
 @RESPATH@/browser/components/SelfSupportService.manifest
 @RESPATH@/browser/components/SelfSupportService.js
 #endif
 @RESPATH@/components/SyncComponents.manifest
 @RESPATH@/components/Weave.js
+@RESPATH@/components/FxAccountsComponents.manifest
+@RESPATH@/components/FxAccountsPush.js
 @RESPATH@/components/CaptivePortalDetectComponents.manifest
 @RESPATH@/components/captivedetect.js
 @RESPATH@/components/servicesComponents.manifest
 @RESPATH@/components/cryptoComponents.manifest
 @RESPATH@/components/TelemetryStartup.js
 @RESPATH@/components/TelemetryStartup.manifest
 @RESPATH@/components/XULStore.js
 @RESPATH@/components/XULStore.manifest
--- a/build/autoconf/clang-plugin.m4
+++ b/build/autoconf/clang-plugin.m4
@@ -38,17 +38,17 @@ if test -n "$ENABLE_CLANG_PLUGIN"; then
         AC_MSG_ERROR([Cannot find an llvm-config binary for building a clang plugin])
     fi
     LLVM_CXXFLAGS=`$LLVMCONFIG --cxxflags`
     dnl The clang package we use on OSX is old, and its llvm-config doesn't
     dnl recognize --system-libs, so ask for that separately.  llvm-config's
     dnl failure here is benign, so we can ignore it if it happens.
     dnl Use tr instead of xargs in order to avoid problems with path separators on Windows.
     LLVM_LDFLAGS=`$LLVMCONFIG --system-libs | tr '\n' ' '`
-    LLVM_LDFLAGS="$LLVM_LDFLAGS `$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader option | tr '\n' ' '`"
+    LLVM_LDFLAGS="$LLVM_LDFLAGS `$LLVMCONFIG --ldflags --libs core mc analysis asmparser mcparser bitreader option profiledata | tr '\n' ' '`"
 
     if test "${HOST_OS_ARCH}" = "Darwin"; then
         CLANG_LDFLAGS="-lclangFrontend -lclangDriver -lclangSerialization"
         CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangParse -lclangSema -lclangAnalysis"
         CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangEdit -lclangAST -lclangLex"
         CLANG_LDFLAGS="$CLANG_LDFLAGS -lclangBasic -lclangASTMatchers"
     elif test "${HOST_OS_ARCH}" = "WINNT"; then
         CLANG_LDFLAGS="clangFrontend.lib clangDriver.lib clangSerialization.lib"
--- a/build/autoconf/subconfigure.m4
+++ b/build/autoconf/subconfigure.m4
@@ -4,17 +4,17 @@ dnl here, not the crazier environment th
 dnl Autoconf expects [] for quotes; give it to them
 changequote([, ])
 
 dnl AC_DEFUN is provided to use instead of define in autoconf. Provide it too.
 define([AC_DEFUN], [define($1, [$2])])
 
 dnl AC_ARG_ENABLE(FEATURE, HELP-STRING, IF-TRUE[, IF-FALSE])
 dnl We have to ignore the help string due to how help works in autoconf...
-AC_DEFUN([AC_ARG_ENABLE],
+AC_DEFUN([MOZ_AC_ARG_ENABLE],
 [#] Check whether --enable-[$1] or --disable-[$1] was given.
 [if test "[${enable_]patsubst([$1], -, _)+set}" = set; then
   enableval="[$enable_]patsubst([$1], -, _)"
   $3
 ifelse([$4], , , [else
   $4
 ])dnl
 fi
--- a/build/autoconf/toolchain.m4
+++ b/build/autoconf/toolchain.m4
@@ -220,16 +220,28 @@ if test "$GNU_CXX"; then
 
         if test "ac_cv_cxx0x_clang_workaround" = "no"; then
             AC_MSG_ERROR([Your toolchain does not support C++0x/C++11 mode properly. Please upgrade your toolchain])
         fi
     elif test "$ac_cv_cxx0x_headers_bug" = "yes"; then
         AC_MSG_ERROR([Your toolchain does not support C++0x/C++11 mode properly. Please upgrade your toolchain])
     fi
 
+    if test -n "$CLANG_CC"; then
+        dnl We'd normally just check for the version from CC_VERSION (fed
+        dnl from __clang_major__ and __clang_minor__), but the clang that
+        dnl comes with Xcode has a completely different version scheme
+        dnl despite exposing the version with the same defines.
+        dnl So instead of a version check, check for one of the C++11
+        dnl features that was added in clang 3.3.
+        AC_TRY_COMPILE([], [#if !__has_feature(cxx_inheriting_constructors)
+                            #error inheriting constructors are not supported
+                            #endif],,AC_MSG_ERROR([Only clang/llvm 3.3 or newer supported]))
+    fi
+
     AC_CACHE_CHECK([whether 64-bits std::atomic requires -latomic],
         ac_cv_needs_atomic,
         AC_TRY_LINK(
             [#include <cstdint>
              #include <atomic>],
             [ std::atomic<uint64_t> foo; foo = 1; ],
             ac_cv_needs_atomic=no,
             _SAVE_LIBS="$LIBS"
@@ -316,16 +328,22 @@ EOF
 
             if test "ac_cv_host_cxx0x_clang_workaround" = "no"; then
                 AC_MSG_ERROR([Your host toolchain does not support C++0x/C++11 mode properly. Please upgrade your toolchain])
             fi
             HOST_CXXFLAGS="$CXXFLAGS"
         elif test "$ac_cv_host_cxx0x_headers_bug" = "yes"; then
             AC_MSG_ERROR([Your host toolchain does not support C++0x/C++11 mode properly. Please upgrade your toolchain])
         fi
+        if test "$host_compiler" = CLANG; then
+            AC_TRY_COMPILE([], [#if !__has_feature(cxx_inheriting_constructors)
+                                #error inheriting constructors are not supported
+                                #endif],,AC_MSG_ERROR([Only clang/llvm 3.3 or newer supported]))
+        fi
+
         CXXFLAGS="$_SAVE_CXXFLAGS"
         CPPFLAGS="$_SAVE_CPPFLAGS"
         CXX="$_SAVE_CXX"
     fi
 elif test "$GNU_CXX"; then
     HOST_CXXFLAGS="$HOST_CXXFLAGS $_ADDED_CXXFLAGS"
 fi
 AC_LANG_C
--- a/build/build-clang/clang-static-analysis-win32.json
+++ b/build/build-clang/clang-static-analysis-win32.json
@@ -1,10 +1,10 @@
 {
-    "llvm_revision": "259916",
+    "llvm_revision": "262971",
     "stages": "3",
     "build_libcxx": false,
     "build_type": "Release",
     "assertions": false,
     "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
     "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
--- a/build/build-clang/clang-static-analysis-win64.json
+++ b/build/build-clang/clang-static-analysis-win64.json
@@ -1,10 +1,10 @@
 {
-    "llvm_revision": "259916",
+    "llvm_revision": "262971",
     "stages": "3",
     "build_libcxx": false,
     "build_type": "Release",
     "assertions": false,
     "llvm_repo": "https://llvm.org/svn/llvm-project/llvm/trunk",
     "clang_repo": "https://llvm.org/svn/llvm-project/cfe/trunk",
     "compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/trunk",
     "libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
--- a/build/clang-plugin/tests/Makefile.in
+++ b/build/clang-plugin/tests/Makefile.in
@@ -4,12 +4,15 @@
 
 # Build without any warning flags, and with clang verify flag for a
 # syntax-only build (no codegen), without a limit on the number of errors.
 OS_CFLAGS := $(filter-out -W%,$(OS_CFLAGS)) -fsyntax-only -Xclang -verify -ferror-limit=0 -std=c11
 OS_CXXFLAGS := $(filter-out -W%,$(OS_CXXFLAGS)) -fsyntax-only -Xclang -verify -ferror-limit=0
 
 include $(topsrcdir)/config/rules.mk
 
-export:: $(OBJS)
+target:: $(OBJS)
 
 # We don't actually build anything.
 .PHONY: $(OBJS)
+
+# Don't actually build a library, since we don't actually build objects.
+$(LIBRARY): EXPAND_LIBS_GEN=true
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -1,14 +1,17 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+# dummy library name to avoid skipping building the sources here.
+Library('clang-plugin-tests')
+
 SOURCES += [
     'TestBadImplicitConversionCtor.cpp',
     'TestCustomHeap.cpp',
     'TestExplicitOperatorBool.cpp',
     'TestGlobalClass.cpp',
     'TestHeapClass.cpp',
     'TestInheritTypeAnnotationsFromTemplateArgs.cpp',
     'TestMultipleAnnotations.cpp',
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -56,43 +56,79 @@ def check_build_environment(help, dist):
             '  *   To clean up the source tree:\n'
             '  *     1. cd %s\n'
             '  *     2. gmake distclean\n'
             '  ***'
             % ('\n  '.join(conflict_files), topsrcdir)
         )
 
 
+option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script')
+
 option(env='MOZ_CURRENT_PROJECT', nargs=1, help='Current build project')
 option(env='MOZCONFIG', nargs=1, help='Mozconfig location')
 
 # Read user mozconfig
 # ==============================================================
 # Note: the dependency on --help is only there to always read the mozconfig,
 # even when --help is passed. Without this dependency, the function wouldn't
 # be called when --help is passed, and the mozconfig wouldn't be read.
-@depends('MOZ_CURRENT_PROJECT', 'MOZCONFIG', check_build_environment, '--help')
+@depends('MOZ_CURRENT_PROJECT', 'MOZCONFIG', 'OLD_CONFIGURE',
+         check_build_environment, '--help')
 @advanced
-def mozconfig(current_project, mozconfig,  build_env, help):
+def mozconfig(current_project, mozconfig, old_configure, build_env, help):
     from mozbuild.mozconfig import MozconfigLoader
 
+    if not old_configure:
+        error('The OLD_CONFIGURE environment variable must be set')
+
     # Don't read the mozconfig for the js configure (yay backwards
     # compatibility)
-    if build_env['TOPOBJDIR'].endswith('/js/src'):
+    # While the long term goal is that js and top-level use the same configure
+    # and the same overall setup, including the possibility to use mozconfigs,
+    # figuring out what we want to do wrt mozconfig vs. command line and
+    # environment variable is not a clear-cut case, and it's more important to
+    # fix the immediate problem mozconfig causes to js developers by
+    # "temporarily" returning to the previous behavior of not loading the
+    # mozconfig for the js configure.
+    # Separately to the immediate problem for js developers, there is also the
+    # need to not load a mozconfig when running js configure as a subconfigure.
+    # Unfortunately, there is no direct way to tell whether the running
+    # configure is the js configure. The indirect way is to look at the
+    # OLD_CONFIGURE path, which points to js/src/old-configure.
+    # I expect we'll have figured things out for mozconfigs well before
+    # old-configure dies.
+    if os.path.dirname(os.path.abspath(old_configure[0])).endswith('/js/src'):
         return {'path': None}
 
     loader = MozconfigLoader(build_env['TOPSRCDIR'])
     current_project = current_project[0] if current_project else None
     mozconfig = mozconfig[0] if mozconfig else None
     mozconfig = loader.find_mozconfig(env={'MOZCONFIG': mozconfig})
     mozconfig = loader.read_mozconfig(mozconfig, moz_build_app=current_project)
 
     return mozconfig
 
 
+# Hacks related to old-configure
+# ==============================
+
+@depends('--help')
+def old_configure_assignments(help):
+    return []
+
+@template
+def add_old_configure_assignment(var, value):
+    @depends(old_configure_assignments)
+    @advanced
+    def add_assignment(assignments):
+        from mozbuild.shellutil import quote
+        assignments.append('%s=%s' % (var, quote(value)))
+
+
 option(env='PYTHON', nargs=1, help='Python interpreter')
 
 # Setup python virtualenv
 # ==============================================================
 @depends('PYTHON', check_build_environment, mozconfig)
 @advanced
 def virtualenv_python(env_python, build_env, mozconfig):
     import os
@@ -156,16 +192,17 @@ def virtualenv_python(env_python, build_
         sys.exit(subprocess.call([python] + sys.argv))
 
     # We are now in the virtualenv
     import distutils.sysconfig
     if not distutils.sysconfig.get_python_lib():
         error('Could not determine python site packages directory')
 
     set_config('PYTHON', python)
+    add_old_configure_assignment('PYTHON', python)
     return python
 
 
 # Inject mozconfig options
 # ==============================================================
 @template
 @advanced
 def command_line_helper():
@@ -225,27 +262,31 @@ option('--with-external-source-dir', env
          check_build_environment, '--help')
 def include_project_configure(project, external_source_dir, build_env, help):
     if not project:
         error('--enable-project is required.')
 
     base_dir = build_env['TOPSRCDIR']
     if external_source_dir:
         set_config('EXTERNAL_SOURCE_DIR', external_source_dir[0])
+        add_old_configure_assignment('EXTERNAL_SOURCE_DIR',
+                                     external_source_dir[0])
         base_dir = os.path.join(base_dir, external_source_dir[0])
 
     path = os.path.join(base_dir, project[0], 'moz.configure')
     if not os.path.exists(path):
         error('Cannot find project %s' % project[0])
     return path
 
 @depends(include_project_configure, check_build_environment, '--help')
 def build_project(include_project_configure, build_env, help):
-    return os.path.dirname(os.path.relpath(include_project_configure,
-                                           build_env['TOPSRCDIR']))
+    ret = os.path.dirname(os.path.relpath(include_project_configure,
+                                          build_env['TOPSRCDIR']))
+    add_old_configure_assignment('MOZ_BUILD_APP', ret)
+    return ret
 
 
 # This is temporary until js/src/configure and configure are merged.
 @depends(build_project)
 def extra_old_configure_args(build_project):
     if build_project != 'js':
         return []
     return False
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -52,37 +52,30 @@ def autoconf(mozconfig, autoconf):
 
     if not autoconf:
         error('Could not find autoconf 2.13')
 
     set_config('AUTOCONF', autoconf)
     return autoconf
 
 
-option(env='OLD_CONFIGURE', nargs=1, help='Path to the old configure script')
-
 @depends('OLD_CONFIGURE', mozconfig, autoconf, check_build_environment, shell,
-         virtualenv_python, compile_environment, build_project,
-         extra_old_configure_args, '--with-external-source-dir')
+         extra_old_configure_args, old_configure_assignments)
 @advanced
 def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
-                      python, compile_env, build_project,
-                      extra_old_configure_args, external_source_dir):
+                      extra_old_configure_args, old_configure_assignments):
     import glob
     import itertools
     import subprocess
     import sys
     # Import getmtime without overwriting the sandbox os.path.
     from os.path import getmtime
 
     from mozbuild.shellutil import quote
 
-    if not old_configure:
-        error('The OLD_CONFIGURE environment variable must be set')
-
     # os.path.abspath in the sandbox will ensure forward slashes on Windows,
     # which is actually necessary because this path actually ends up literally
     # as $0, and backslashes there breaks autoconf's detection of the source
     # directory.
     old_configure = os.path.abspath(old_configure[0])
 
     refresh = True
     if os.path.exists(old_configure):
@@ -120,22 +113,18 @@ def prepare_configure(old_configure, moz
             for key, value in mozconfig['vars']['added'].items():
                 print("%s=%s" % (key, quote(value)), file=out)
             for key, (old, value) in mozconfig['vars']['modified'].items():
                 print("%s=%s" % (key, quote(value)), file=out)
             for t in ('env', 'vars'):
                 for key in mozconfig[t]['removed'].keys():
                     print("unset %s" % key, file=out)
 
-        print('PYTHON=%s' % quote(python), file=out)
-        if compile_env:
-            print('COMPILE_ENVIRONMENT=1', file=out)
-        print('MOZ_BUILD_APP=%s' % build_project, file=out)
-        if external_source_dir:
-            print(external_source_dir.format('EXTERNAL_SOURCE_DIR'), file=out)
+        for assignment in old_configure_assignments:
+            print(assignment, file=out)
 
     if extra_old_configure_args:
         cmd += extra_old_configure_args
 
     return cmd
 
 
 @template
@@ -178,17 +167,16 @@ def old_configure_options(*options):
     '--enable-debug-symbols',
     '--enable-default-toolkit',
     '--enable-directshow',
     '--enable-dmd',
     '--enable-dtrace',
     '--enable-dump-painting',
     '--enable-elf-hack',
     '--enable-eme',
-    '--enable-export-js',
     '--enable-extensions',
     '--enable-faststripe',
     '--enable-feeds',
     '--enable-ffmpeg',
     '--enable-fmp4',
     '--enable-gamepad',
     '--enable-gc-trace',
     '--enable-gconf',
@@ -242,17 +230,16 @@ def old_configure_options(*options):
     '--enable-readline',
     '--enable-reflow-perf',
     '--enable-release',
     '--enable-replace-malloc',
     '--enable-require-all-d3dc-versions',
     '--enable-rust',
     '--enable-safe-browsing',
     '--enable-sandbox',
-    '--enable-shared-js',
     '--enable-signmar',
     '--enable-simulator',
     '--enable-skia',
     '--enable-skia-gpu',
     '--enable-small-chunk-size',
     '--enable-startup-notification',
     '--enable-startupcache',
     '--enable-stdcxx-compat',
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -71,8 +71,32 @@ del _defines
 
 @template
 def unique_list(l):
     result = []
     for i in l:
         if l not in result:
             result.append(i)
     return result
+
+
+# Denotes a deprecated option. Combines option() and @depends:
+# @deprecated_option('--option')
+# def option(value):
+#     ...
+# @deprecated_option() takes the same arguments as option(), except `help`.
+# The function may handle the option like a typical @depends function would,
+# but it is recommended it emits a deprecation error message suggesting an
+# alternative option to use if there is one.
+@template
+def deprecated_option(*args, **kwargs):
+    assert 'help' not in kwargs
+    kwargs['help'] = 'Deprecated'
+    opt = option(*args, **kwargs)
+
+    def decorator(func):
+        @depends(opt.option)
+        def deprecated(value):
+            if value.origin != 'default':
+                return func(value)
+        return deprecated
+
+    return decorator
--- a/caps/nsJSPrincipals.cpp
+++ b/caps/nsJSPrincipals.cpp
@@ -78,17 +78,17 @@ nsJSPrincipals::Destroy(JSPrincipals *js
     nsjsprin->refcount++;
 #endif
     nsjsprin->Release();
 }
 
 #ifdef DEBUG
 
 // Defined here so one can do principals->dump() in the debugger
-JS_EXPORT_API(void)
+JS_PUBLIC_API(void)
 JSPrincipals::dump()
 {
     if (debugToken == nsJSPrincipals::DEBUG_TOKEN) {
       nsAutoCString str;
       static_cast<nsJSPrincipals *>(this)->GetScriptLocation(str);
       fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this), str.get());
     } else if (debugToken == dom::workers::kJSPrincipalsDebugToken) {
         fprintf(stderr, "Web Worker principal singleton (%p)\n", this);
--- a/config/gcc-stl-wrapper.template.h
+++ b/config/gcc-stl-wrapper.template.h
@@ -12,33 +12,40 @@
 // compiling ObjC.
 #if defined(__EXCEPTIONS) && __EXCEPTIONS && !(__OBJC__ && __GNUC__ && XP_IOS)
 #  error "STL code can only be used with -fno-exceptions"
 #endif
 
 // Silence "warning: #include_next is a GCC extension"
 #pragma GCC system_header
 
+// Don't include mozalloc for cstdlib. See bug 1245076.
+#ifndef moz_dont_include_mozalloc_for_cstdlib
+#  define moz_dont_include_mozalloc_for_cstdlib
+#endif
+#ifndef moz_dont_include_mozalloc_for_${HEADER}
 // mozalloc.h wants <new>; break the cycle by always explicitly
 // including <new> here.  NB: this is a tad sneaky.  Sez the gcc docs:
 //
 //    `#include_next' does not distinguish between <file> and "file"
 //    inclusion, nor does it check that the file you specify has the
 //    same name as the current file. It simply looks for the file
 //    named, starting with the directory in the search path after the
 //    one where the current file was found.
-#include_next <new>
+#  include_next <new>
 
 // See if we're in code that can use mozalloc.  NB: this duplicates
 // code in nscore.h because nscore.h pulls in prtypes.h, and chromium
 // can't build with that being included before base/basictypes.h.
-#if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
-#  include "mozilla/mozalloc.h"
-#else
-#  error "STL code can only be used with infallible ::operator new()"
+#  if !defined(XPCOM_GLUE) && !defined(NS_NO_XPCOM) && !defined(MOZ_NO_MOZALLOC)
+#    include "mozilla/mozalloc.h"
+#  else
+#    error "STL code can only be used with infallible ::operator new()"
+#  endif
+
 #endif
 
 #if defined(DEBUG) && !defined(_GLIBCXX_DEBUG)
 // Enable checked iterators and other goodies
 //
 // FIXME/bug 551254: gcc's debug STL implementation requires -frtti.
 // Figure out how to resolve this with -fno-rtti.  Maybe build with
 // -frtti in DEBUG builds?
--- a/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js
+++ b/devtools/client/animationinspector/test/browser_animation_animated_properties_displayed.js
@@ -17,17 +17,17 @@ const EXPECTED_PROPERTIES = [
   "border-top-right-radius",
   "filter",
   "height",
   "transform",
   "width"
 ].sort();
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_keyframes.html");
+  yield addTab(URL_ROOT + "doc_keyframes.html");
   let {panel} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
   let propertiesList = timeline.rootWrapperEl
                                .querySelector(".animated-properties");
 
   ok(!isNodeVisible(propertiesList),
      "The list of properties panel is hidden by default");
 
--- a/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js
+++ b/devtools/client/animationinspector/test/browser_animation_click_selects_animation.js
@@ -3,17 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Check that animations displayed in the timeline can be selected by clicking
 // them, and that this emits the right events and adds the right classes.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
 
   let selected = timeline.rootWrapperEl.querySelectorAll(".animation.selected");
   ok(!selected.length, "There are no animations selected by default");
 
   info("Click on the first animation, expect the right event and right class");
   let animation0 = yield clickOnAnimation(panel, 0);
--- a/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js
+++ b/devtools/client/animationinspector/test/browser_animation_controller_exposes_document_currentTime.js
@@ -3,17 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that the controller provides the document.timeline currentTime (at least
 // the last known version since new animations were added).
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel, controller} = yield openAnimationInspector();
 
   ok(controller.documentCurrentTime, "The documentCurrentTime getter exists");
   checkDocumentTimeIsCorrect(controller);
   let time1 = controller.documentCurrentTime;
 
   yield startNewAnimation(controller, panel);
   checkDocumentTimeIsCorrect(controller);
--- a/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js
+++ b/devtools/client/animationinspector/test/browser_animation_empty_on_invalid_nodes.js
@@ -6,38 +6,38 @@
 requestLongerTimeout(2);
 
 // Test that the panel shows no animation data for invalid or not animated nodes
 
 const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
 const L10N = new ViewHelpers.L10N(STRINGS_URI);
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel, window} = yield openAnimationInspector();
   let {document} = window;
 
   info("Select node .still and check that the panel is empty");
   let stillNode = yield getNodeFront(".still", inspector);
   let onUpdated = panel.once(panel.UI_UPDATED_EVENT);
-  yield selectNode(stillNode, inspector);
+  yield selectNodeAndWaitForAnimations(stillNode, inspector);
   yield onUpdated;
 
   is(panel.animationsTimelineComponent.animations.length, 0,
      "No animation players stored in the timeline component for a still node");
   is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
      "No animation displayed in the timeline component for a still node");
   is(document.querySelector("#error-type").textContent,
      L10N.getStr("panel.invalidElementSelected"),
      "The correct error message is displayed");
 
   info("Select the comment text node and check that the panel is empty");
   let commentNode = yield inspector.walker.previousSibling(stillNode);
   onUpdated = panel.once(panel.UI_UPDATED_EVENT);
-  yield selectNode(commentNode, inspector);
+  yield selectNodeAndWaitForAnimations(commentNode, inspector);
   yield onUpdated;
 
   is(panel.animationsTimelineComponent.animations.length, 0,
      "No animation players stored in the timeline component for a text node");
   is(panel.animationsTimelineComponent.animationsEl.childNodes.length, 0,
      "No animation displayed in the timeline component for a text node");
   is(document.querySelector("#error-type").textContent,
      L10N.getStr("panel.invalidElementSelected"),
--- a/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js
+++ b/devtools/client/animationinspector/test/browser_animation_keyframe_click_to_set_time.js
@@ -3,17 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Test that animated properties' keyframes can be clicked, and that doing so
 // sets the current time in the timeline.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_keyframes.html");
+  yield addTab(URL_ROOT + "doc_keyframes.html");
   let {panel} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
   let {scrubberEl} = timeline;
 
   // XXX: The scrollbar is placed in the timeline in such a way that it causes
   // the animations to be slightly offset with the header when it appears.
   // So for now, let's hide the scrollbar. Bug 1229340 should fix this.
   timeline.animationsEl.style.overflow = "hidden";
--- a/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js
+++ b/devtools/client/animationinspector/test/browser_animation_keyframe_markers.js
@@ -17,17 +17,17 @@ const EXPECTED_PROPERTIES = [
   "borderTopRightRadius",
   "filter",
   "height",
   "transform",
   "width"
 ];
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_keyframes.html");
+  yield addTab(URL_ROOT + "doc_keyframes.html");
   let {panel} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
 
   info("Expand the animation");
   yield clickOnAnimation(panel, 0);
 
   ok(timeline.rootWrapperEl.querySelectorAll(".frames .keyframes").length,
      "There are container elements for displaying keyframes");
--- a/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js
+++ b/devtools/client/animationinspector/test/browser_animation_mutations_with_same_names.js
@@ -5,17 +5,17 @@
 "use strict";
 
 // Check that when animations are added later (through animation mutations) and
 // if these animations have the same names, then all of them are still being
 // displayed (which should be true as long as these animations apply to
 // different nodes).
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_negative_animation.html");
+  yield addTab(URL_ROOT + "doc_negative_animation.html");
   let {controller, panel} = yield openAnimationInspector();
 
   info("Wait until all animations have been added " +
        "(they're added with setTimeout)");
   while (controller.animationPlayers.length < 3) {
     yield controller.once(controller.PLAYERS_UPDATED_EVENT);
   }
   yield waitForAllAnimationTargets(panel);
--- a/devtools/client/animationinspector/test/browser_animation_participate_in_inspector_update.js
+++ b/devtools/client/animationinspector/test/browser_animation_participate_in_inspector_update.js
@@ -6,17 +6,17 @@
 
 requestLongerTimeout(2);
 
 // Test that the update of the animation panel participate in the
 // inspector-updated event. This means that the test verifies that the
 // inspector-updated event is emitted *after* the animation panel is ready.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel, controller} = yield openAnimationInspector();
 
   info("Listen for the players-updated, ui-updated and " +
        "inspector-updated events");
   let receivedEvents = [];
   controller.once(controller.PLAYERS_UPDATED_EVENT, () => {
     receivedEvents.push(controller.PLAYERS_UPDATED_EVENT);
   });
@@ -24,17 +24,17 @@ add_task(function*() {
     receivedEvents.push(panel.UI_UPDATED_EVENT);
   });
   inspector.once("inspector-updated", () => {
     receivedEvents.push("inspector-updated");
   });
 
   info("Selecting an animated node");
   let node = yield getNodeFront(".animated", inspector);
-  yield selectNode(node, inspector);
+  yield selectNodeAndWaitForAnimations(node, inspector);
 
   info("Check that all events were received");
   // Only assert that the inspector-updated event is last, the order of the
   // first 2 events is irrelevant.
 
   is(receivedEvents.length, 3, "3 events were received");
   is(receivedEvents[2], "inspector-updated",
      "The third event received was the inspector-updated event");
--- a/devtools/client/animationinspector/test/browser_animation_playerFronts_are_refreshed.js
+++ b/devtools/client/animationinspector/test/browser_animation_playerFronts_are_refreshed.js
@@ -5,32 +5,32 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Check that the AnimationPlayerFront objects lifecycle is managed by the
 // AnimationController.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {controller, inspector} = yield openAnimationInspector();
 
   info("Selecting an animated node");
   // selectNode waits for the inspector-updated event before resolving, which
   // means the controller.PLAYERS_UPDATED_EVENT event has been emitted before
   // and players are ready.
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   is(controller.animationPlayers.length, 1,
     "One AnimationPlayerFront has been created");
 
   info("Selecting a node with mutliple animations");
-  yield selectNode(".multi", inspector);
+  yield selectNodeAndWaitForAnimations(".multi", inspector);
 
   is(controller.animationPlayers.length, 2,
     "2 AnimationPlayerFronts have been created");
 
   info("Selecting a node with no animations");
-  yield selectNode(".still", inspector);
+  yield selectNodeAndWaitForAnimations(".still", inspector);
 
   is(controller.animationPlayers.length, 0,
     "There are no more AnimationPlayerFront objects");
 });
--- a/devtools/client/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js
+++ b/devtools/client/animationinspector/test/browser_animation_playerWidgets_appear_on_panel_init.js
@@ -11,17 +11,17 @@ const { ANIMATION_TYPES } = require("dev
 
 add_task(function*() {
   yield new Promise(resolve => {
     SpecialPowers.pushPrefEnv({"set": [
       ["dom.animations-api.core.enabled", true]
     ]}, resolve);
   });
 
-  yield addTab(TEST_URL_ROOT + "doc_multiple_animation_types.html");
+  yield addTab(URL_ROOT + "doc_multiple_animation_types.html");
 
   let {panel} = yield openAnimationInspector();
   is(panel.animationsTimelineComponent.animations.length, 3,
     "Three animations are handled by the timeline after init");
   assertAnimationsDisplayed(panel, 3,
     "Three animations are displayed after init");
   is(
     panel.animationsTimelineComponent
--- a/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js
+++ b/devtools/client/animationinspector/test/browser_animation_playerWidgets_target_nodes.js
@@ -4,21 +4,21 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that player widgets display information about target nodes
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Select the simple animated node");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   let targetNodeComponent = panel.animationsTimelineComponent.targetNodes[0];
   let {previewer} = targetNodeComponent;
 
   // Make sure to wait for the target-retrieved event if the nodeFront hasn't
   // yet been retrieved by the TargetNodeComponent.
   if (!previewer.nodeFront) {
     yield targetNodeComponent.once("target-retrieved");
--- a/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js
+++ b/devtools/client/animationinspector/test/browser_animation_refresh_on_added_animation.js
@@ -4,21 +4,21 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that the panel content refreshes when new animations are added.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Select a non animated node");
-  yield selectNode(".still", inspector);
+  yield selectNodeAndWaitForAnimations(".still", inspector);
 
   assertAnimationsDisplayed(panel, 0);
 
   info("Start an animation on the node");
   yield changeElementAndWait({
     selector: ".still",
     attributeName: "class",
     attributeValue: "ball animated"
--- a/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js
+++ b/devtools/client/animationinspector/test/browser_animation_refresh_on_removed_animation.js
@@ -4,25 +4,25 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that the panel content refreshes when animations are removed.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {inspector, panel} = yield openAnimationInspector();
   yield testRefreshOnRemove(inspector, panel);
 });
 
 function* testRefreshOnRemove(inspector, panel) {
   info("Select a animated node");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   assertAnimationsDisplayed(panel, 1);
 
   info("Listen to the next UI update event");
   let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
 
   info("Remove the animation on the node by removing the class");
   yield executeInContent("devtools:test:setAttribute", {
--- a/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js
+++ b/devtools/client/animationinspector/test/browser_animation_refresh_when_active.js
@@ -4,47 +4,47 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that the panel only refreshes when it is visible in the sidebar.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {inspector, panel} = yield openAnimationInspector();
   yield testRefresh(inspector, panel);
 });
 
 function* testRefresh(inspector, panel) {
   info("Select a non animated node");
-  yield selectNode(".still", inspector);
+  yield selectNodeAndWaitForAnimations(".still", inspector);
 
   info("Switch to the rule-view panel");
   inspector.sidebar.select("ruleview");
 
   info("Select the animated node now");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   assertAnimationsDisplayed(panel, 0,
     "The panel doesn't show the animation data while inactive");
 
   info("Switch to the animation panel");
   inspector.sidebar.select("animationinspector");
   yield panel.once(panel.UI_UPDATED_EVENT);
 
   assertAnimationsDisplayed(panel, 1,
     "The panel shows the animation data after selecting it");
 
   info("Switch again to the rule-view");
   inspector.sidebar.select("ruleview");
 
   info("Select the non animated node again");
-  yield selectNode(".still", inspector);
+  yield selectNodeAndWaitForAnimations(".still", inspector);
 
   assertAnimationsDisplayed(panel, 1,
     "The panel still shows the previous animation data since it is inactive");
 
   info("Switch to the animation panel again");
   inspector.sidebar.select("animationinspector");
   yield panel.once(panel.UI_UPDATED_EVENT);
 
--- a/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js
+++ b/devtools/client/animationinspector/test/browser_animation_running_on_compositor.js
@@ -8,31 +8,31 @@ requestLongerTimeout(2);
 
 // Test that when animations displayed in the timeline are running on the
 // compositor, they get a special icon and information in the tooltip.
 
 const STRINGS_URI = "chrome://devtools/locale/animationinspector.properties";
 const L10N = new ViewHelpers.L10N(STRINGS_URI);
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
 
   info("Select a test node we know has an animation running on the compositor");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   let animationEl = timeline.animationsEl.querySelector(".animation");
   ok(animationEl.classList.contains("fast-track"),
      "The animation element has the fast-track css class");
   ok(hasTooltip(animationEl),
      "The animation element has the right tooltip content");
 
   info("Select a node we know doesn't have an animation on the compositor");
-  yield selectNode(".no-compositor", inspector);
+  yield selectNodeAndWaitForAnimations(".no-compositor", inspector);
 
   animationEl = timeline.animationsEl.querySelector(".animation");
   ok(!animationEl.classList.contains("fast-track"),
      "The animation element does not have the fast-track css class");
   ok(!hasTooltip(animationEl),
      "The animation element has the right tooltip content");
 });
 
--- a/devtools/client/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js
+++ b/devtools/client/animationinspector/test/browser_animation_same_nb_of_playerWidgets_and_playerFronts.js
@@ -5,19 +5,19 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Check that when playerFronts are updated, the same number of playerWidgets
 // are created in the panel.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel, controller} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
 
   info("Selecting the test animated node again");
-  yield selectNode(".multi", inspector);
+  yield selectNodeAndWaitForAnimations(".multi", inspector);
 
   is(controller.animationPlayers.length,
     timeline.animationsEl.querySelectorAll(".animation").length,
     "As many timeline elements were created as there are playerFronts");
 });
--- a/devtools/client/animationinspector/test/browser_animation_shows_player_on_valid_node.js
+++ b/devtools/client/animationinspector/test/browser_animation_shows_player_on_valid_node.js
@@ -5,17 +5,17 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that the panel shows an animation player when an animated node is
 // selected.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Select node .animated and check that the panel is not empty");
   let node = yield getNodeFront(".animated", inspector);
-  yield selectNode(node, inspector);
+  yield selectNodeAndWaitForAnimations(node, inspector);
 
   assertAnimationsDisplayed(panel, 1);
 });
--- a/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_animations.js
+++ b/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_animations.js
@@ -6,22 +6,22 @@
 
 // Test that the spacebar key press toggles the toggleAll button state
 // when a node with no animation is selected.
 // This test doesn't need to test if animations actually pause/resume
 // because there's an other test that does this :
 // browser_animation_toggle_button_toggles_animation.js
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel, inspector, window, controller} = yield openAnimationInspector();
   let {toggleAllButtonEl} = panel;
 
   // select a node without animations
-  yield selectNode(".still", inspector);
+  yield selectNodeAndWaitForAnimations(".still", inspector);
 
   // ensure the focus is on the animation panel
   window.focus();
 
   info("Simulate spacebar stroke and check toggleAll button" +
        " is in paused state");
 
   // sending the key will lead to a ALL_ANIMATIONS_TOGGLED_EVENT
--- a/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js
+++ b/devtools/client/animationinspector/test/browser_animation_spacebar_toggles_node_animations.js
@@ -6,17 +6,17 @@
 
 // Test that the spacebar key press toggles the play/resume button state.
 // This test doesn't need to test if animations actually pause/resume
 // because there's an other test that does this.
 // There are animations in the test page and since, by default, the <body> node
 // is selected, animations will be displayed in the timeline, so the timeline
 // play/resume button will be displayed
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel, window} = yield openAnimationInspector();
   let {playTimelineButtonEl} = panel;
 
   // ensure the focus is on the animation panel
   window.focus();
 
   info("Simulate spacebar stroke and check playResume button" +
        " is in paused state");
--- a/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js
+++ b/devtools/client/animationinspector/test/browser_animation_target_highlight_select.js
@@ -5,23 +5,23 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that the DOM element targets displayed in animation player widgets can
 // be used to highlight elements in the DOM and select them in the inspector.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {toolbox, inspector, panel} = yield openAnimationInspector();
 
   info("Select the simple animated node");
   let onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
   yield onPanelUpdated;
 
   let targets = yield waitForAllAnimationTargets(panel);
   // Arbitrary select the first one
   let targetNodeComponent = targets[0];
 
   info("Retrieve the part of the widget that highlights the node on hover");
   let highlightingEl = targetNodeComponent.previewer.previewEl;
@@ -45,17 +45,17 @@ add_task(function*() {
     "The highlighted node has the correct tagName");
   is(nodeFront.attributes[0].name, "class",
     "The highlighted node has the correct attributes");
   is(nodeFront.attributes[0].value, "ball animated",
     "The highlighted node has the correct class");
 
   info("Select the body node in order to have the list of all animations");
   onPanelUpdated = panel.once(panel.UI_UPDATED_EVENT);
-  yield selectNode("body", inspector);
+  yield selectNodeAndWaitForAnimations("body", inspector);
   yield onPanelUpdated;
 
   targets = yield waitForAllAnimationTargets(panel);
   targetNodeComponent = targets[0];
 
   info("Click on the first animated node component and wait for the " +
        "selection to change");
   let onSelection = inspector.selection.once("new-node-front");
--- a/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js
+++ b/devtools/client/animationinspector/test/browser_animation_target_highlighter_lock.js
@@ -5,17 +5,17 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that the DOM element targets displayed in animation player widgets can
 // be used to highlight elements in the DOM and select them in the inspector.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
 
   let targets = panel.animationsTimelineComponent.targetNodes;
 
   info("Click on the highlighter icon for the first animated node");
   let domNodePreview1 = targets[0].previewer;
   yield lockHighlighterOn(domNodePreview1);
   ok(domNodePreview1.highlightNodeEl.classList.contains("selected"),
--- a/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_currentTime.js
@@ -6,17 +6,17 @@
 
 requestLongerTimeout(2);
 
 // Check that the timeline toolbar displays the current time, and that it
 // changes when animations are playing, gets back to 0 when animations are
 // rewound, and stops when animations are paused.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {panel} = yield openAnimationInspector();
   let label = panel.timelineCurrentTimeEl;
   ok(label, "The current time label exists");
 
   // On page load animations are playing so the time shoud change, although we
   // don't want to test the exact value of the time displayed, just that it
   // actually changes.
--- a/devtools/client/animationinspector/test/browser_animation_timeline_header.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_header.js
@@ -10,17 +10,17 @@ requestLongerTimeout(2);
 
 const {findOptimalTimeInterval, TimeScale} = require("devtools/client/animationinspector/utils");
 
 // Should be kept in sync with TIME_GRADUATION_MIN_SPACING in
 // animation-timeline.js
 const TIME_GRADUATION_MIN_SPACING = 40;
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
 
   let timeline = panel.animationsTimelineComponent;
   let headerEl = timeline.timeHeaderEl;
 
   info("Find out how many time graduations should there be");
   let width = headerEl.offsetWidth;
 
--- a/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_pause_button.js
@@ -12,17 +12,17 @@ requestLongerTimeout(2);
 // that the scrubber resumes/stops moving.
 // Also checks that the button goes to the right state when the scrubber has
 // reached the end of the timeline: continues to be in playing mode for infinite
 // animations, goes to paused mode otherwise.
 // And test that clicking the button once the scrubber has reached the end of
 // the timeline does the right thing.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {panel, inspector} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
   let btn = panel.playTimelineButtonEl;
 
   ok(btn, "The play/pause button exists");
   ok(!btn.classList.contains("paused"),
      "The play/pause button is in its playing state");
@@ -40,17 +40,17 @@ add_task(function*() {
   ok(!btn.classList.contains("paused"),
      "The play/pause button is in its playing state again");
   yield assertScrubberMoving(panel, true);
 
   // Some animations on the test page are infinite, so the scrubber won't stop
   // at the end of the timeline, and the button should remain in play mode.
   info("Select an infinite animation, reload the page and wait for the " +
        "animation to complete");
-  yield selectNode(".multi", inspector);
+  yield selectNodeAndWaitForAnimations(".multi", inspector);
   yield reloadTab(inspector);
   yield waitForOutOfBoundScrubber(timeline);
 
   ok(!btn.classList.contains("paused"),
      "The button is in its playing state still, animations are infinite.");
   yield assertScrubberMoving(panel, true);
 
   info("Click on the button after the scrubber has moved out of bounds");
@@ -59,17 +59,17 @@ add_task(function*() {
   ok(btn.classList.contains("paused"),
      "The button can be paused after the scrubber has moved out of bounds");
   yield assertScrubberMoving(panel, false);
 
   // For a finite animation though, once the scrubber reaches the end of the
   // timeline, it should go back to paused mode.
   info("Select a finite animation, reload the page and wait for the " +
        "animation to complete");
-  yield selectNode(".negative-delay", inspector);
+  yield selectNodeAndWaitForAnimations(".negative-delay", inspector);
 
   let onScrubberStopped = waitForScrubberStopped(timeline);
   yield reloadTab(inspector);
   yield onScrubberStopped;
 
   ok(btn.classList.contains("paused"),
      "The button is in paused state once finite animations are done");
   yield assertScrubberMoving(panel, false);
--- a/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_rate_selector.js
@@ -8,17 +8,17 @@ requestLongerTimeout(2);
 
 // Check that the timeline toolbar contains a playback rate selector UI and that
 // it can be used to change the playback rate of animations in the timeline.
 // Also check that it displays the rate of the current animations in case they
 // all have the same rate, or that it displays the empty value in case they
 // have mixed rates.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {panel, controller, inspector, toolbox} = yield openAnimationInspector();
 
   // In this test, we disable the highlighter on purpose because of the way
   // events are simulated to select an option in the playbackRate <select>.
   // Indeed, this may cause mousemove events to be triggered on the nodes that
   // are underneath the <select>, and these are AnimationTargetNode instances.
   // Simulating mouse events on them will cause the highlighter to emit requests
@@ -29,23 +29,23 @@ add_task(function*() {
 
   ok(select, "The rate selector exists");
 
   info("Change all of the current animations' rates to 0.5");
   yield changeTimelinePlaybackRate(panel, .5);
   checkAllAnimationsRatesChanged(controller, select, .5);
 
   info("Select just one animated node and change its rate only");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   yield changeTimelinePlaybackRate(panel, 2);
   checkAllAnimationsRatesChanged(controller, select, 2);
 
   info("Select the <body> again, it should now have mixed-rates animations");
-  yield selectNode("body", inspector);
+  yield selectNodeAndWaitForAnimations("body", inspector);
 
   is(select.value, "", "The selected rate is empty");
 
   info("Change the rate for these mixed-rate animations");
   yield changeTimelinePlaybackRate(panel, 1);
   checkAllAnimationsRatesChanged(controller, select, 1);
 });
 
--- a/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_rewind_button.js
@@ -8,17 +8,17 @@ requestLongerTimeout(2);
 
 // Check that the timeline toolbar contains a rewind button and that it can be
 // clicked. Check that when it is, the current animations displayed in the
 // timeline get their playstates changed to paused, and their currentTimes
 // reset to 0, and that the scrubber stops moving and is positioned to the
 // start.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {panel, controller} = yield openAnimationInspector();
   let players = controller.animationPlayers;
   let btn = panel.rewindTimelineButtonEl;
 
   ok(btn, "The rewind button exists");
 
   info("Click on the button to rewind all timeline animations");
--- a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_exists.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_exists.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Check that the timeline does have a scrubber element.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
 
   let timeline = panel.animationsTimelineComponent;
   let scrubberEl = timeline.scrubberEl;
 
   ok(scrubberEl, "The scrubber element exists");
   ok(scrubberEl.classList.contains("scrubber"), "It has the right classname");
 });
--- a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_movable.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_movable.js
@@ -8,17 +8,17 @@ requestLongerTimeout(2);
 
 // Check that the scrubber in the timeline can be moved by clicking & dragging
 // in the header area.
 // Also check that doing so changes the timeline's play/pause button to paused
 // state.
 // Finally, also check that the scrubber can be moved using the scrubber handle.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
 
   let {panel} = yield openAnimationInspector();
   let timeline = panel.animationsTimelineComponent;
   let {win, timeHeaderEl, scrubberEl, scrubberHandleEl} = timeline;
   let playTimelineButtonEl = panel.playTimelineButtonEl;
 
   ok(!playTimelineButtonEl.classList.contains("paused"),
      "The timeline play button is in its playing state by default");
--- a/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_scrubber_moves.js
@@ -7,17 +7,17 @@
 requestLongerTimeout(2);
 
 // Check that the scrubber in the timeline moves when animations are playing.
 // The animations in the test page last for a very long time, so the test just
 // measures the position of the scrubber once, then waits for some time to pass
 // and measures its position again.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
 
   let timeline = panel.animationsTimelineComponent;
   let scrubberEl = timeline.scrubberEl;
   let startPos = scrubberEl.getBoundingClientRect().left;
 
   info("Wait for some time to check that the scrubber moves");
   yield new Promise(r => setTimeout(r, 2000));
--- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_delay.js
@@ -7,30 +7,30 @@
 requestLongerTimeout(2);
 
 // Check that animation delay is visualized in the timeline when the animation
 // is delayed.
 // Also check that negative delays do not overflow the UI, and are shown like
 // positive delays.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Selecting a delayed animated node");
-  yield selectNode(".delayed", inspector);
+  yield selectNodeAndWaitForAnimations(".delayed", inspector);
   let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
   checkDelayAndName(timelineEl, true);
 
   info("Selecting a no-delay animated node");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
   checkDelayAndName(timelineEl, false);
 
   info("Selecting a negative-delay animated node");
-  yield selectNode(".negative-delay", inspector);
+  yield selectNodeAndWaitForAnimations(".negative-delay", inspector);
   checkDelayAndName(timelineEl, true);
 });
 
 function checkDelayAndName(timelineEl, hasDelay) {
   let delay = timelineEl.querySelector(".delay");
 
   is(!!delay, hasDelay, "The timeline " +
                         (hasDelay ? "contains" : "does not contain") +
--- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_iterations.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_iterations.js
@@ -5,21 +5,21 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Check that the timeline is displays as many iteration elements as there are
 // iterations in an animation.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Selecting the test node");
-  yield selectNode(".delayed", inspector);
+  yield selectNodeAndWaitForAnimations(".delayed", inspector);
 
   info("Getting the animation element from the panel");
   let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
   let animation = timelineEl.querySelector(".time-block");
   let iterations = animation.querySelector(".iterations");
 
   // Iterations are rendered with a repeating linear-gradient, so we need to
   // calculate how many iterations are represented by looking at the background
@@ -27,17 +27,17 @@ add_task(function*() {
   let iterationCount = getIterationCountFromBackground(iterations);
 
   is(iterationCount, 10,
      "The animation timeline contains the right number of iterations");
   ok(!iterations.classList.contains("infinite"),
      "The iteration element doesn't have the infinite class");
 
   info("Selecting another test node with an infinite animation");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   info("Getting the animation element from the panel again");
   animation = timelineEl.querySelector(".time-block");
   iterations = animation.querySelector(".iterations");
 
   iterationCount = getIterationCountFromBackground(iterations);
 
   is(iterationCount, 1,
--- a/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_shows_time_info.js
@@ -5,17 +5,17 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Check that the timeline displays animations' duration, delay and iteration
 // counts in tooltips.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel, controller} = yield openAnimationInspector();
 
   info("Getting the animation element from the panel");
   let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
   let timeBlockNameEls = timelineEl.querySelectorAll(".time-block .name");
 
   // Verify that each time-block's name element has a tooltip that looks sort of
   // ok. We don't need to test the actual content.
--- a/devtools/client/animationinspector/test/browser_animation_timeline_takes_rate_into_account.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_takes_rate_into_account.js
@@ -13,17 +13,17 @@
 
 add_task(function*() {
   yield new Promise(resolve => {
     SpecialPowers.pushPrefEnv({"set": [
       ["dom.animations-api.core.enabled", true]
     ]}, resolve);
   });
 
-  yield addTab(TEST_URL_ROOT + "doc_modify_playbackRate.html");
+  yield addTab(URL_ROOT + "doc_modify_playbackRate.html");
 
   let {panel} = yield openAnimationInspector();
 
   let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
 
   let timeBlocks = timelineEl.querySelectorAll(".time-block");
   is(timeBlocks.length, 2, "2 animations are displayed");
 
--- a/devtools/client/animationinspector/test/browser_animation_timeline_ui.js
+++ b/devtools/client/animationinspector/test/browser_animation_timeline_ui.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Check that the timeline contains the right elements.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
 
   let timeline = panel.animationsTimelineComponent;
   let el = timeline.rootWrapperEl;
 
   ok(el.querySelector(".time-header"),
      "The header element is in the DOM of the timeline");
   ok(el.querySelectorAll(".time-header .time-tick").length,
--- a/devtools/client/animationinspector/test/browser_animation_toggle_button_resets_on_navigate.js
+++ b/devtools/client/animationinspector/test/browser_animation_toggle_button_resets_on_navigate.js
@@ -4,21 +4,21 @@
 
 "use strict";
 
 requestLongerTimeout(2);
 
 // Test that a page navigation resets the state of the global toggle button.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, panel} = yield openAnimationInspector();
 
   info("Select the non-animated test node");
-  yield selectNode(".still", inspector);
+  yield selectNodeAndWaitForAnimations(".still", inspector);
 
   ok(!panel.toggleAllButtonEl.classList.contains("paused"),
     "The toggle button is in its running state by default");
 
   info("Toggle all animations, so that they pause");
   yield panel.toggleAll();
   ok(panel.toggleAllButtonEl.classList.contains("paused"),
     "The toggle button now is in its paused state");
--- a/devtools/client/animationinspector/test/browser_animation_toggle_button_toggles_animations.js
+++ b/devtools/client/animationinspector/test/browser_animation_toggle_button_toggles_animations.js
@@ -7,17 +7,17 @@
 requestLongerTimeout(2);
 
 // Test that the main toggle button actually toggles animations.
 // This test doesn't need to be extra careful about checking that *all*
 // animations have been paused (including inside iframes) because there's an
 // actor test in /devtools/server/tests/browser/ that does this.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel} = yield openAnimationInspector();
 
   info("Click the toggle button");
   yield panel.toggleAll();
   yield checkState("paused");
 
   info("Click again the toggle button");
   yield panel.toggleAll();
--- a/devtools/client/animationinspector/test/browser_animation_toolbar_exists.js
+++ b/devtools/client/animationinspector/test/browser_animation_toolbar_exists.js
@@ -7,30 +7,30 @@
 requestLongerTimeout(2);
 
 // Test that the animation panel has a top toolbar that contains the play/pause
 // button and that is displayed at all times.
 // Also test that this toolbar gets replaced by the timeline toolbar when there
 // are animations to be displayed.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {inspector, window} = yield openAnimationInspector();
   let doc = window.document;
   let toolbar = doc.querySelector("#global-toolbar");
 
   ok(toolbar, "The panel contains the toolbar element with the new UI");
   ok(!isNodeVisible(toolbar),
      "The toolbar is hidden while there are animations");
 
   let timelineToolbar = doc.querySelector("#timeline-toolbar");
   ok(timelineToolbar, "The panel contains a timeline toolbar element");
   ok(isNodeVisible(timelineToolbar),
      "The timeline toolbar is visible when there are animations");
 
   info("Select a node that has no animations");
-  yield selectNode(".still", inspector);
+  yield selectNodeAndWaitForAnimations(".still", inspector);
 
   ok(isNodeVisible(toolbar),
      "The toolbar is shown when there are no animations");
   ok(!isNodeVisible(timelineToolbar),
      "The timeline toolbar is hidden when there are no animations");
 });
--- a/devtools/client/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js
+++ b/devtools/client/animationinspector/test/browser_animation_ui_updates_when_animation_data_changes.js
@@ -5,21 +5,21 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 // Verify that if the animation's duration, iterations or delay change in
 // content, then the widget reflects the changes.
 
 add_task(function*() {
-  yield addTab(TEST_URL_ROOT + "doc_simple_animation.html");
+  yield addTab(URL_ROOT + "doc_simple_animation.html");
   let {panel, controller, inspector} = yield openAnimationInspector();
 
   info("Select the test node");
-  yield selectNode(".animated", inspector);
+  yield selectNodeAndWaitForAnimations(".animated", inspector);
 
   let animation = controller.animationPlayers[0];
   yield setStyle(animation, panel, "animationDuration", "5.5s");
   yield setStyle(animation, panel, "animationIterationCount", "300");
   yield setStyle(animation, panel, "animationDelay", "45s");
 
   let animationsEl = panel.animationsTimelineComponent.animationsEl;
   let timeBlockEl = animationsEl.querySelector(".time-block");
--- a/devtools/client/animationinspector/test/head.js
+++ b/devtools/client/animationinspector/test/head.js
@@ -1,142 +1,94 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 /* eslint no-unused-vars: [2, {"vars": "local", "args": "none"}] */
 
 "use strict";
 
-var Cu = Components.utils;
-const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
-const {gDevTools} = require("devtools/client/framework/devtools");
-const promise = require("promise");
-const {TargetFactory} = require("devtools/client/framework/target");
-const {console} = Cu.import("resource://gre/modules/Console.jsm", {});
+/* import-globals-from ../../inspector/test/head.js */
+// Import the inspector's head.js first (which itself imports shared-head.js).
+Services.scriptloader.loadSubScript(
+  "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
+  this);
+
 const {ViewHelpers} = Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm", {});
-const DevToolsUtils = require("devtools/shared/DevToolsUtils");
-
-// All tests are asynchronous
-waitForExplicitFinish();
-
-const TEST_URL_ROOT = "http://example.com/browser/devtools/client/animationinspector/test/";
-const ROOT_TEST_DIR = getRootDirectory(gTestPath);
-const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
+const FRAME_SCRIPT_URL = CHROME_URL_ROOT + "doc_frame_script.js";
 const COMMON_FRAME_SCRIPT_URL = "chrome://devtools/content/shared/frame-script-utils.js";
 const TAB_NAME = "animationinspector";
 
 // Auto clean-up when a test ends
 registerCleanupFunction(function*() {
   yield closeAnimationInspector();
 
   while (gBrowser.tabs.length > 1) {
     gBrowser.removeCurrentTab();
   }
 });
 
-// Uncomment this pref to dump all devtools emitted events to the console.
-// Services.prefs.setBoolPref("devtools.dump.emit", true);
-
-// Uncomment this pref to dump all devtools protocol traffic
-// Services.prefs.setBoolPref("devtools.debugger.log", true);
-
-// Set the testing flag on DevToolsUtils and reset it when the test ends
-DevToolsUtils.testing = true;
-registerCleanupFunction(() => DevToolsUtils.testing = false);
-
 // Clean-up all prefs that might have been changed during a test run
 // (safer here because if the test fails, then the pref is never reverted)
 registerCleanupFunction(() => {
-  Services.prefs.clearUserPref("devtools.dump.emit");
   Services.prefs.clearUserPref("devtools.debugger.log");
 });
 
 /**
  * Add a new test tab in the browser and load the given url.
  * @param {String} url The url to be loaded in the new tab
  * @return a promise that resolves to the tab object when the url is loaded
  */
-function addTab(url) {
-  info("Adding a new tab with URL: '" + url + "'");
-  let def = promise.defer();
-
-  window.focus();
-
-  let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
-  let browser = tab.linkedBrowser;
-
-  info("Loading the helper frame script " + FRAME_SCRIPT_URL);
-  browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
-
-  info("Loading the helper frame script " + COMMON_FRAME_SCRIPT_URL);
-  browser.messageManager.loadFrameScript(COMMON_FRAME_SCRIPT_URL, false);
-
-  browser.addEventListener("load", function onload() {
-    browser.removeEventListener("load", onload, true);
-    info("URL '" + url + "' loading complete");
-
-    def.resolve(tab);
-  }, true);
-
-  return def.promise;
-}
+var _addTab = addTab;
+addTab = function(url) {
+  return _addTab(url).then(tab => {
+    let browser = tab.linkedBrowser;
+    info("Loading the helper frame script " + FRAME_SCRIPT_URL);
+    browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
+    info("Loading the helper frame script " + COMMON_FRAME_SCRIPT_URL);
+    browser.messageManager.loadFrameScript(COMMON_FRAME_SCRIPT_URL, false);
+    return tab;
+  });
+};
 
 /**
  * Reload the current tab location.
  * @param {InspectorPanel} inspector The instance of InspectorPanel currently
  * loaded in the toolbox
  */
 function* reloadTab(inspector) {
   let onNewRoot = inspector.once("new-root");
   yield executeInContent("devtools:test:reload", {}, {}, false);
   yield onNewRoot;
   yield inspector.once("inspector-updated");
 }
 
-/**
- * Get the NodeFront for a given css selector, via the protocol
- * @param {String} selector
- * @param {InspectorPanel} inspector The instance of InspectorPanel currently
- * loaded in the toolbox
- * @return {Promise} Resolves to the NodeFront instance
- */
-function getNodeFront(selector, {walker}) {
-  return walker.querySelector(walker.rootNode, selector);
-}
-
 /*
  * Set the inspector's current selection to a node or to the first match of the
- * given css selector.
+ * given css selector and wait for the animations to be displayed
  * @param {String|NodeFront}
  *        data The node to select
  * @param {InspectorPanel} inspector
  *        The instance of InspectorPanel currently
  * loaded in the toolbox
  * @param {String} reason
  *        Defaults to "test" which instructs the inspector not
  *        to highlight the node upon selection
  * @return {Promise} Resolves when the inspector is updated with the new node
+           and animations of its subtree are properly displayed.
  */
-var selectNode = Task.async(function*(data, inspector, reason = "test") {
-  info("Selecting the node for '" + data + "'");
-  let nodeFront = data;
-  if (!data._form) {
-    nodeFront = yield getNodeFront(data, inspector);
+var selectNodeAndWaitForAnimations = Task.async(
+  function*(data, inspector, reason = "test") {
+    yield selectNode(data, inspector, reason);
+
+    // We want to make sure the rest of the test waits for the animations to
+    // be properly displayed (wait for all target DOM nodes to be previewed).
+    let {AnimationsPanel} = inspector.sidebar.getWindowForTab(TAB_NAME);
+    yield waitForAllAnimationTargets(AnimationsPanel);
   }
-  let updated = inspector.once("inspector-updated");
-  inspector.selection.setNodeFront(nodeFront, reason);
-  yield updated;
-
-  // 99% of the times, selectNode is called to select an animated node, and we
-  // want to make sure the rest of the test waits for the animations to be
-  // properly displayed (wait for all target DOM nodes to be previewed).
-  // Even if there are no animations, this is safe to do.
-  let {AnimationsPanel} = inspector.sidebar.getWindowForTab(TAB_NAME);
-  yield waitForAllAnimationTargets(AnimationsPanel);
-});
+);
 
 /**
  * Check if there are the expected number of animations being displayed in the
  * panel right now.
  * @param {AnimationsPanel} panel
  * @param {Number} nbAnimations The expected number of animations.
  * @param {String} msg An optional string to be used as the assertion message.
  */
@@ -171,33 +123,20 @@ var waitForAnimationInspectorReady = Tas
 });
 
 /**
  * Open the toolbox, with the inspector tool visible and the animationinspector
  * sidebar selected.
  * @return a promise that resolves when the inspector is ready.
  */
 var openAnimationInspector = Task.async(function*() {
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-
-  info("Opening the toolbox with the inspector selected");
-  let toolbox = yield gDevTools.showToolbox(target, "inspector");
-
-  info("Switching to the animationinspector");
-  let inspector = toolbox.getPanel("inspector");
-
-  let panelReady = waitForAnimationInspectorReady(inspector);
-
-  info("Waiting for toolbox focus");
-  yield waitForToolboxFrameFocus(toolbox);
-
-  inspector.sidebar.select(TAB_NAME);
+  let {inspector, toolbox} = yield openInspectorSidebarTab(TAB_NAME);
 
   info("Waiting for the inspector and sidebar to be ready");
-  yield panelReady;
+  yield waitForAnimationInspectorReady(inspector);
 
   let win = inspector.sidebar.getWindowForTab(TAB_NAME);
   let {AnimationsController, AnimationsPanel} = win;
 
   info("Waiting for the animation controller and panel to be ready");
   if (AnimationsPanel.initialized) {
     yield AnimationsPanel.initialized;
   } else {
@@ -223,70 +162,16 @@ var openAnimationInspector = Task.async(
  * @return a promise that resolves when the toolbox has closed.
  */
 var closeAnimationInspector = Task.async(function*() {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   yield gDevTools.closeToolbox(target);
 });
 
 /**
- * Wait for the toolbox frame to receive focus after it loads
- * @param {Toolbox} toolbox
- * @return a promise that resolves when focus has been received
- */
-function waitForToolboxFrameFocus(toolbox) {
-  info("Making sure that the toolbox's frame is focused");
-  let def = promise.defer();
-  let win = toolbox.frame.contentWindow;
-  waitForFocus(def.resolve, win);
-  return def.promise;
-}
-
-/**
- * Checks whether the inspector's sidebar corresponding to the given id already
- * exists
- * @param {InspectorPanel}
- * @param {String}
- * @return {Boolean}
- */
-function hasSideBarTab(inspector, id) {
-  return !!inspector.sidebar.getWindowForTab(id);
-}
-
-/**
- * Wait for eventName on target.
- * @param {Object} target An observable object that either supports on/off or
- * addEventListener/removeEventListener
- * @param {String} eventName
- * @param {Boolean} useCapture Optional, for add/removeEventListener
- * @return A promise that resolves when the event has been handled
- */
-function once(target, eventName, useCapture = false) {
-  info("Waiting for event: '" + eventName + "' on " + target + ".");
-
-  let deferred = promise.defer();
-
-  for (let [add, remove] of [
-    ["addEventListener", "removeEventListener"],
-    ["addListener", "removeListener"],
-    ["on", "off"]
-  ]) {
-    if ((add in target) && (remove in target)) {
-      target[add](eventName, function onEvent(...aArgs) {
-        target[remove](eventName, onEvent, useCapture);
-        deferred.resolve.apply(deferred, aArgs);
-      }, useCapture);
-      break;
-    }
-  }
-
-  return deferred.promise;
-}
-
-/**
  * Wait for a content -> chrome message on the message manager (the window
  * messagemanager is used).
  * @param {String} name The message name
  * @return {Promise} A promise that resolves to the response data when the
  * message has been received
  */
 function waitForContentMessage(name) {
   info("Expecting message " + name + " from content");
index cf17a2f80edc9102c9e2317889f10f864349c210..f10ab2373a6316eb089ef538c6dd9c1e0c09ddb3
GIT binary patch
literal 11743
zc$|%T19)EBw)Pj>wr$&uZJS?gqj8fow$Z4uZM(76xUrfv{@Z)*xqEm2d!Kv9dggl8
zT+evlr7`Dx=NeN<77QF6002M(3T?EdK&3SK-{1iNEo1=T*I9XSH4z4B1qmiQ2XCOQ
ztudpsi}6OP7x%o+)9|E89TNiE%1{-3;)PKhMf*st868i?5V^J_b~`g{5k1CAbRC+u
z=;9P}d<geSqN~}~68(en7oO~`hnK6Tlh&LQ@7JfU?)z))sxL2X)p*1%T7B3>r0}Gi
z+9HxY=&a#{!Uxl!!NS-U?@=U}CLuv?X6HaAgtCRvS>X_f=Tt#h3*$gRf_sdxM}job
z^1!s-u0dIdz(Z%cr~<V_j2&x|A;O5Z1<>UjTUc0nMi(%c3dL@3iM@9^vp<|;YXkhO
z%)?}#feWmh7_2ws1|%qm1R?ZU_#4^l1flf!{C-)`h}iJNKG=Z3+{+*1FlXQUVdQ&q
z2Mk+9UGI6n-I1+H7nG1mfW$r7M13R<X<3R@Gq5TMPrXHYBf826kU;rh4}cwwR0iMM
zt8vB#(3QAe3DXitg$77(LqZ}tzAp34eR+Aks3!wdi8+B!S<8{P`s`+}hgM|c`?8!u
zrQW?L80l=KzOhAuATG}IeE=cdiX9m|JavT#9%|<q-PPys*gL!Ogp!oEgmOUQ?}Z=^
z7Jv2sPVCJKjWeO(ahVGv2N`^1krkRvK#9s4=;2j={TM7Cn6C*-beZ^3Ym40X5}|#+
zHTAo07YGmm=Y@Y2QtDi#vLU@Tq7Y`;il_3lRRTB0_7j}p3rTQqFP$JHjLLY3yubcY
z)pb~P&PG5Db`3e_V!WB-`Hozl1db_I^mHA6N#^|Xvq>=0nN7|+d#lfQY#vXc@Lzcg
z+rD~fD5sJNygm#(n`kpcQaYo}MRpCm71`v~EbO197I3LpNN4AkpOxdp)XIGnD4>0G
z;8)JkIo)}1)WL|T+k;D|<wheE9I2sCo~-AP7J(SYG#>L|b#F71Iz*q{BKCM7mkX=6
zGwm1`d(^H!5=Y4_E<9~8IXH06bnR7i90(_ueMr7eE%~;Vxn(Dm285{`-q=~&8go;{
zm%bQU8dsKs97_v|UTITib$y+k`;q~v(`5#c8>51!!lSAu*%e?%Vx#Ki&G<b8D4M?e
zVA9-)D_874iOVjnu1hvDBgtsn|83CWW%ArZwRE9-d1G>G4)0Sl;!Y`g9|M8rLHt`O
zj~NbExfqRkLm|cq4nmw-4Yy_31CXX}*20IU?$u96MlEJ78cjsKS}ztJR}KD39-*wA
zInG58p7=p=t;=0@=9xAxks_UVPQ_N2UKYYDJSwQ!aC*ND5--_*LguV!zRWp|BPd#-
zMYPv;17}^q!!jmhO0~5Y8JXaSXb^_S7rXY6xrJXwNM7=hp5Bpuq$JrWX+qOZoy1G~
z3&@f?XNHc1il*TpDn%IBf(Cc0>%FvLujC7?DOs}GVx!ACtJ3fc%`samQ2fIx9{iOb
z>gj64YVTpR1CxYXB^hqznodfz@g$lbIv$lwTgZ6bSJ3k-DgR~%g%yE%muj-9%5cIr
z&i6`L=)RSW1-eJip8T*}4A}_516Jue2kYxAT~J*E78N4QzJnh7yWa5f$F+LGD7VUE
z@5YXHa<&GZrk2)G;lKl&Y+pm;F74TiRjS^xdnBS>(u>!Okqzb+ZOe?jI;+UKne;in
zqqZU3fvwBqDUvH<jCJdo>-3X~)**JV4?`L$&o!xecPr?&vv32UPtO`H)#8T7oNXrH
z0^EF7OD*-PuP+@ekxUj}8{XXGN`L}lDJEBEijeXtPUBY!sPndTfXQ{sO_=rN;z&6k
z#PxrZQ+0ZL#hWjk63m@E18oC^QAs$BuwyD*>FMW%;>-=*34bjm!<pewsxjFNH3aY5
z^QTDg<VvyF_avQTgjyErE#U3_s<J`5y}8H-h7zBhsS~y#eNihRNns>jdHzVWBCRF#
z5o7sfmDKXBb>p%H-|+MMru?zIyMyNq9pcPGx0?qA%j~*Q(!OvEUheS(g<_qpq1TX@
zCb23D+Zo-=n)Y&&p*y;0w%L0SR$C}yF`>6S?vP-_=X=dQ=l7S}0d&0(Ab~{SlAfp$
zn@|%HZ_#_6Tst1uCLmrP6SDa4-Zw+-CG#c0z9qbI5FEUbaW{(j*F?S@QBlr>p%aQu
zC5e+)FNuxr542hgy9RII5q$s96xLFn2@3)GLS(3h$%lt!zzMv}mg8V7lIcD}i?G0n
z*_fV6TOTYb6#!+Eq?XPqN}2n7HvMEYhEHD9z2A%~?vY1!36hekNUs^He0S=u_~?5v
zs00e10%354tz87yP|S(hf-GCI5c0fgqG8V^2${SdN0VLmWAG}Fub20SPN;o<64^VF
z#M}0DzZIP-$-q>2PrYt=v`H5YijV?D83~f8m~P#*AN<}n_2vW9U;AaHC&L^BAjJ;t
zM?4!CjK1*}Cht}s!$pWF9M<cKo%1mYq9K%mui&@h)L44=O1AL1lFGRs>C5|Ehc+V`
zH!6sM`II8l25hm^Q@12<PgXY`cWx%)uzlw)qHyKcBo1ch6uutGpweSM{A{u>k#yMe
z1RZN14rQrYy<=t(yt@J_-X>8J`GuamZXHK`<s4Q4TC-C}&06)<x3ia6*?n!~v@Jft
zq5gP3PZ`wV<XgL_G*v|YlARN*mo?#{r9Z=Sbh?O8Yjv!;)YBcEsnm*g1k^%OyWkvV
zgGfRPm(K-}9f@^r!9|*;CK4z5d_%+MxNSM&#LFL@RI`ExShxdl-phtp9=G5WenT+Q
z0`h7dbE)mJO}fC@@trs%t?Vt$qwr&UScC{>qaBFv7Qja<W^jw5+YoqOh&U0g_xsz*
zus!*=0C4bCsAWWqr(P^{Z>1q-fK%xp5(iulxM^Hi;L*2OVd5=W`S%Es@14D%zP30I
zxts@7IR@`<p(@Rb!%Bb{KZLt0TVX>$%OdTUmFBi?>)(!UD3*0l%cCbN#(Ak_V_>Eb
zToXxv;(&wh8GlSAgBM28T_vVg10`{vTw4<p*SLGr_(TuFBzx&9@a^mN9a4>-LxAE_
zW)M`^Aq%WO*Q&`0!!WAkM+Lnf)1<Z-kMO;O%@=aZ$C$3ls2oHW!ACaRstXT?peEf`
z2Tbqp;|XxN+-SY`u77Ae)Y69eBX1<2?vvhZ*7>vBebh~)E~Yyzz5+UDiKWX2m*}_S
zuke%IV0%|6lP9?N)ac9euFSuAeOEo|oQ-Ko{-D2<2T21muL*}%hLn4Kfsb5}8zLQ+
zE^P2-nP{FVr+p}zTU+P0hDGZ!`&7DqZeg`0G%K6alOu&DH@Z?CgAo7HpFY)+asKYo
zeAqc5dMyG@KKuGx|3Fc%T*N{6{wE%<9hP=JdVH+~7w=@qmc|r3`B_7w(Ou;DmJbzW
z&>8-AIGhMD8!=sbj*V6$qR#HuG;p@D$)Bzaj#oMK)AN^c2vRO7l#JyOj<m<3c8^Vc
zpA&ZxqB?GP4uS3j&2;HoHBM1NQW_mqb`DXe%uJu!G0~{U(=UeWCLY}21#Y;7NT@!M
z&WdLlW6-D#=XMxpXC^ZAV=ZSR=1F{ylH{n9IUic7&WLHuS+Fh1w;{xW-n4A+dQ~af
zHI3MzG+k733{jvoJDy*h@<jJ5DN~dRqfU0sP&NJWeQ{gwKskN;J52*dS&YR}-KxZm
z%Z^j?`Y|jK$(1=Q7|JImh5qY2z2%(k49Z*EV_ZZv_3U!oo9Vsu1-E5D7(7n^^MDq<
z9G|e(eSj?6gAMKzPnYuPds87a5$1s01Hfx8rZ@bPkOYD7Z3#vskI}G3?s3A~5O)WW
zBV#hKhDb-ztn^9pBq*WR)k5V^;O>g$tAkH~X+vvQ5iZf}$BX!}@vLP`{9S9@sSm4G
zL4zUl--?$RFdY^VF3XZbY-!PbXnSKqVa{%vQ?gK<vllXCWgDA6f)4u8ZhD8Bl}^;l
z`>UGs$A1O8vB?lk$9mY$Z<0G7p4vxZaJTlfJXyh!+krUtPkzS$EUK&DFNaOM(DPf#
zC*L_4{P<GTjKcRO*;!Eh<=w*2#e`^RQREPBa&HhOzgYZCXE&Ah4*v!*#D$k_<!5x`
zc3E%w_Q$YOGB)b34M-~s_zwIRb!UX#(8y93jzNR_9K)t?PyNHm5|p4g?MqGUA@UDb
ziyQr#PG7MeqBkQV3ajbIKT9igLs{0GT8)}LoIzAtx^N!Uj&^Eny7}`N^X9onwGRbH
zRi+<wq8Kcw(pG<7PUYspP(ms7fb<?C?dae5aP=~vqdo%J<aDajXHf$1UEgRRb^W+&
z(6d`YGA@Xs!bqS|)U2q&>2_*ha^eknwUgMg8j8Rw$5G0=gFv2>Nn}^f%wgPPEY(h?
z%;qzNYb!&vB=qRtmeLjt{W_bk@6KiyP<-XfM45MfqwtycZAQ{jh~=ocnPW^xE`3QY
zoG3;-8~CI{a>N=y8!b9jf(f08lG{pb5WvQsD>gMo3-f3jMZ(SA=3`N@yRN-&$elhM
ze$S@bU;JDGr;Y;u?F~%nzb8z;j0Es!gZf!)9ZZdF&6$38vbrrE{W+lm{3`JO<K)6<
z?c!kXL;Bw}QeI+ReLq;G|Cx^=+X1DVd-7KtPyv9CtiO=>022oXR~J`jW5=IZbu}0O
zm{Qud#;@Y$2?qcHKLP^){%e=5bK<-vk@8wya#UIj%1R<Knw(BP@6E+&r<k;yqM@?L
zR^-WmY!z7}%npelWy0@$|1$Lr4woFGU4sJ+&5y_Ly!m{TYsVzr#;IzRH`%0^mB!$+
zHwAO?+Jj^|XMu8ow#>|kcTuR$<uKlNNdxo<Zo5PAobw2WffN4Zq7*VGyeO(G5&9S`
zQk2hSi~e7}**K+IDVIr@wb~#1ZgR4s{hW>r1nHrri5mchgw*L~3(>7N$$4IBillIB
zZ8NNS(<>%cYRjsr-t+VV6SaKVR@O4*1{8H<x-Yw8`Umgsu|IISsmQUT2|SciwJA{D
ztCx+Tf-Ax%o7ENXcV~T>FYCK9zsZ2wZ793DE6|V?0WXwy9T+C;<`Lj&_q@9^q0QMS
z<42QD+23!J8fzRG?-)%aeIo-pt4C7KaOu#SBk<mYY6Z`$1R)r?6ho(I(80JH-Rm)`
zF~BTh<B^~a(SvEqW`p5nDDM~A2YN7Q(AvO7?7EUAo|bnC=q!FvBxOLYEXs-0<_-G5
zqSXxiWDP&@UJPcGF(C<Sk8Fn1OGIdGCZ{H#ao%ob+DHJkyil%+!p<N9>PpQM@f(?s
zN!66OADmy_$}Q_74Z0{zCZGD2oHNIw#lnp7t>B%dTfkCXts`VTKjZhStB4oEw#4_?
z<Clkp6R<VgKo9qiXC;l+YGtr|0w2~Nty)fmZ|=7$E0%_1Xzq^KK6AbI!oS6RHppJ|
zN<UCnL7uD^$+f62be0vqlzR96m`l801d6HhW~^+D5psu14RZ*H857+kI5fZ@X!3N$
zba;67%+EbcWU%0TMb-BSNNo>e{*ZO+K623j_6q&xah=m7P@TxC@6DcA#><E`me;Z+
zcGZ=FCKu~6K}2wV(PIZ!9q@ejm=1D;)FSWE7Z#-@Z*N{{JYxD>mB1TFVwYX-Ht?1v
zz}5{x#RDeb^KkmS$1v57uB^M6bX-OLGA*ydWj834YL~cTtW9|%I?MD!>Bc298HFdX
zklIRHH;ib(4I%Kx9l%bs^Ag{0o|B5h?6r_W!&A;Z*p&te<^Q1z`bm^?h$ucK#ZDRj
zN=bLt$bs69O>2U5Y20ObN^j%dV*F0RV6PkikHn|ym#+a0lCccNj)e)AZ|-8DDV*w-
z$i)zi#A<-Zq;V*A1yr={izwG%I-^x0;nbIc?}-KFU-dC^c*D~(+pGv3F4m^pgU%~x
zq*X7E;@GCd;jwj`&LzQY)N!Kkm~t?e&Z`34!y1$J7Zg{DP=n9(WIFrORPV-^1^rlC
zx#~%jupLW&eS26H`d$U;-X@2v1$$TK9-ueYo{r-$`aw9>zulAL6$Dni&gE_6GJ=oY
z^)PqEcA8}P9VJd~cb1>0kMrHZ$_W#MDPRJgND%`y$<6ob%Umjv0;9jb*TE=Quz4M*
zTgsG{dL6mY>Bv1?6LwUZwj42a3+NBp9~otKLl$1cU(s`;`6+kl1X3;S=UC2o4jDei
z3osPh8XNgTO$hY7@lG%!R0s-i%hVN0Gb4-JzgL3*gSyS8(ZKu)xgm1vHO0%x-D0@h
zjnZr38xr_<rivTkkXVq+{!DzHA~iGcKHu;AeExo3F@)M6>x>n9zf;PM0%$I)H8kCx
z1m$G@`cMn?RpaHkOocfcsuT)Kgq-sXXc{@T$4F;N8AF^IMrd38xA<akS_U(frerD1
zZAU0tW>P*@;zEf5)JhqxIkD!xi&X=(7NXrOA6aTI&ajnvn{gL9_=%vKp&3K>@+~}x
zL`fb#%#rWQT=TFnb(86DPTmtVPN$d>M2X(GSC8xTU-9D-`e~&d%pi;M5!|EuA|Dx-
z2;TQP;NtB0GDP+V*Nx+ZmW?I`hr_KD$~q0^$Qpo@2cd?<;2KHB<<{w$9<DN@pU4!`
zdkP-y><x~pbx1F|;C!eMwJLcGTChx?FPitRpfxFr5kk#P$RQ%&am4Kk0m)}vp3ZFw
z5t2v(rv?o^q8;}5pmMAb8%X45iNeq=yI4y#KnN@9AE;(BU`}0iQyVkpAdar+o{xhN
zo}zZwXQt(^!$}^wizVsbC8xovC6Y_<$)d1<US{tF#wpoy-Gs|ix_#47VtbpGD@o!4
zEH9wzeCy33;Oms$yvi%d!?aQM!8bI<CzE=!OY!Y+Nj|`R=>uwBKVmnVS2S!qEk3%W
zhdv-$jytBJR`?|Pv7bf+c-1O;F3CGX4FyYy4s_ZVwknz3Bz<L67U)%Fn}zH`!Twmd
z06rn3hTo0tMm1yY6^ks!-;)Fuu8-b^fIEVsnI<0cIT8KVDv{Pq#(LHya!Scl2`7v1
zyY*a?mpkNOt&_ubcXt4;9^uCTxuK~0Tz^mOr>!l&-iv-Jr2Z|US5}z$MZ(A*Ijy&i
z%GC?m6_zkwPFz~!WqH27*K>QgujX0oyH-Be_sbI&)=Lff5H|rlA4TW#6G*$c2nUxe
zsW-`%a|V$lxFcdf1FR{4oNgFI?B@OMRQ_j$srg!dFM6mrIq1}fAHn#Z8NM^1KcAi`
zT)670m)TcDaR>y*Xq*y<-;BZ}p?6B*k_RuM*$CG6Z~@lZa@CM9nyIf_H=uIS<-w->
zY;KdGhYBL9p=+uF-{xYgn(F-p7DHKEBpA%EGO*=eKP+@`Us5<EjHQz(9O|WfMWtc9
zFprwEZDb96(aOLM*^P8V;c~8Q#vecqq_oMGU<5^yQ#2W9fESRQJSw7!6WH7R=xvs2
zKK{w)tYd2u7z1L0eqwA^3Y!F(9&2+WtVtgZZ@8^$CY@htAFpl3<$i4+p*AL)i|A2P
z$}`L;VZk3FXJjM_Z~K9Q1v1Ub3dKx~@e@-aZOx>{_#s2G_{u|+VY`wGj!4XBd{b|J
zt{dMRc}wWbYHwY>2iJ6z7rQ>BHl+D3uPQZ>!8fC=Cv5_s>z&PWKbzU@&KE9u>R24`
zvEB}{_nU8HKJU`wC&{9#1CmWaWYjv%USWIALHsXK1xoPanjFFA&U~D)iO9pr6uhhg
zAx<XN0>vQ$)y7Z10SbDKNOs*H+OE3B^f#Mj#(Y8IMRaS*7m5R^8?FP-aOjnjOT{Bj
z(ioE3jM2ymT=Kpeg5}+!1(rde+6*O2Xc|-)fH=#OI?jeG_`Nh*UT<?o%R9V7wEaZc
zB!Jcu(4T8X{VIm9q%o_RWPF6TQtR5{&18Z*>qRiXz(1#X&mew5-;e#K?1B1OaF&;~
zLIZCH3swuogPXu(6A8!)90;#ZOoR(Fi6wNaX<%g$9DdUp<&EdV9Ny8SDbEwgafug8
z`z{T_owzQVDT8X{h2UXq3QvL>i4rm8y0#-U4EeZ};J|Z@Y-W7PdYvK~dyr5_1)Wc<
z4(p^dfksP9t>K2yS5xW;04Z-6TbPX*;FRK}ZSjzoR7R;cW?UR-^W;6O+D07i-3_L8
z#JdYgn}szyNm@cnBt7BOgJ(sC8G<*rzr%G!A}vJBC2S&%^CSn4{~8Zt^M$C&3CkBN
zZ>@EA)7Q?0EF<Qdizq#r3a{nXKEgafzm;6{Rxu$yqOv^(Pfb+3jh~tqk8lGXB(I-n
zN^arjiVQ-^jjL^W-5Un+z%i*^zMJz?YiDzj_zg5rvEZR*#dg~XBgq8T&srm$g%(Sb
z9knEb1rWe54=LfC&dF_Z%cV|TJpB2)?W=C&oEgr6Un#j}3wQSH$A*+GF=!C2YOD-a
z19nAImL{Eje;D|FPXgk4BOOpXH`uq3Z}seks_J&B_E84yeb!W?@}+UjoaZT9MO-Hx
zjcQ66GN%7ZPlDPXgv@HLMqSX_DB4qoJ7(*ul+qkXE|`j=+vaZ8=l`aw`dQF|S6_mV
zFV*UFgc22T)ik|Pz}Un342>n|hrgu2_T>|&S}&7q_olFNNVMoqgiUn|_OU=DQkjUp
zT{y4SFr9n1roJKG)Xf-=Bw8!lSMLpafdOPKhU>1$guGxU>yP|(&9MU8BH!nt9hT(y
zZrq$N2RdG*^~)?wA((uSxQ1Bh+nrM0HSwfQyB&(zPPN{|KFVg5$6?_q*PJSFXw#W<
z>l3?DHcP7^l}I{reM_S^LIc6c0Y_XD40yz6h$Zd`mkbyZ!K3%kcbW#dvzZPSTBndd
zp0Edv*cSk1oU2__mT9^s(+{eb<a$Z}&<jn6D)PoP#*<M@J>>V5><HI!HGc<Oqnlzh
z!Vovu40#0NfoFzme|$Dq%&WARNH{tV5At%^<#zm<z$3u%2Ckiym{l)$IJ$8^|Aq^3
z{*eATE!HsY7L<i?94jl1eP`ucEoWy+)5P0?s0}OpVbpp&oXbe@k2fngLMQ{iF#_Dz
zi#y(N$>w=~1tQ?gL!l>JO!)&V@Z2+bcv{30{(zGnGY-hZN6hXzM5fBO>ve=Sm}gvr
zkl0sp(^b5}>LwI4Sk-&{&X_T@!fe-mgH8qvdGY+XBc7D^frE4yrPJH}nOF41Jy-QH
zTbe}Eu2+#dXcP6pcXjLP6CT`ERrMN%fHJ^_gDOYo<8bMh41NNt?~QPy7U1P>P&IgK
zB&Ea~jiXj^Z4mX8WM}W~<-a#9o9e21jIbk6OJW@qg=<2ZlFjAyMEe)Gq4~(6E5MY|
zGci96*}06|4)^PFLKj-3K$W-GI#Q@ag%O6fs2}j@1y+P!$8tFr9lMQ07;)=W<EdvS
zF`eiv<TF1TwP2>OOFGY2)`NB4eC}1mI_O=or`AhlH21ELpg{81vLpVcgV4l=+{9tW
zI(_3C)(aLxrK?ORK4dCVkn(1&{CFFfo!%P=!d?f(i++mfqVYopdN8QHy{`B|eLy&4
zHGm*_@2cc^OF3_mx4|niK3$LeR)X4>w6FVH8~OEfKHR&dG!l}wIvN|z1!C{>Idb4Y
zOzE2R(CPdBxs0scfQZ+7wdFNAFi$D17lZR40AwN8ybp73p+95g9@!bUXuj`S)j^$m
zO@&;BdFA;8X|YvoMt&DPe82xiSyutnyRN75NmPIJ`3gFov(aAAv@oKWH#Yq4gbOvl
z{_2__rd+ItOyjfqcx^ns3QmVZ1PeL6r40q8EMlL_Xe2dUFL|WB5w?ifN_)9ci32h{
zJ7E1<?CN_Nb^Y-Mnnj-+gVfm{Pc~fV2nT2ajcKs{dPZ1^&F=S2?sqc_2VMtiQ3?J0
zyQB_6<`!q|4Rg>5ti*TJ!7mCR1iMxAmvpe5vdJqs3SDKe2O$$XFH=V?sNW3T{7~!X
zyE?`v!P>RQt515YZu0D#3YuLF+UjY#`*5b$I?nAj9N!hx5X~9w+~|CTkJZNHe~i>_
zUKeA&$>>iwGbCK5VwFqH-YtLLZsMQ!XdkG_!R}V9_BlNjq{ymYWF|VsmV1cy+b$*j
zW*%pq2_o<=qu*9iDl*b+LtEW67tu~&aR<gfz43+wQi#Xo+LNTa-7|d5#{wy6TPE}t
zS)?ah-i;#nl?q82bo*{{bS;%=DnPImng^(Kl4zalDR5n|4Y!Gc+#dbHGs#tVh0-Tz
z#(ivgem9B{-D_fax%;vG-JBbB4LcL<kA%)^B*e0^5!IWtWNTidDLY5eE!`~fJ38!a
zGP~|AvfUWyysb1uwI%SqwYYPX)5Zdp7Q(gk0`KC2DW6DJW~-#t4pj0>I8%u%84^+7
z#sux09+dBytn0wkdse%2K&9_7q^Gp?tfqHDPpa-gCqeh<bySdUHs0Lq_pe{NGbxQ@
z+w4<-@ckK4p!R*5d9I}2yR`tQ4{%$EKg!5F$+5H`5ZW8$@d@$qZ*}axtl3=cdThP?
zSQ2A7*Fl~?G-!PGbT6_m@)0AguksRy5k#|ZC>(F{Vfuzy=AT}8&XVo<m@88EP*i>F
z%}^R{jMekV!jb1<)L`|rV3Y?gS_@a~57wF6Rj0f=X0WM>V0)ofu@%p0)OnJFS?ir3
z$5WM0+jKpT=)JV)B7+b5$tDFv`z+e5s6Kw?xJA*2JY^($RMytZ0Ts?Pkq1I~C~&Rt
z6+8SyPe(g}uxuFV9xuH2gnZ*fGo+lKFw^r~$9UoF>Eg}%viYK92ZQB)p}ha%EQ-L%
zw7Lm-YZGUYswvz$AHo30M~!V@+ri1Po=$hH5q!Qw>7jT(89YXpcqn(iW&)oZ+N;xs
zbzA!8&l7+KbjqZHoRZ*j7$6>LN<TEJ?VVh1i*Kia(t7qDupfVa+&RX&X42QBxZ&PB
zOdLR{^wLT|jF9BUcgHL8eAZ6X#g`U_IM()@w?BU)y-q0lK~GE$c_PO{x}5;8ow;q#
zh8iJKD7M0D|HqN)c6jH1`X>havpAc(IJh~Rn!7Olvmg3ze#T~I4)zQ#W;Xu;f&C8%
zTcF8*KoR_gGI4hBa4~l_G&8X@{4WN!{{SWV-=KfKGBkia!~7ivK~?s~&sq`)06_hJ
zf!i4a?HR3IqGM|n`k9f#?)e8tRY^nNRYU{{r>9|KqXgR+szwb^O~n+c>~GYH2{fQZ
z70vl=J-h{*we*x)V<Xry19tDNv1RiW<lrL9nEIyT)IDXnUl!WxZ(16#r@d3Rvx|ep
z5JxVqIF#{rkcf7?@`>2K)RE+@e&lZvDh@!;oeX&`OZo(?@bPOGa79Sm@Vr+MCgkI;
z((n?)9J4kASn*fPg{%()>6);a7M4GGut`U+16^~z(I1;3DBiE&4TXXp5Stq;5no?n
zT@>-=W2zqqT*y|wQ7kzo)yrZ8fc)`__<p`3s$jY$QcwV33H)C{U}fxVZ|>s4;Na*A
zbg=)|KhkJ5`Pfxv<jxzqiY&Yls?1xpGD4ltl^SL9vW=pqKB({!@@F9sl|L>TZ$yOK
ztukf%GP&3sHkUglJ`8h?xS!zK6e(^>stB83g4Kc~3DfDBVyEHhVQ*b#E9#EY?Q!KZ
zaQYavI~dX*+d&}tm5Rf+cSg_vQgR`KmTKuB@EbpY9?G<pMafKy-=CYnEjq6iB3rO+
zWeAo-lISbkcM-=<+v3YKdUKX8Wu=@{S$DKh$|&an>95Qs&J&-QuUbqFmX_3$7#Yad
z%AD2dyRwz4^LnnS_r*nn!}($A8-z2$P!yeUhvOjGqj$nTm}_G~@-wvfIfrCfJg_3n
zPUBfGMmA%-hTuAc)uUKqC#6o?%#bPXZfRImD05n5^`2>#3%dL`UKw!V%uEE<7;GDl
zc!9a@-Awlq+k_;1LT{(X68z#Fq-hF<kBj}%S>fi4jxc9(5!nJtH|0kG(_Bg0=+P%_
zcdvjv0ThgB?4PTjT_1g#quc5OdE`wsR!R|7sCUaQ*{&4<4q!Oj(rw596}LX1FSd#j
zFm*#^wqNB!QY0HSDR4c;4quRGKz)+n;bxWR$J6(*G4?nGi1tED<kb)QG@q20I~MJ|
zvhd__iuD^2Zqi?7oB5zOiriN_x}4lE^2}4?WPHITUwd9UYo>h3NrJz7Qr>}*75ey0
z4Q={HGWyKg!yHIWREKK?uKTTy?`x+uAF}#E0nq&w>i3xX)mlOS)Zop`EsWi4U0s+Q
zoy{%Goz3lkwZLD;zrqU)@H^P;*6IlFCmQo-K*Iez3$%A}HMX^7bT+dvPu#H26h;oc
zxItHSUW0(wK-EPAF0iW<y^CBeQ>iWpBsi5f!a76jm0s|;z=f~P#51z&ViSVW(ziQ-
z%^Br2zcpuu+XYBrNzit7!Rs&%iaRD(3POVjagFsN&8-G)N5zA44J~e)R!tIpHZlV1
zATg?I1XH~W=esE@gZ<hyNvEC#c>i8kJ<k0WB}YuEk2}PHf*8HnD_!lrc{(4=4!h9V
zR(+FI`Uu^DKW|;BR4uvsdaXez4>FOBHee2Xq{i4jMOh8$Ma*<5z8d$zUm04|to&k$
zYujV#oOQWge<@Ud^;7+z3Cf^!5_#X4N(<Ix3&v_TWUz(w_xRHqdDP*X569V;>?6;G
z<u=Zt>IgnjATD!t9*f8O1`TSfEE>tB%H;|8_oPgpyg!@WmF~$IRjT+}>t&G5KF*Oj
z1rN^A;>N*jbq~`cTKd`ZD+0RNlPLVE0<utBSx)_iC{5Q?kUBys%NE+3v?G%7()_l~
zh}{iGqwCZ%&Zc&ntE`p=ax;elKu6|;ho?T)0<VPB^ag->IZ>n$$`fA>inR7vBD5oE
z7_FRg3?|+Py_m~viUQ6w6{q@IED=qH>FtL-abr()ZL`?DxsJDYo)!>0Y9!cv7f{bX
zT;bxx+RkXHrs&S`)FH7N3gsn9l=y83a>ZZgaf!w#U~C&3yCRKye0nf4hFMvzpc)d(
z6=-{IUZ%Z%6Td@J`fV9qb{WQC>(4%49PF>l=#1@w7UnLljCK~u@$wF3!q}nrudw&;
zKw5t!w*ZuFX=sDQ+kii?E#4bLS_(&XcV!&3)nvBujrt@Uj{2O&nbB;!T@WzmD6^i8
z`F)<#4yQ<SXX`sb-W8OcjfwBomG6(MtB|0`b+;2cYon7t*Au%q6g(5vW=Klqwo4iv
z53j+JwdHxsTB&fc+0<>9-nTqZ*qKrhv_B|eDp%TUqTaCXJrxotXgJ`2EBBvz`$!b{
z)%^Odt=o2nCDbm`{SE>c>-mMNP-+1#S_i5av374EQbWs|@4$l}76&Bj-b&r@t*;t2
z=~=s<)rkH>S>shKqB)3DB&XY#SlojFcLr6A5Kl!!du{LCqJ4(xHt{KausQC5ZE4>k
zZY%1D{`y+fdxR_8FK;6O(MCs3lpVMQym8Yx^!oa(N7q;jSZJQZRKy5)dM>pl#1Qat
z*w1FK6SQ@LHBh};yVK=)8jznDGD<FIEaOripvxx&WY2uab84y~LMb30TU(x(dw~7+
zs3@N-5tl7dd%rMCQ!BsA5;wuI*u&wlc2JY%$Ue}5oU-1ewO0u1PSK%H9A~+?sZ2i#
zPgJRx#D;Abp5WqYbol*KO9hadSpTef{VZsJzgaQqVgWZL_eGYThCyZlL6(7bYT`@1
z3iCYM_O%<!g4?K^A_L>hcln8NIWX1=^k>*QKiNKK{lu~I+Z(t<S>JxzmtcH5yVf89
zd<2%{r*I%v5fJO0S3CLvjwcizua_rzyV+q1ML5-(vlGbAo(u#O9qgZ%bN<`jg8=^S
zR-Ijp|6ut41rXGqj?Y9`5dM_y{2lbyeCNNd5JUsv_w45{Bq7*8<vX$e3-#+>3j^bR
zB7e_*Li{WH`IpS+e|iAe-yT4m_;+dg&p7noaCXH1Bvt>J0sA+G+<##Bmw^0d7J}bc
z7Kr~>Df`b<B)?H1ll-5g?H|GQcjETnRv4)Gf1&$tsrzTvzte+%usW0ey*m6W!!PeY
zkN$r!43YmYTHvo#f7JqiP=QhWrVRet@cudg{M+7xNK*a%aPU`#zxFGCFtF16Z7-uF
U3jz7d0qN)V{PVJtG{0*956*?XjsO4v
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -282,117 +282,117 @@ promise_test(function(t) {
        + 'property is overridden in the CSS cascade, the animation should '
        + 'still report that it is running on the compositor');
   }));
 }, 'isRunningOnCompositor is true when a property that would otherwise block ' +
    'running on the compositor is overridden in the CSS cascade');
 
 promise_test(function(t) {
   var div = addDiv(t);
-  var animation = div.animate({ opacity: [ 0, 1 ] }, 100000);
+  var animation = div.animate({ opacity: [ 0, 1 ] }, 100000); // 100s
 
   return animation.ready.then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor');
 
-    animation.currentTime = 50000;
-    animation.effect.timing.duration = 10000;
+    animation.currentTime = 50000; // 50s
+    animation.effect.timing.duration = 10000; // 10s
 
     assert_equals(animation.isRunningOnCompositor, false,
        'Animation reports that it is NOT running on the compositor'
        + ' when the animation is set a shorter duration than current time');
   }));
 }, 'animation is immediately removed from compositor' +
    'when timing.duration is made shorter than the current time');
 
 promise_test(function(t) {
   var div = addDiv(t);
-  var animation = div.animate({ opacity: [ 0, 1 ] }, 10000);
+  var animation = div.animate({ opacity: [ 0, 1 ] }, 100000); // 100s
 
   return animation.ready.then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor');
 
-    animation.currentTime = 50000;
+    animation.currentTime = 500000; // 500s
 
     assert_equals(animation.isRunningOnCompositor, false,
       'Animation reports that it is NOT running on the compositor'
       + ' when finished');
 
-    animation.effect.timing.duration = 100000;
+    animation.effect.timing.duration = 1000000; // 1000s
     return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor'
       + ' when restarted');
   }));
 }, 'animation is added to compositor' +
    ' when timing.duration is made longer than the current time');
 
 promise_test(function(t) {
   var div = addDiv(t);
-  var animation = div.animate({ opacity: [ 0, 1 ] }, 10000);
+  var animation = div.animate({ opacity: [ 0, 1 ] }, 100000); // 100s
 
   return animation.ready.then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor');
 
-    animation.effect.timing.endDelay = 10000;
+    animation.effect.timing.endDelay = 100000; // 100s
 
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor'
       + ' when endDelay is changed');
 
-    animation.currentTime = 11000;
+    animation.currentTime = 110000; // 110s
     return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, false,
       'Animation reports that it is NOT running on the compositor'
       + ' when currentTime is during endDelay');
   }));
 }, 'animation is removed from compositor' +
    ' when current time is made longer than the duration even during endDelay');
 
 promise_test(function(t) {
   var div = addDiv(t);
-  var animation = div.animate({ opacity: [ 0, 1 ] }, 10000);
+  var animation = div.animate({ opacity: [ 0, 1 ] }, 100000); // 100s
 
   return animation.ready.then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor');
 
-    animation.effect.timing.endDelay = -20000;
+    animation.effect.timing.endDelay = -200000; // -200s
     return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, false,
       'Animation reports that it is NOT running on the compositor'
       + ' when endTime is negative value');
   }));
 }, 'animation is removed from compositor' +
    ' when endTime is negative value');
 
 promise_test(function(t) {
   var div = addDiv(t);
-  var animation = div.animate({ opacity: [ 0, 1 ] }, 10000);
+  var animation = div.animate({ opacity: [ 0, 1 ] }, 100000); // 100s
 
   return animation.ready.then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor');
 
-    animation.effect.timing.endDelay = -5000;
+    animation.effect.timing.endDelay = -50000; // 50s
     return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, omtaEnabled,
       'Animation reports that it is running on the compositor'
       + ' when endTime is positive and endDelay is negative');
-    animation.currentTime = 6000;
+    animation.currentTime = 60000; // 60s
     return waitForFrame();
   })).then(t.step_func(function() {
     assert_equals(animation.isRunningOnCompositor, false,
       'Animation reports that it is NOT running on the compositor'
       + ' when currentTime is after endTime');
   }));
 }, 'animation is NOT running on compositor' +
-   'when endTime is positive and endDelay is negative');
+   ' when endTime is positive and endDelay is negative');
 
 </script>
 </script>
 </body>
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -809,17 +809,17 @@ nsDOMWindowUtils::SendWheelEvent(float a
 
   wheelEvent.time = PR_Now() / 1000;
 
   nsPresContext* presContext = GetPresContext();
   NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
 
   wheelEvent.refPoint = nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
 
-  widget->DispatchAPZAwareEvent(&wheelEvent);
+  widget->DispatchInputEvent(&wheelEvent);
 
   if (widget->AsyncPanZoomEnabled()) {
     // Computing overflow deltas is not compatible with APZ, so if APZ is
     // enabled, we skip testing it.
     return NS_OK;
   }
 
   bool failedX = false;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7530,30 +7530,30 @@ nsGlobalWindow::MozRequestOverfill(Overf
       return;
     }
   }
 
   aError.Throw(NS_ERROR_NOT_AVAILABLE);
 }
 
 void
-nsGlobalWindow::ClearTimeout(int32_t aHandle, ErrorResult& aError)
+nsGlobalWindow::ClearTimeout(int32_t aHandle)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (aHandle > 0) {
-    ClearTimeoutOrInterval(aHandle, aError);
-  }
-}
-
-void
-nsGlobalWindow::ClearInterval(int32_t aHandle, ErrorResult& aError)
+    ClearTimeoutOrInterval(aHandle);
+  }
+}
+
+void
+nsGlobalWindow::ClearInterval(int32_t aHandle)
 {
   if (aHandle > 0) {
-    ClearTimeoutOrInterval(aHandle, aError);
+    ClearTimeoutOrInterval(aHandle);
   }
 }
 
 void
 nsGlobalWindow::SetResizable(bool aResizable) const
 {
   // nop
 }
@@ -11906,16 +11906,17 @@ nsGlobalWindow::RunTimeoutHandler(nsTime
 
   const char *reason;
   if (timeout->mIsInterval) {
     reason = "setInterval handler";
   } else {
     reason = "setTimeout handler";
   }
 
+  bool abortIntervalHandler = false;
   nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
   RefPtr<Function> callback = handler->GetCallback();
   if (!callback) {
     // Evaluate the timeout expression.
     const char16_t* script = handler->GetHandlerText();
     NS_ASSERTION(script, "timeout has no script nor handler text!");
 
     const char* filename = nullptr;
@@ -11925,26 +11926,44 @@ nsGlobalWindow::RunTimeoutHandler(nsTime
     // New script entry point required, due to the "Create a script" sub-step of
     // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
     nsAutoMicroTask mt;
     AutoEntryScript aes(this, reason, true, aScx->GetNativeContext());
     JS::CompileOptions options(aes.cx());
     options.setFileAndLine(filename, lineNo)
            .setVersion(JSVERSION_DEFAULT);
     JS::Rooted<JSObject*> global(aes.cx(), FastGetGlobalJSObject());
-    nsJSUtils::EvaluateString(aes.cx(), nsDependentString(script),
-                              global, options);
+    nsresult rv =
+      nsJSUtils::EvaluateString(aes.cx(), nsDependentString(script),
+                                global, options);
+    if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
+      abortIntervalHandler = true;
+    }
   } else {
     // Hold strong ref to ourselves while we call the callback.
     nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
-    ErrorResult ignored;
+    ErrorResult rv;
     JS::Rooted<JS::Value> ignoredVal(CycleCollectedJSRuntime::Get()->Runtime());
-    callback->Call(me, handler->GetArgs(), &ignoredVal, ignored, reason);
-    ignored.SuppressException();
-  }
+    callback->Call(me, handler->GetArgs(), &ignoredVal, rv, reason);
+    if (rv.IsUncatchableException()) {
+      abortIntervalHandler = true;
+    }
+
+    rv.SuppressException();
+  }
+
+  // If we received an uncatchable exception, do not schedule the timeout again.
+  // This allows the slow script dialog to break easy DoS attacks like
+  // setInterval(function() { while(1); }, 100);
+  if (abortIntervalHandler) {
+    // If it wasn't an interval timer to begin with, this does nothing.  If it
+    // was, we'll treat it as a timeout that we just ran and discard it when
+    // we return.
+    timeout->mIsInterval = false;
+   }
 
   // We ignore any failures from calling EvaluateString() on the context or
   // Call() on a Function here since we're in a loop
   // where we're likely to be running timeouts whose OS timers
   // didn't fire in time and we don't want to not fire those timers
   // now just because execution of one timer failed. We can't
   // propagate the error to anyone who cares about it from this
   // point anyway, and the script context should have already reported
@@ -12211,17 +12230,17 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
   dummy_timeout->remove();
   timeoutExtraRef = nullptr;
   MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
 
   mTimeoutInsertionPoint = last_insertion_point;
 }
 
 void
-nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID, ErrorResult& aError)
+nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   uint32_t public_id = (uint32_t)aTimerID;
   nsTimeout *timeout;
 
   for (timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
     if (timeout->mPublicId == public_id) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -966,26 +966,26 @@ public:
   int32_t SetTimeout(JSContext* aCx, mozilla::dom::Function& aFunction,
                      int32_t aTimeout,
                      const mozilla::dom::Sequence<JS::Value>& aArguments,
                      mozilla::ErrorResult& aError);
   int32_t SetTimeout(JSContext* aCx, const nsAString& aHandler,
                      int32_t aTimeout,
                      const mozilla::dom::Sequence<JS::Value>& /* unused */,
                      mozilla::ErrorResult& aError);
-  void ClearTimeout(int32_t aHandle, mozilla::ErrorResult& aError);
+  void ClearTimeout(int32_t aHandle);
   int32_t SetInterval(JSContext* aCx, mozilla::dom::Function& aFunction,
                       const mozilla::dom::Optional<int32_t>& aTimeout,
                       const mozilla::dom::Sequence<JS::Value>& aArguments,
                       mozilla::ErrorResult& aError);
   int32_t SetInterval(JSContext* aCx, const nsAString& aHandler,
                       const mozilla::dom::Optional<int32_t>& aTimeout,
                       const mozilla::dom::Sequence<JS::Value>& /* unused */,
                       mozilla::ErrorResult& aError);
-  void ClearInterval(int32_t aHandle, mozilla::ErrorResult& aError);
+  void ClearInterval(int32_t aHandle);
   void Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData,
             mozilla::ErrorResult& aError);
   void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String,
             mozilla::ErrorResult& aError);
   mozilla::dom::DOMStorage* GetSessionStorage(mozilla::ErrorResult& aError);
   mozilla::dom::DOMStorage* GetLocalStorage(mozilla::ErrorResult& aError);
   mozilla::dom::Selection* GetSelectionOuter();
   mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
@@ -1430,18 +1430,17 @@ public:
   int32_t SetTimeoutOrInterval(JSContext* aCx,
                                mozilla::dom::Function& aFunction,
                                int32_t aTimeout,
                                const mozilla::dom::Sequence<JS::Value>& aArguments,
                                bool aIsInterval, mozilla::ErrorResult& aError);
   int32_t SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
                                int32_t aTimeout, bool aIsInterval,
                                mozilla::ErrorResult& aError);
-  void ClearTimeoutOrInterval(int32_t aTimerID,
-                              mozilla::ErrorResult& aError);
+  void ClearTimeoutOrInterval(int32_t aTimerID);
 
   // JS specific timeout functions (JS args grabbed from context).
   nsresult ResetTimersForNonBackgroundWindow();
 
   // The timeout implementation functions.
   void RunTimeout(nsTimeout *aTimeout);
   void RunTimeout() { RunTimeout(nullptr); }
   // Return true if |aTimeout| was cleared while its handler ran.
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -228,17 +228,22 @@ nsJSUtils::EvaluateString(JSContext* aCx
       JS::Rooted<JS::Value> value(aCx, aRetValue);
       JSString* str = JS::ToString(aCx, value);
       ok = !!str;
       aRetValue.set(ok ? JS::StringValue(str) : JS::UndefinedValue());
     }
   }
 
   if (!ok) {
-    rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
+    if (JS_IsExceptionPending(aCx)) {
+      rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
+    } else {
+      rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE;
+    }
+
     if (!aCompileOptions.noScriptRval) {
       aRetValue.setUndefined();
     }
   }
 
   // Wrap the return value into whatever compartment aCx was in.
   if (ok && !aCompileOptions.noScriptRval) {
     if (!JS_WrapValue(aCx, aRetValue)) {
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -793,16 +793,18 @@ skip-if = buildapp == 'b2g' # b2g(bug 90
 [test_plugin_freezing.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #CLICK_TO_PLAY
 [test_processing_instruction_update_stylesheet.xhtml]
 [test_progress_events_for_gzip_data.html]
 [test_range_bounds.html]
 skip-if = toolkit == 'android'
 [test_reentrant_flush.html]
 skip-if = toolkit == 'android'
+[test_setInterval_uncatchable_exception.html]
+skip-if = debug == false
 [test_sync_xhr_timer.xhtml]
 skip-if = toolkit == 'android'
 [test_text_wholeText.html]
 [test_textnode_normalize_in_selection.html]
 [test_textnode_split_in_selection.html]
 [test_title.html]
 [test_treewalker_nextsibling.xml]
 [test_viewport_scroll.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_setInterval_uncatchable_exception.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1252268
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1252268</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1252268">Mozilla Bug 1252268</a>
+
+<script type="text/javascript">
+  function go() {
+    SimpleTest.requestFlakyTimeout("I'm smarter than the test harness");
+
+    var ranOnce = false;
+    var finished = false;
+
+    var interval = setInterval(function () {
+      if (ranOnce) {
+        ok(false, "Don't execute me again!");
+        clearInterval(interval);
+        if (!finished) {
+          finished = true;
+          SimpleTest.finish();
+        }
+      } else {
+        ranOnce = true;
+        ok(true, "Ran the first time");
+        try {
+          TestFunctions.throwUncatchableException();
+          ok(false, "How did we get here!");
+        } catch (e) {
+          ok(false, "How did we get here!?");
+        }
+      }
+    }, 100);
+
+    setTimeout(function() {
+      if (!finished) {
+        finished = true;
+        SimpleTest.finish();
+      }
+    }, 1000);
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
+</script>
+
+</body>
+</html>
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -471,19 +471,18 @@ ErrorResult::SetPendingException(JSConte
     // Nuke any existing exception on cx, to make sure we're uncatchable.
     JS_ClearPendingException(cx);
     // Don't do any reporting.  Just return, to create an
     // uncatchable exception.
     mResult = NS_OK;
     return;
   }
   if (IsJSContextException()) {
-    // Whatever we need to throw is on the JSContext already.  We
-    // can't assert that there is a pending exception on it, though,
-    // because in the uncatchable exception case there won't be one.
+    // Whatever we need to throw is on the JSContext already.
+    MOZ_ASSERT(JS_IsExceptionPending(cx));
     mResult = NS_OK;
     return;
   }
   if (IsErrorWithMessage()) {
     SetPendingExceptionWithMessage(cx);
     return;
   }
   if (IsJSException()) {
@@ -508,16 +507,26 @@ ErrorResult::StealExceptionFromJSContext
     ThrowUncatchableException();
     return;
   }
 
   ThrowJSException(cx, exn);
   JS_ClearPendingException(cx);
 }
 
+void
+ErrorResult::NoteJSContextException(JSContext* aCx)
+{
+  if (JS_IsExceptionPending(aCx)) {
+    mResult = NS_ERROR_DOM_EXCEPTION_ON_JSCONTEXT;
+  } else {
+    mResult = NS_ERROR_UNCATCHABLE_EXCEPTION;
+  }
+}
+
 namespace dom {
 
 bool
 DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
                 const ConstantSpec* cs)
 {
   JS::Rooted<JS::Value> value(cx);
   for (; cs->name; ++cs) {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1267,16 +1267,20 @@ DOMInterfaces = {
 'SVGUnitTypes' : {
     'concrete': False,
 },
 
 'SVGZoomAndPan' : {
     'concrete': False,
 },
 
+'TestFunctions': {
+    'wrapperCache': False
+},
+
 'Text': {
     # Total hack to allow binding code to realize that nsTextNode can
     # in fact be cast to Text.
     'headerFile': 'nsTextNode.h',
 },
 
 'TextDecoder': {
     'wrapperCache': False
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -292,16 +292,22 @@ CallbackObject::CallSetup::~CallSetup()
         // Note that we don't JS_ReportPendingException here because we want to
         // go through our AutoEntryScript's reporting mechanism instead, since
         // it currently owns error reporting.
         mAutoEntryScript->ReportException();
       }
       if (saved) {
         JS_RestoreFrameChain(mCx);
       }
+
+      if (mErrorResult.IsJSContextException()) {
+        // XXXkhuey bug 1117269.
+        // This isn't true anymore ... so throw something else.
+        mErrorResult.Throw(NS_ERROR_UNEXPECTED);
+      }
     }
   }
 
   mAutoIncumbentScript.reset();
   mAutoEntryScript.reset();
 
   // It is important that this is the last thing we do, after leaving the
   // compartment and undoing all our entry/incumbent script changes
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -15178,17 +15178,17 @@ class CallbackMethod(CallbackMember):
             args = "JS::HandleValueArray::empty()"
 
         return fill(
             """
             $*{declCallable}
             $*{declThis}
             if (${callGuard}!JS::Call(cx, ${thisVal}, callable,
                           ${args}, &rval)) {
-              aRv.Throw(NS_ERROR_UNEXPECTED);
+              aRv.NoteJSContextException(cx);
               return${errorReturn};
             }
             """,
             declCallable=self.getCallableDecl(),
             declThis=self.getThisDecl(),
             callGuard=self.getCallGuard(),
             thisVal=self.getThisVal(),
             args=args,
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -230,19 +230,19 @@ public:
   // nsresult will be used.  The passed-in string must be UTF-8.  The nsresult
   // passed in must be one we create DOMExceptions for; otherwise you may get an
   // XPConnect Exception.
   void ThrowDOMException(nsresult rv, const nsACString& message = EmptyCString());
   bool IsDOMException() const { return ErrorCode() == NS_ERROR_DOM_DOMEXCEPTION; }
 
   // Flag on the ErrorResult that whatever needs throwing has been
   // thrown on the JSContext already and we should not mess with it.
-  void NoteJSContextException() {
-    mResult = NS_ERROR_DOM_EXCEPTION_ON_JSCONTEXT;
-  }
+  // If nothing was thrown, this becomes an uncatchable exception.
+  void NoteJSContextException(JSContext* aCx);
+
   // Check whether the ErrorResult says to just throw whatever is on
   // the JSContext already.
   bool IsJSContextException() {
     return ErrorCode() == NS_ERROR_DOM_EXCEPTION_ON_JSCONTEXT;
   }
 
   // Support for uncatchable exceptions.
   void ThrowUncatchableException() {
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -57,16 +57,17 @@ MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, JSEXN_
 MSG_DEF(MSG_INVALID_HEADER_NAME, 1, JSEXN_TYPEERR, "{0} is an invalid header name.")
 MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, JSEXN_TYPEERR, "{0} is an invalid header value.")
 MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, JSEXN_TYPEERR, "Headers require name/value tuples when being initialized by a sequence.")
 MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, JSEXN_TYPEERR, "Permission denied to pass cross-origin object as {0}.")
 MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing required {0}.")
 MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.")
 MSG_DEF(MSG_INVALID_REQUEST_MODE, 1, JSEXN_TYPEERR, "Invalid request mode {0}.")
 MSG_DEF(MSG_INVALID_REFERRER_URL, 1, JSEXN_TYPEERR, "Invalid referrer URL {0}.")
+MSG_DEF(MSG_CROSS_ORIGIN_REFERRER_URL, 2, JSEXN_TYPEERR, "Referrer URL {0} cannot be cross-origin to the entry settings object ({1}).")
 MSG_DEF(MSG_FETCH_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Body has already been consumed.")
 MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, JSEXN_TYPEERR, "Response statusText may not contain newline or carriage return.")
 MSG_DEF(MSG_FETCH_FAILED, 0, JSEXN_TYPEERR, "NetworkError when attempting to fetch resource.")
 MSG_DEF(MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD, 0, JSEXN_TYPEERR, "HEAD or GET Request cannot have a body.")
 MSG_DEF(MSG_RESPONSE_NULL_STATUS_WITH_BODY, 0, JSEXN_TYPEERR, "Response body is given with a null body status.")
 MSG_DEF(MSG_DEFINE_NON_CONFIGURABLE_PROP_ON_WINDOW, 0, JSEXN_TYPEERR, "Not allowed to define a non-configurable property on the WindowProxy object")
 MSG_DEF(MSG_INVALID_ZOOMANDPAN_VALUE_ERROR, 0, JSEXN_RANGEERR, "Invalid zoom and pan value.")
 MSG_DEF(MSG_INVALID_TRANSFORM_ANGLE_ERROR, 0, JSEXN_RANGEERR, "Invalid transform angle.")
--- a/dom/bindings/moz.build
+++ b/dom/bindings/moz.build
@@ -95,24 +95,26 @@ SOURCES += [
 
 # Tests for maplike and setlike require bindings to be built, which means they
 # must be included in libxul. This breaks the "no test classes are exported"
 # rule stated in the test/ directory, but it's the only way this will work.
 # Test classes are only built in debug mode, and all tests requiring use of
 # them are only run in debug mode.
 if CONFIG['MOZ_DEBUG']:
     EXPORTS.mozilla.dom += [
+        "test/TestFunctions.h",
         "test/TestInterfaceIterableDouble.h",
         "test/TestInterfaceIterableSingle.h",
         "test/TestInterfaceMaplike.h",
         "test/TestInterfaceMaplikeObject.h",
         "test/TestInterfaceSetlike.h",
         "test/TestInterfaceSetlikeNode.h"
         ]
     UNIFIED_SOURCES += [
+        "test/TestFunctions.cpp",
         "test/TestInterfaceIterableDouble.cpp",
         "test/TestInterfaceIterableSingle.cpp",
         "test/TestInterfaceMaplike.cpp",
         "test/TestInterfaceMaplikeObject.cpp",
         "test/TestInterfaceSetlike.cpp",
         "test/TestInterfaceSetlikeNode.cpp",
         ]
 
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/TestFunctions.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/TestFunctions.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */ void
+TestFunctions::ThrowUncatchableException(GlobalObject& aGlobal,
+                                         ErrorResult& aRv)
+{
+  aRv.ThrowUncatchableException();
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/TestFunctions.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_TestFunctions_h
+#define mozilla_dom_TestFunctions_h
+
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
+
+namespace mozilla {
+namespace dom {
+
+class TestFunctions : public NonRefcountedDOMObject {
+public:
+  static void
+  ThrowUncatchableException(GlobalObject& aGlobal, ErrorResult& aRv);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_TestFunctions_h
--- a/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothMapSmsManager.cpp
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothMapSmsManager.h"
 
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/BluetoothMapParametersBinding.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/Endian.h"
 #include "mozilla/dom/File.h"
 
 #include "mozilla/RefPtr.h"
--- a/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothOppManager.cpp
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothOppManager.h"
 
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
--- a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothPbapManager.h"
 
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 
 #include "mozilla/dom/BluetoothPbapParametersBinding.h"
 #include "mozilla/Endian.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -24,17 +24,17 @@
 #include "BluetoothHfpManager.h"
 #include "BluetoothHidManager.h"
 #include "BluetoothMapSmsManager.h"
 #include "BluetoothOppManager.h"
 #include "BluetoothPbapManager.h"
 #include "BluetoothProfileController.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/ipc/SocketBase.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 
 #define ENSURE_BLUETOOTH_IS_ENABLED(runnable, result)                  \
   do {                                                                 \
--- a/dom/bluetooth/bluez/BluetoothDBusService.cpp
+++ b/dom/bluetooth/bluez/BluetoothDBusService.cpp
@@ -23,17 +23,17 @@
 #include "BluetoothHashKeys.h"
 #include "BluetoothHfpManager.h"
 #include "BluetoothHidManager.h"
 #include "BluetoothOppManager.h"
 #include "BluetoothProfileController.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUnixSocketConnector.h"
 #include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 
 #include <cstdio>
 #include <dbus/dbus.h>
 
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "nsDebug.h"
 #include "nsDataHashtable.h"
--- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp
@@ -8,17 +8,17 @@
 
 #include "BluetoothHfpManager.h"
 
 #include "BluetoothProfileController.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 
 #include "jsapi.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
--- a/dom/bluetooth/bluez/BluetoothOppManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothOppManager.cpp
@@ -5,17 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothOppManager.h"
 
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 #include "ObexBase.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
--- a/dom/bluetooth/common/BluetoothProfileController.cpp
+++ b/dom/bluetooth/common/BluetoothProfileController.cpp
@@ -194,21 +194,29 @@ BluetoothProfileController::SetupProfile
   NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);
 
   // Audio bit should be set if remote device supports HFP/HSP.
   if (hasAudio) {
     AddProfile(BluetoothHfpManager::Get());
   }
 
   // Rendering bit should be set if remote device supports A2DP.
-  // A device which supports AVRCP should claim that it's a peripheral and it's
-  // a remote control.
-  if (hasRendering || (isPeripheral && isRemoteControl)) {
+  if (hasRendering) {
     AddProfile(BluetoothA2dpManager::Get());
-    AddProfile(BluetoothAvrcpManager::Get()); // register after A2DP
+  }
+
+  // A remote control may either support HID or AVRCP since class of device
+  // value are the same. So we can only differentiate between AVRCP and HID
+  // by using hasRendering bit.
+  if ((isPeripheral && isRemoteControl)) {
+    if (hasRendering) {
+      AddProfile(BluetoothAvrcpManager::Get());
+    } else {
+      AddProfile(BluetoothHidManager::Get());
+    }
   }
 
   // A device which supports HID should claim that it's a peripheral and it's
   // either a keyboard, a pointing device, or both.
   if (isPeripheral && (isKeyboard || isPointingDevice)) {
     AddProfile(BluetoothHidManager::Get());
   }
 }
--- a/dom/bluetooth/common/BluetoothProfileController.h
+++ b/dom/bluetooth/common/BluetoothProfileController.h
@@ -2,17 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_BluetoothProfileController_h
 #define mozilla_dom_bluetooth_BluetoothProfileController_h
 
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 #include "nsISupportsImpl.h"
 #include "nsAutoPtr.h"
 #include "nsITimer.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 /*
  * Class of Device(CoD): 32-bit unsigned integer
rename from dom/bluetooth/common/BluetoothUuid.cpp
rename to dom/bluetooth/common/BluetoothUuidHelper.cpp
--- a/dom/bluetooth/common/BluetoothUuid.cpp
+++ b/dom/bluetooth/common/BluetoothUuidHelper.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "BluetoothUuid.h"
+#include "BluetoothUuidHelper.h"
 
 #include "BluetoothA2dpManager.h"
 #include "BluetoothAvrcpManager.h"
 #include "BluetoothHfpManager.h"
 #include "BluetoothHidManager.h"
 #include "BluetoothOppManager.h"
 
 USING_BLUETOOTH_NAMESPACE
rename from dom/bluetooth/common/BluetoothUuid.h
rename to dom/bluetooth/common/BluetoothUuidHelper.h
--- a/dom/bluetooth/common/BluetoothUuid.h
+++ b/dom/bluetooth/common/BluetoothUuidHelper.h
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_dom_bluetooth_BluetoothUuid_h
-#define mozilla_dom_bluetooth_BluetoothUuid_h
+#ifndef mozilla_dom_bluetooth_BluetoothUuidHelper_h
+#define mozilla_dom_bluetooth_BluetoothUuidHelper_h
 
 #include "BluetoothCommon.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothProfileManagerBase;
 
 class BluetoothUuidHelper
@@ -46,9 +46,9 @@ enum BluetoothReservedChannels {
   CHANNEL_SIM_ACCESS     = 15,
   CHANNEL_PBAP_PSE       = 19,
   CHANNEL_FTP            = 20,
   CHANNEL_OPUSH_L2CAP    = 5255
 };
 
 END_BLUETOOTH_NAMESPACE
 
-#endif // mozilla_dom_bluetooth_BluetoothUuid_h
+#endif // mozilla_dom_bluetooth_BluetoothUuidHelper_h
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -18,17 +18,17 @@ if CONFIG['MOZ_B2G_BT']:
     SOURCES += [
         'common/BluetoothGattReplyRunnable.cpp',
         'common/BluetoothHidManager.cpp',
         'common/BluetoothInterface.cpp',
         'common/BluetoothProfileController.cpp',
         'common/BluetoothReplyRunnable.cpp',
         'common/BluetoothService.cpp',
         'common/BluetoothUtils.cpp',
-        'common/BluetoothUuid.cpp',
+        'common/BluetoothUuidHelper.cpp',
         'common/ObexBase.cpp',
         'common/webapi/BluetoothAdapter.cpp',
         'common/webapi/BluetoothClassOfDevice.cpp',
         'common/webapi/BluetoothDevice.cpp',
         'common/webapi/BluetoothDiscoveryHandle.cpp',
         'common/webapi/BluetoothGatt.cpp',
         'common/webapi/BluetoothGattAttributeEvent.cpp',
         'common/webapi/BluetoothGattCharacteristic.cpp',
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -5351,33 +5351,33 @@ CanvasRenderingContext2D::FillRuleChange
     mPath = nullptr;
   }
 }
 
 void
 CanvasRenderingContext2D::PutImageData(ImageData& aImageData, double aDx,
                                        double aDy, ErrorResult& aError)
 {
-  dom::Uint8ClampedArray arr;
+  RootedTypedArray<Uint8ClampedArray> arr(nsContentUtils::RootingCxForThread());
   DebugOnly<bool> inited = arr.Init(aImageData.GetDataObject());
   MOZ_ASSERT(inited);
 
   aError = PutImageData_explicit(JS::ToInt32(aDx), JS::ToInt32(aDy),
                                 aImageData.Width(), aImageData.Height(),
                                 &arr, false, 0, 0, 0, 0);
 }
 
 void
 CanvasRenderingContext2D::PutImageData(ImageData& aImageData, double aDx,
                                        double aDy, double aDirtyX,
                                        double aDirtyY, double aDirtyWidth,
                                        double aDirtyHeight,
                                        ErrorResult& aError)
 {
-  dom::Uint8ClampedArray arr;
+  RootedTypedArray<Uint8ClampedArray> arr(nsContentUtils::RootingCxForThread());
   DebugOnly<bool> inited = arr.Init(aImageData.GetDataObject());
   MOZ_ASSERT(inited);
 
   aError = PutImageData_explicit(JS::ToInt32(aDx), JS::ToInt32(aDy),
                                 aImageData.Width(), aImageData.Height(),
                                 &arr, true,
                                 JS::ToInt32(aDirtyX),
                                 JS::ToInt32(aDirtyY),
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -562,26 +562,16 @@ protected:
                                 int32_t aWidth, int32_t aHeight);
 
   /**
     * The number of living nsCanvasRenderingContexts.  When this goes down to
     * 0, we free the premultiply and unpremultiply tables, if they exist.
     */
   static uint32_t sNumLivingContexts;
 
-  /**
-    * Lookup table used to speed up GetImageData().
-    */
-  static uint8_t (*sUnpremultiplyTable)[256];
-
-  /**
-    * Lookup table used to speed up PutImageData().
-    */
-  static uint8_t (*sPremultiplyTable)[256];
-
   static mozilla::gfx::DrawTarget* sErrorTarget;
 
   // Some helpers.  Doesn't modify a color on failure.
   void SetStyleFromUnion(const StringOrCanvasGradientOrCanvasPattern& aValue,
                          Style aWhichStyle);
   void SetStyleFromString(const nsAString& aStr, Style aWhichStyle);
 
   void SetStyleFromGradient(CanvasGradient& aGradient, Style aWhichStyle)
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -203,17 +203,18 @@ UnpackBlobFromImageData(WebGLContext* we
 }
 
 void
 WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
                             GLint level, GLenum internalFormat, GLint xOffset,
                             GLint yOffset, GLint zOffset, GLenum unpackFormat,
                             GLenum unpackType, dom::ImageData* imageData)
 {
-    dom::Uint8ClampedArray scopedArr;
+    dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(
+      nsContentUtils::RootingCxForThread());
 
     UniquePtr<webgl::TexUnpackBlob> blob;
     blob = UnpackBlobFromImageData(mContext, funcName, unpackType, imageData, &scopedArr);
     if (!blob)
         return;
 
     const GLint border = 0;
     TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
--- a/dom/events/test/test_wheel_default_action.html
+++ b/dom/events/test/test_wheel_default_action.html
@@ -4,17 +4,17 @@
   <title>Test for default action of WheelEvent</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>
 <p id="display"></p>
 <div id="content" style="display: none">
-  
+
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.requestFlakyTimeout("untriaged");
 
 var subWin = window.open("window_wheel_default_action.html", "_blank",
--- a/dom/events/test/window_wheel_default_action.html
+++ b/dom/events/test/window_wheel_default_action.html
@@ -80,22 +80,25 @@ function hitEventLoop(aFunc, aTimes)
 
   if (--aTimes) {
     setTimeout(hitEventLoop, 0, aFunc, aTimes);
   } else {
     setTimeout(aFunc, 20);
   }
 }
 
+const zoomResetTopic = "browser-fullZoom:zoomReset";
+SpecialPowers.registerObservers(zoomResetTopic);
+
 function onZoomReset(aCallback) {
-  var topic = "browser-fullZoom:zoomReset";
+  var specialPowersTopic = "specialpowers-" + zoomResetTopic;
   SpecialPowers.addObserver(function observe() {
-    SpecialPowers.removeObserver(observe, topic);
+    SpecialPowers.removeObserver(observe, specialPowersTopic);
     SimpleTest.executeSoon(aCallback);
-  }, topic, false);
+  }, specialPowersTopic, false);
 }
 
 function setDeltaMultiplierSettings(aSettings, aCallback)
 {
   SpecialPowers.pushPrefEnv({"set": [
     ["mousewheel.default.delta_multiplier_x", aSettings.deltaMultiplierX * 100],
     ["mousewheel.default.delta_multiplier_y", aSettings.deltaMultiplierY * 100],
     ["mousewheel.default.delta_multiplier_z", aSettings.deltaMultiplierZ * 100],
@@ -912,17 +915,17 @@ function doTestScroll(aSettings, aCallba
       } else {
         nextStep();
       }
 
       function nextStep() {
         winUtils.advanceTimeAndRefresh(100);
         doNextTest();
       }
-    }, 10);
+    });
   }
   doNextTest();
 }
 
 function doTestZoom(aSettings, aCallback)
 {
   if ((aSettings.deltaMultiplierX != 1.0  && aSettings.deltaMultiplierX != -1.0) ||
       (aSettings.deltaMultiplierY != 1.0  && aSettings.deltaMultiplierY != -1.0)) {
@@ -1153,17 +1156,17 @@ function doTestZoom(aSettings, aCallback
              description + "not zoomed out, got " + SpecialPowers.getFullZoom(window));
         }
       }
 
       synthesizeKey("0", { accelKey: true });
       onZoomReset(function () {
         hitEventLoop(doNextTest, 20);
       });
-    }, 20);
+    });
   }
   doNextTest();
 }
 
 function doTestZoomedScroll(aCallback)
 {
   var zoom = 1.0;
   function setFullZoom(aWindow, aZoom)
@@ -1244,19 +1247,19 @@ function doTestZoomedScroll(aCallback)
             ok(Math.abs(gScrollableElement.scrollTop - (1000 + (scrolledY - 1000) / 2)) <= 1,
                "doTestZoomedScroll: zoomed vertical scroll amount by pixel wheel event is different from normal, scrollTop=" +
                  gScrollableElement.scrollTop + ", scrolledY=" + scrolledY);
             window.removeEventListener("MozMousePixelScroll", mousePixelScrollHandler, true);
             window.removeEventListener("wheel", wheelHandler, true);
 
             synthesizeKey("0", { accelKey: true });
             onZoomReset(prepareTestZoomedLineScroll);
-          }, 20);
+          });
         }, 20);
-      }, 20);
+      });
     }, 20);
   }
 
   function prepareTestZoomedLineScroll()
   {
     // Reset zoom and store the scroll amount into the data.
     synthesizeKey("0", { accelKey: true });
     zoom = 1.0;
@@ -1329,19 +1332,19 @@ function doTestZoomedScroll(aCallback)
             ok(Math.abs(gScrollableElement.scrollTop - scrolledY) <= 1,
                "doTestZoomedScroll: zoomed vertical scroll amount by line wheel event is different from normal, scrollTop=" +
                  gScrollableElement.scrollTop + ", scrolledY=" + scrolledY);
 
             window.removeEventListener("MozMousePixelScroll", handler, true);
 
             synthesizeKey("0", { accelKey: true });
             onZoomReset(aCallback);
-          }, 20);
+          });
         }, 20);
-      }, 20);
+      });
     }, 20);
   }
 
   // XXX It's too difficult to test page scroll because the page scroll amount
   //     is computed by complex logic.
 
   prepareTestZoomedPixelScroll();
 }
@@ -1592,17 +1595,17 @@ function doTestWholeScroll2(aCallback)
          "doTestWholeScroll, " + kTest.description + ": unexpected scrollTop");
       is(gScrollableElement.scrollLeft, kTest.expectedScrollLeft,
          "doTestWholeScroll, " + kTest.description + ": unexpected scrollLeft");
       if (++index == kTests.length) {
         SimpleTest.executeSoon(aCallback);
       } else {
         doIt();
       }
-    }, 20);
+    });
   }
   doIt();
 }
 
 function doTestActionOverride(aCallback)
 {
   const kNoScroll    = 0x00;
   const kScrollUp    = 0x01;
@@ -1757,24 +1760,25 @@ function doTestActionOverride(aCallback)
       } else {
         is(gScrollableElement.scrollLeft, 1000, description + "scrolled horizontal");
       }
       if (++index == kTests.length) {
         SimpleTest.executeSoon(aCallback);
       } else {
         doIt();
       }
-    }, 20);
+    });
   }
   doIt();
 }
 
 function runTests()
 {
   SpecialPowers.pushPrefEnv({"set": [
+    ["test.events.async.enabled", true],
     ["general.smoothScroll", false],
     ["mousewheel.default.action", 1],      // scroll
     ["mousewheel.default.action.override_x", -1],
     ["mousewheel.with_shift.action", 2],   // history
     ["mousewheel.with_shift.action.override_x", -1],
     ["mousewheel.with_control.action", 3], // zoom
     ["mousewheel.with_control.action.override_x", -1]]},
     runTests2);
@@ -1828,18 +1832,16 @@ function runTests2()
       });
     });
   }
   doTest();
 }
 
 function finishTests()
 {
-  SpecialPowers.clearUserPref("mousewheel.default.action");
-
   winUtils.restoreNormalRefresh();
 
   window.opener.finish();
 }
 
 </script>
 </pre>
 </body>
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -378,17 +378,20 @@ Request::Constructor(const GlobalObject&
         uri->GetSpec(spec);
         CopyUTF8toUTF16(spec, referrerURL);
         if (!referrerURL.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
           nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
           if (principal) {
             nsresult rv = principal->CheckMayLoad(uri, /* report */ false,
                                                   /* allowIfInheritsPrincipal */ false);
             if (NS_FAILED(rv)) {
-              aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
+              nsAutoCString globalOrigin;
+              principal->GetOrigin(globalOrigin);
+              aRv.ThrowTypeError<MSG_CROSS_ORIGIN_REFERRER_URL>(referrer,
+                                                                NS_ConvertUTF8toUTF16(globalOrigin));
               return nullptr;
             }
           }
         }
       } else {
         RefPtr<workers::URL> url = ParseURLFromWorker(aGlobal, referrer, aRv);
         if (NS_WARN_IF(aRv.Failed())) {
           aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
@@ -406,17 +409,18 @@ Request::Constructor(const GlobalObject&
           // to perform the same-origin check.  Overall, on Workers this method
           // can create 3 sync loops (two for constructing URLs and one here) so
           // in the future we may want to optimize it all by off-loading all of
           // this work in a single sync loop.
           RefPtr<ReferrerSameOriginChecker> checker =
             new ReferrerSameOriginChecker(worker, referrerURL, rv);
           checker->Dispatch(aRv);
           if (aRv.Failed() || NS_FAILED(rv)) {
-            aRv.ThrowTypeError<MSG_INVALID_REFERRER_URL>(referrer);
+            aRv.ThrowTypeError<MSG_CROSS_ORIGIN_REFERRER_URL>(referrer,
+                                                              worker->GetLocationInfo().mOrigin);
             return nullptr;
           }
         }
       }
       request->SetReferrer(referrerURL);
     }
   }
 
--- a/dom/gamepad/GamepadFunctions.cpp
+++ b/dom/gamepad/GamepadFunctions.cpp
@@ -45,17 +45,16 @@ AddGamepad(const char* aID,
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(XRE_IsParentProcess());
 
   int index = gGamepadIndex;
   gGamepadIndex++;
   GamepadAdded a(NS_ConvertUTF8toUTF16(nsDependentCString(aID)), index,
                  (uint32_t)aMapping, aNumButtons, aNumAxes);
-  gGamepadIndex++;
   NotifyGamepadChange<GamepadAdded>(a);
   return index;
 }
 
 void
 RemoveGamepad(uint32_t aIndex)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/gamepad/GamepadService.cpp
+++ b/dom/gamepad/GamepadService.cpp
@@ -73,36 +73,42 @@ GamepadService::Observe(nsISupports* aSu
     mozilla::services::GetObserverService();
   observerService->RemoveObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID);
 
   BeginShutdown();
   return NS_OK;
 }
 
 void
-GamepadService::BeginShutdown()
+GamepadService::StopMonitoring()
 {
-  mShuttingDown = true;
-  if (mTimer) {
-    mTimer->Cancel();
-  }
   if (mStarted) {
     if (XRE_IsParentProcess()) {
       MaybeStopGamepadMonitoring();
     } else {
       ContentChild::GetSingleton()->SendGamepadListenerRemoved();
     }
     mStarted = false;
   }
+  mGamepads.Clear();
+}
+
+void
+GamepadService::BeginShutdown()
+{
+  mShuttingDown = true;
+  if (mTimer) {
+    mTimer->Cancel();
+  }
+  StopMonitoring();
   // Don't let windows call back to unregister during shutdown
   for (uint32_t i = 0; i < mListeners.Length(); i++) {
     mListeners[i]->SetHasGamepadEventListener(false);
   }
   mListeners.Clear();
-  mGamepads.Clear();
   sShutdown = true;
 }
 
 void
 GamepadService::AddListener(nsGlobalWindow* aWindow)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
@@ -139,17 +145,21 @@ GamepadService::RemoveListener(nsGlobalW
 
   if (mListeners.IndexOf(aWindow) == NoIndex) {
     return; // doesn't exist
   }
 
   mListeners.RemoveElement(aWindow);
 
   if (mListeners.Length() == 0 && !mShuttingDown && mStarted) {
-    StartCleanupTimer();
+    if (XRE_IsParentProcess()) {
+      StartCleanupTimer();
+    } else {
+      StopMonitoring();
+    }
   }
 }
 
 already_AddRefed<Gamepad>
 GamepadService::GetGamepad(uint32_t aIndex)
 {
   RefPtr<Gamepad> gamepad;
   if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
@@ -501,26 +511,19 @@ GamepadService::TimeoutHandler(nsITimer*
     return;
   }
 
   if (self->mShuttingDown) {
     return;
   }
 
   if (self->mListeners.Length() == 0) {
-    if (XRE_IsParentProcess()) {
-      MaybeStopGamepadMonitoring();
-    } else {
-      ContentChild::GetSingleton()->SendGamepadListenerRemoved();
-    }
-
-    self->mStarted = false;
-      self->mGamepads.Clear();
-    }
+    self->StopMonitoring();
   }
+}
 
 void
 GamepadService::StartCleanupTimer()
 {
   if (mTimer) {
     mTimer->Cancel();
   }
 
--- a/dom/gamepad/GamepadService.h
+++ b/dom/gamepad/GamepadService.h
@@ -34,16 +34,17 @@ class GamepadService : public nsIObserve
   // Returns true if we actually have a service up and running
   static bool IsServiceRunning();
   // Get the singleton service
   static already_AddRefed<GamepadService> GetService();
   // Return true if the API is preffed on.
   static bool IsAPIEnabled();
 
   void BeginShutdown();
+  void StopMonitoring();
 
   // Indicate that |aWindow| wants to receive gamepad events.
   void AddListener(nsGlobalWindow* aWindow);
   // Indicate that |aWindow| should no longer receive gamepad events.
   void RemoveListener(nsGlobalWindow* aWindow);
 
   // Add a gamepad to the list of known gamepads.
   void AddGamepad(uint32_t aIndex, const nsAString& aID, GamepadMappingType aMapping,
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -1745,18 +1745,20 @@ HTMLFormElement::GetActionURL(nsIURI** a
   if (isHttpScheme && document->GetUpgradeInsecureRequests(false)) {
     // let's use the old specification before the upgrade for logging
     nsAutoCString spec;
     rv = actionURL->GetSpec(spec);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ConvertUTF8toUTF16 reportSpec(spec);
 
     // upgrade the actionURL from http:// to use https://
-    rv = actionURL->SetScheme(NS_LITERAL_CSTRING("https"));
+    nsCOMPtr<nsIURI> upgradedActionURL;
+    rv = NS_GetSecureUpgradedURI(actionURL, getter_AddRefs(upgradedActionURL));
     NS_ENSURE_SUCCESS(rv, rv);
+    actionURL = upgradedActionURL.forget();
 
     // let's log a message to the console that we are upgrading a request
     nsAutoCString scheme;
     rv = actionURL->GetScheme(scheme);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ConvertUTF8toUTF16 reportScheme(scheme);
 
     const char16_t* params[] = { reportSpec.get(), reportScheme.get() };
--- a/dom/icc/Icc.cpp
+++ b/dom/icc/Icc.cpp
@@ -99,17 +99,17 @@ Icc::NotifyStkEvent(const nsAString& aNa
 
   nsCOMPtr<nsIStkCmdFactory> cmdFactory =
     do_GetService(ICC_STK_CMD_FACTORY_CONTRACTID);
   NS_ENSURE_TRUE(cmdFactory, NS_ERROR_UNEXPECTED);
 
   cmdFactory->CreateCommandMessage(aStkProactiveCmd, &value);
   NS_ENSURE_TRUE(value.isObject(), NS_ERROR_UNEXPECTED);
 
-  MozStkCommandEventInit init;
+  RootedDictionary<MozStkCommandEventInit> init(cx);
   init.mBubbles = false;
   init.mCancelable = false;
   init.mCommand = value;
 
   RefPtr<MozStkCommandEvent> event =
     MozStkCommandEvent::Constructor(this, aName, init);
 
   return DispatchTrustedEvent(event);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1844,70 +1844,74 @@ TabChild::RecvMouseEvent(const nsString&
                          const bool&     aIgnoreRootScrollFrame)
 {
   APZCCallbackHelper::DispatchMouseEvent(GetPresShell(), aType, CSSPoint(aX, aY),
       aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame, nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN);
   return true;
 }
 
 bool
-TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& event,
+TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& aEvent,
                                  const ScrollableLayerGuid& aGuid,
                                  const uint64_t& aInputBlockId)
 {
-  return RecvRealMouseButtonEvent(event, aGuid, aInputBlockId);
+  return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
 }
 
 bool
-TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& event,
+TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& aEvent,
                                   const ScrollableLayerGuid& aGuid,
                                   const uint64_t& aInputBlockId)
 {
-  return RecvRealMouseButtonEvent(event, aGuid, aInputBlockId);
+  return RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
 }
 
 bool
-TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& event,
+TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
                                    const ScrollableLayerGuid& aGuid,
                                    const uint64_t& aInputBlockId)
 {
   nsEventStatus unused;
   InputAPZContext context(aGuid, aInputBlockId, unused);
 
-  WidgetMouseEvent localEvent(event);
+  WidgetMouseEvent localEvent(aEvent);
   localEvent.widget = mPuppetWidget;
+  APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
+      mPuppetWidget->GetDefaultScale());
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
-  if (event.mFlags.mHandledByAPZ) {
-    mAPZEventState->ProcessMouseEvent(event, aGuid, aInputBlockId);
+  if (aEvent.mFlags.mHandledByAPZ) {
+    mAPZEventState->ProcessMouseEvent(aEvent, aGuid, aInputBlockId);
   }
   return true;
 }
 
 bool
 TabChild::RecvMouseWheelEvent(const WidgetWheelEvent& aEvent,
                               const ScrollableLayerGuid& aGuid,
                               const uint64_t& aInputBlockId)
 {
   if (aEvent.mFlags.mHandledByAPZ) {
     nsCOMPtr<nsIDocument> document(GetDocument());
     APZCCallbackHelper::SendSetTargetAPZCNotification(
       mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
   }
 
-  WidgetWheelEvent event(aEvent);
-  event.widget = mPuppetWidget;
-  APZCCallbackHelper::DispatchWidgetEvent(event);
-
-  if (event.mCanTriggerSwipe) {
-    SendRespondStartSwipeEvent(aInputBlockId, event.TriggersSwipe());
+  WidgetWheelEvent localEvent(aEvent);
+  localEvent.widget = mPuppetWidget;
+  APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
+      mPuppetWidget->GetDefaultScale());
+  APZCCallbackHelper::DispatchWidgetEvent(localEvent);
+
+  if (localEvent.mCanTriggerSwipe) {
+    SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
   }
 
   if (aEvent.mFlags.mHandledByAPZ) {
-    mAPZEventState->ProcessWheelEvent(event, aGuid, aInputBlockId);
+    mAPZEventState->ProcessWheelEvent(localEvent, aGuid, aInputBlockId);
   }
   return true;
 }
 
 bool
 TabChild::RecvMouseScrollTestEvent(const uint64_t& aLayersId,
                                    const FrameMetrics::ViewID& aScrollId, const nsString& aEvent)
 {
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1357,17 +1357,17 @@ bool TabParent::RecvDispatchWheelEvent(c
   if (!widget) {
     return true;
   }
 
   WidgetWheelEvent localEvent(aEvent);
   localEvent.widget = widget;
   localEvent.refPoint -= GetChildProcessOffset();
 
-  widget->DispatchAPZAwareEvent(&localEvent);
+  widget->DispatchInputEvent(&localEvent);
   return true;
 }
 
 bool
 TabParent::RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -26,16 +26,18 @@ VP9Benchmark::IsVP9DecodeFast()
   bool hasPref = Preferences::HasUserValue(sBenchmarkFpsPref);
 
   if (!sHasRunTest && !hasPref) {
     sHasRunTest = true;
 
     RefPtr<WebMDemuxer> demuxer =
       new WebMDemuxer(new BufferMediaResource(sWebMSample, sizeof(sWebMSample), nullptr,
                                               NS_LITERAL_CSTRING("video/webm")));
+    PDMFactory::Init();
+
     RefPtr<Benchmark> estimiser =
       new Benchmark(demuxer,
                     {
                       Preferences::GetInt("media.benchmark.frames", 300), // frames to measure
                       1, // start benchmarking after decoding this frame.
                       8, // loop after decoding that many frames.
                       TimeDuration::FromMilliseconds(
                         Preferences::GetUint("media.benchmark.timeout", 1000))
@@ -56,86 +58,96 @@ VP9Benchmark::IsVP9DecodeFast()
   uint32_t decodeFps = Preferences::GetUint(sBenchmarkFpsPref);
   uint32_t threshold =
     Preferences::GetUint("media.benchmark.vp9.threshold", 150);
 
   return decodeFps >= threshold;
 }
 
 Benchmark::Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters)
-  : QueueObject(AbstractThread::MainThread())
+  : QueueObject(AbstractThread::GetCurrent())
   , mParameters(aParameters)
   , mKeepAliveUntilComplete(this)
   , mPlaybackState(this, aDemuxer)
 {
   MOZ_COUNT_CTOR(Benchmark);
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(Thread(), "Must be run in task queue");
 }
 
 Benchmark::~Benchmark()
 {
   MOZ_COUNT_DTOR(Benchmark);
 }
 
 RefPtr<Benchmark::BenchmarkPromise>
 Benchmark::Run()
 {
+  MOZ_ASSERT(OnThread());
+
   RefPtr<BenchmarkPromise> p = mPromise.Ensure(__func__);
   RefPtr<Benchmark> self = this;
   mPlaybackState.Dispatch(
     NS_NewRunnableFunction([self]() { self->mPlaybackState.DemuxSamples(); }));
   return p;
 }
 
 void
 Benchmark::ReturnResult(uint32_t aDecodeFps)
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(OnThread());
 
   mPromise.ResolveIfExists(aDecodeFps, __func__);
 }
 
 void
 Benchmark::Dispose()
 {
-  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(OnThread());
 
   mKeepAliveUntilComplete = nullptr;
   mPromise.RejectIfExists(false, __func__);
 }
 
+void
+Benchmark::Init()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  PDMFactory::Init();
+}
+
 BenchmarkPlayback::BenchmarkPlayback(Benchmark* aMainThreadState,
                                      MediaDataDemuxer* aDemuxer)
   : QueueObject(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK)))
   , mMainThreadState(aMainThreadState)
   , mDecoderTaskQueue(new FlushableTaskQueue(GetMediaThreadPool(
                         MediaThreadType::PLATFORM_DECODER)))
   , mDemuxer(aDemuxer)
   , mSampleIndex(0)
   , mFrameCount(0)
   , mFinished(false)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-  PDMFactory::Init();
+  MOZ_ASSERT(static_cast<Benchmark*>(mMainThreadState)->OnThread());
 }
 
 void
 BenchmarkPlayback::DemuxSamples()
 {
   MOZ_ASSERT(OnThread());
 
   RefPtr<Benchmark> ref(mMainThreadState);
   mDemuxer->Init()->Then(
     Thread(), __func__,
     [this, ref](nsresult aResult) {
       MOZ_ASSERT(OnThread());
       mTrackDemuxer =
         mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
       if (!mTrackDemuxer) {
         MainThreadShutdown();
+        return;
       }
       DemuxNextSample();
     },
     [this, ref](DemuxerFailureReason aReason) { MainThreadShutdown(); });
 }
 
 void
 BenchmarkPlayback::DemuxNextSample()
@@ -174,30 +186,32 @@ BenchmarkPlayback::InitDecoder(TrackInfo
   RefPtr<PDMFactory> platform = new PDMFactory();
   mDecoder = platform->CreateDecoder(aInfo, mDecoderTaskQueue, this);
   if (!mDecoder) {
     MainThreadShutdown();
     return;
   }
   RefPtr<Benchmark> ref(mMainThreadState);
   mDecoder->Init()->Then(
-    ref->Thread(), __func__,
+    Thread(), __func__,
     [this, ref](TrackInfo::TrackType aTrackType) {
-      Dispatch(NS_NewRunnableFunction([this, ref]() { InputExhausted(); }));
+      InputExhausted();
     },
     [this, ref](MediaDataDecoder::DecoderFailureReason aReason) {
       MainThreadShutdown();
     });
 }
 
 void
 BenchmarkPlayback::MainThreadShutdown()
 {
   MOZ_ASSERT(OnThread());
 
+  mFinished = true;
+
   if (mDecoder) {
     mDecoder->Flush();
     mDecoder->Shutdown();
     mDecoder = nullptr;
   }
 
   mDecoderTaskQueue->BeginShutdown();
   mDecoderTaskQueue->AwaitShutdownAndIdle();
@@ -226,17 +240,16 @@ BenchmarkPlayback::Output(MediaData* aDa
       mDecodeStartTime = TimeStamp::Now();
     }
     int32_t frames = mFrameCount - ref->mParameters.mStartupFrame;
     TimeDuration elapsedTime = TimeStamp::Now() - mDecodeStartTime;
     if (!mFinished &&
         (frames == ref->mParameters.mFramesToMeasure ||
          elapsedTime >= ref->mParameters.mTimeout)) {
       uint32_t decodeFps = frames / elapsedTime.ToSeconds();
-      mFinished = true;
       MainThreadShutdown();
       ref->Dispatch(NS_NewRunnableFunction([ref, decodeFps]() {
         ref->ReturnResult(decodeFps);
       }));
     }
   }));
 }
 
@@ -271,17 +284,16 @@ BenchmarkPlayback::InputExhausted()
 void
 BenchmarkPlayback::DrainComplete()
 {
   RefPtr<Benchmark> ref(mMainThreadState);
   Dispatch(NS_NewRunnableFunction([this, ref]() {
     int32_t frames = mFrameCount - ref->mParameters.mStartupFrame;
     TimeDuration elapsedTime = TimeStamp::Now() - mDecodeStartTime;
     uint32_t decodeFps = frames / elapsedTime.ToSeconds();
-    mFinished = true;
     MainThreadShutdown();
     ref->Dispatch(NS_NewRunnableFunction([ref, decodeFps]() {
       ref->ReturnResult(decodeFps);
     }));
   }));
 }
 
 bool
--- a/dom/media/Benchmark.h
+++ b/dom/media/Benchmark.h
@@ -17,48 +17,48 @@
 
 namespace mozilla {
 
 class FlushableTaskQueue;
 class Benchmark;
 
 class BenchmarkPlayback : public QueueObject, private MediaDataDecoderCallback
 {
-public:
+  friend class Benchmark;
   explicit BenchmarkPlayback(Benchmark* aMainThreadState, MediaDataDemuxer* aDemuxer);
   void DemuxSamples();
   void DemuxNextSample();
   void MainThreadShutdown();
   void InitDecoder(TrackInfo&& aInfo);
 
   // MediaDataDecoderCallback
   // Those methods are called on the MediaDataDecoder's task queue.
   void Output(MediaData* aData) override;
   void Error() override;
   void InputExhausted() override;
   void DrainComplete() override;
   bool OnReaderTaskQueue() override;
 
-private:
   Atomic<Benchmark*> mMainThreadState;
 
   RefPtr<FlushableTaskQueue> mDecoderTaskQueue;
   RefPtr<MediaDataDecoder> mDecoder;
 
-  RefPtr<TaskQueue> mTaskQueue;
-  // Object only accessed on mTaskQueue
+  // Object only accessed on Thread()
   RefPtr<MediaDataDemuxer> mDemuxer;
   RefPtr<MediaTrackDemuxer> mTrackDemuxer;
   nsTArray<RefPtr<MediaRawData>> mSamples;
   size_t mSampleIndex;
   TimeStamp mDecodeStartTime;
   uint32_t mFrameCount;
   bool mFinished;
 };
 
+// Init() must have been called at least once prior on the
+// main thread.
 class Benchmark : public QueueObject
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Benchmark)
 
   struct Parameters
   {
     Parameters()
@@ -80,23 +80,25 @@ public:
     const Maybe<int32_t> mStopAtFrame;
     const TimeDuration mTimeout;
   };
 
   typedef MozPromise<uint32_t, bool, /* IsExclusive = */ true> BenchmarkPromise;
 
   explicit Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters = Parameters());
   RefPtr<BenchmarkPromise> Run();
+
+  static void Init();
+
+private:
+  friend class BenchmarkPlayback;
+  virtual ~Benchmark();
   void ReturnResult(uint32_t aDecodeFps);
   void Dispose();
-
   const Parameters mParameters;
-
-private:
-  virtual ~Benchmark();
   RefPtr<Benchmark> mKeepAliveUntilComplete;
   BenchmarkPlayback mPlaybackState;
   MozPromiseHolder<BenchmarkPromise> mPromise;
 };
 
 class VP9Benchmark
 {
 public:
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -275,17 +275,17 @@ bool DecoderTraits::DecoderWaitsForOnCon
   return false;
 #endif
 }
 
 #ifdef MOZ_ANDROID_OMX
 static bool
 IsAndroidMediaType(const nsACString& aType)
 {
-  if (!MediaDecoder::IsAndroidMediaEnabled()) {
+  if (!MediaDecoder::IsAndroidMediaPluginEnabled()) {
     return false;
   }
 
   static const char* supportedTypes[] = {
     "audio/mpeg", "audio/mp4", "video/mp4", "video/x-m4v", nullptr
   };
   return CodecListContains(supportedTypes, aType);
 }
@@ -415,17 +415,17 @@ DecoderTraits::CanHandleCodecsType(const
       codecList = gH264Codecs;
     }
   }
 #endif
 #ifdef MOZ_DIRECTSHOW
   DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList);
 #endif
 #ifdef MOZ_ANDROID_OMX
-  if (MediaDecoder::IsAndroidMediaEnabled()) {
+  if (MediaDecoder::IsAndroidMediaPluginEnabled()) {
     EnsureAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList);
   }
 #endif
   if (!codecList) {
     return CANPLAY_MAYBE;
   }
 
   // See http://www.rfc-editor.org/rfc/rfc4281.txt for the description
@@ -494,17 +494,17 @@ DecoderTraits::CanHandleMediaType(const 
   }
 #endif
 #ifdef MOZ_DIRECTSHOW
   if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), nullptr)) {
     return CANPLAY_MAYBE;
   }
 #endif
 #ifdef MOZ_ANDROID_OMX
-  if (MediaDecoder::IsAndroidMediaEnabled() &&
+  if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), nullptr)) {
     return CANPLAY_MAYBE;
   }
 #endif
 #ifdef NECKO_PROTOCOL_rtsp
   if (IsRtspSupportedType(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
@@ -571,17 +571,17 @@ InstantiateDecoder(const nsACString& aTy
 #endif
 #ifdef NECKO_PROTOCOL_rtsp
   if (IsRtspSupportedType(aType)) {
     decoder = new RtspOmxDecoder(aOwner);
     return decoder.forget();
   }
 #endif
 #ifdef MOZ_ANDROID_OMX
-  if (MediaDecoder::IsAndroidMediaEnabled() &&
+  if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoder = new AndroidMediaDecoder(aOwner, aType);
     return decoder.forget();
   }
 #endif
 
   if (IsWebMSupportedType(aType)) {
     decoder = new WebMDecoder(aOwner);
@@ -643,17 +643,17 @@ MediaDecoderReader* DecoderTraits::Creat
     decoderReader = new WaveReader(aDecoder);
   } else
 #ifdef MOZ_OMX_DECODER
   if (IsOmxSupportedType(aType)) {
     decoderReader = new MediaOmxReader(aDecoder);
   } else
 #endif
 #ifdef MOZ_ANDROID_OMX
-  if (MediaDecoder::IsAndroidMediaEnabled() &&
+  if (MediaDecoder::IsAndroidMediaPluginEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoderReader = new AndroidMediaReader(aDecoder, aType);
   } else
 #endif
   if (IsWebMSupportedType(aType)) {
     decoderReader =
       new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()));
   } else
@@ -684,17 +684,17 @@ bool DecoderTraits::IsSupportedInVideoDo
     // We support the formats in gB2GOnlyTypes only inside WebApps on firefoxOS
     // but not in general web content. Ensure we dont create a VideoDocument
     // when accessing those format URLs directly.
     (IsOmxSupportedType(aType) &&
      !IsB2GSupportOnlyType(aType)) ||
 #endif
     IsWebMSupportedType(aType) ||
 #ifdef MOZ_ANDROID_OMX
-    (MediaDecoder::IsAndroidMediaEnabled() && IsAndroidMediaType(aType)) ||
+    (MediaDecoder::IsAndroidMediaPluginEnabled() && IsAndroidMediaType(aType)) ||
 #endif
 #ifdef MOZ_FMP4
     IsMP4SupportedType(aType) ||
 #endif
     IsMP3SupportedType(aType) ||
     IsAACSupportedType(aType) ||
 #ifdef MOZ_DIRECTSHOW
     IsDirectShowSupportedType(aType) ||
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -25,16 +25,20 @@
 #include "mozilla/dom/AudioTrack.h"
 #include "mozilla/dom/AudioTrackList.h"
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/VideoTrack.h"
 #include "mozilla/dom/VideoTrackList.h"
 #include "nsPrintfCString.h"
 #include "mozilla/Telemetry.h"
 
+#ifdef MOZ_ANDROID_OMX
+#include "AndroidBridge.h"
+#endif
+
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::media;
 
 // Default timeout msecs until try to enter dormant state by heuristic.
 static const int DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS = 60000;
 
 namespace mozilla {
@@ -1686,19 +1690,21 @@ bool
 MediaDecoder::IsOmxEnabled()
 {
   return Preferences::GetBool("media.omx.enabled", false);
 }
 #endif
 
 #ifdef MOZ_ANDROID_OMX
 bool
-MediaDecoder::IsAndroidMediaEnabled()
+MediaDecoder::IsAndroidMediaPluginEnabled()
 {
-  return Preferences::GetBool("media.plugins.enabled");
+  return AndroidBridge::Bridge() &&
+         AndroidBridge::Bridge()->GetAPIVersion() < 16 &&
+         Preferences::GetBool("media.plugins.enabled");
 }
 #endif
 
 NS_IMETHODIMP
 MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
                                    nsISupports* aData, bool aAnonymize)
 {
   int64_t video = 0, audio = 0;
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -450,17 +450,17 @@ private:
   static bool IsRtspEnabled();
 #endif
 
 #ifdef MOZ_OMX_DECODER
   static bool IsOmxEnabled();
 #endif
 
 #ifdef MOZ_ANDROID_OMX
-  static bool IsAndroidMediaEnabled();
+  static bool IsAndroidMediaPluginEnabled();
 #endif
 
 #ifdef MOZ_WMF
   static bool IsWMFEnabled();
 #endif
 
   // Return statistics. This is used for progress events and other things.
   // This can be called from any thread. It's only a snapshot of the
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -858,17 +858,17 @@ MediaDecoderStateMachine::MaybeFinishDec
   }
   FinishDecodeFirstFrame();
   if (!mQueuedSeek.Exists()) {
     return false;
   }
 
   // We can now complete the pending seek.
   SetState(DECODER_STATE_SEEKING);
-  InitiateSeek(mQueuedSeek);
+  InitiateSeek(Move(mQueuedSeek));
   return true;
 }
 
 void
 MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample,
                                          TimeStamp aDecodeStartTime)
 {
   MOZ_ASSERT(OnTaskQueue());
@@ -1263,17 +1263,17 @@ MediaDecoderStateMachine::SetDormant(boo
 
   DECODER_LOG("SetDormant=%d", aDormant);
 
   if (aDormant) {
     if (mState == DECODER_STATE_SEEKING) {
       if (mQueuedSeek.Exists()) {
         // Keep latest seek target
       } else if (mCurrentSeek.Exists()) {
-        mQueuedSeek.Steal(mCurrentSeek);
+        mQueuedSeek = Move(mCurrentSeek);
       } else {
         mQueuedSeek.mTarget = SeekTarget(mCurrentPosition,
                                          SeekTarget::Accurate,
                                          MediaDecoderEventVisibility::Suppressed);
         // XXXbholley - Nobody is listening to this promise. Do we need to pass it
         // back to MediaDecoder when we come out of dormant?
         RefPtr<MediaDecoder::SeekPromise> unused = mQueuedSeek.mPromise.Ensure(__func__);
       }
@@ -1371,17 +1371,17 @@ void MediaDecoderStateMachine::StartDeco
       // we have the start time from last time we loaded.
       // FinishDecodeFirstFrame will be launched upon completion of the seek when
       // we have data ready to play.
       MOZ_ASSERT(mQueuedSeek.Exists() && mSentFirstFrameLoadedEvent,
                  "Return from dormant must have queued seek");
     }
     if (mQueuedSeek.Exists()) {
       SetState(DECODER_STATE_SEEKING);
-      InitiateSeek(mQueuedSeek);
+      InitiateSeek(Move(mQueuedSeek));
       return;
     }
   }
 
   mDecodeStartTime = TimeStamp::Now();
 
   CheckIfDecodeComplete();
   if (mState == DECODER_STATE_COMPLETED) {
@@ -1493,17 +1493,17 @@ MediaDecoderStateMachine::Seek(SeekTarge
   }
   mQueuedSeek.RejectIfExists(__func__);
 
   DECODER_LOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
   SetState(DECODER_STATE_SEEKING);
 
   SeekJob seekJob;
   seekJob.mTarget = aTarget;
-  InitiateSeek(seekJob);
+  InitiateSeek(Move(seekJob));
   return mCurrentSeek.mPromise.Ensure(__func__);
 }
 
 RefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::InvokeSeek(SeekTarget aTarget)
 {
   return InvokeAsync(OwnerThread(), this, __func__,
                      &MediaDecoderStateMachine::Seek, aTarget);
@@ -1574,22 +1574,22 @@ MediaDecoderStateMachine::DispatchDecode
                 GetDecodedAudioDuration(),
                 VideoQueue().Duration());
     nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::SetIdle);
     DecodeTaskQueue()->Dispatch(task.forget());
   }
 }
 
 void
-MediaDecoderStateMachine::InitiateSeek(SeekJob& aSeekJob)
+MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   mCurrentSeek.RejectIfExists(__func__);
-  mCurrentSeek.Steal(aSeekJob);
+  mCurrentSeek = Move(aSeekJob);
 
   // Bound the seek time to be inside the media range.
   int64_t end = Duration().ToMicroseconds();
   NS_ASSERTION(end != -1, "Should know end time by now");
   int64_t seekTime = mCurrentSeek.mTarget.GetTime().ToMicroseconds();
   seekTime = std::min(seekTime, end);
   seekTime = std::max(int64_t(0), seekTime);
   NS_ASSERTION(seekTime >= 0 && seekTime <= end,
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -523,22 +523,31 @@ protected:
   // Dispatches a LoadedMetadataEvent.
   // This is threadsafe and can be called on any thread.
   // The decoder monitor must be held.
   void EnqueueLoadedMetadataEvent();
 
   void EnqueueFirstFrameLoadedEvent();
 
   struct SeekJob {
-    void Steal(SeekJob& aOther)
+    SeekJob() {}
+
+    SeekJob(SeekJob&& aOther) : mTarget(aOther.mTarget)
+    {
+      aOther.mTarget.Reset();
+      mPromise = Move(aOther.mPromise);
+    }
+
+    SeekJob& operator=(SeekJob&& aOther)
     {
       MOZ_DIAGNOSTIC_ASSERT(!Exists());
       mTarget = aOther.mTarget;
       aOther.mTarget.Reset();
       mPromise = Move(aOther.mPromise);
+      return *this;
     }
 
     bool Exists()
     {
       MOZ_ASSERT(mTarget.IsValid() == !mPromise.IsEmpty());
       return mTarget.IsValid();
     }
 
@@ -562,17 +571,17 @@ protected:
     }
 
     SeekTarget mTarget;
     MozPromiseHolder<MediaDecoder::SeekPromise> mPromise;
   };
 
   // Clears any previous seeking state and initiates a new see on the decoder.
   // The decoder monitor must be held.
-  void InitiateSeek(SeekJob& aSeekJob);
+  void InitiateSeek(SeekJob aSeekJob);
 
   nsresult DispatchAudioDecodeTaskIfNeeded();
 
   // Ensures a task to decode audio has been dispatched to the decode task queue.
   // If a task to decode has already been dispatched, this does nothing,
   // otherwise this dispatches a task to do the decode.
   // This is called on the state machine or decode threads.
   // The decoder monitor must be held.
--- a/dom/media/fmp4/MP4Decoder.cpp
+++ b/dom/media/fmp4/MP4Decoder.cpp
@@ -175,17 +175,17 @@ MP4Decoder::CanHandleMediaType(const nsA
 
   return CanHandleMediaType(NS_ConvertUTF16toUTF8(mimeType), codecs);
 }
 
 /* static */
 bool
 MP4Decoder::IsEnabled()
 {
-  return Preferences::GetBool("media.mp4.enabled");
+  return Preferences::GetBool("media.mp4.enabled", true);
 }
 
 // sTestH264ExtraData represents the content of the avcC atom found in
 // an AVC1 h264 video. It contains the H264 SPS and PPS NAL.
 // the structure of the avcC atom is as follow:
 // write(0x1);  // version, always 1
 // write(sps[0].data[1]); // profile
 // write(sps[0].data[2]); // compatibility
--- a/dom/media/gtest/MockMediaResource.cpp
+++ b/dom/media/gtest/MockMediaResource.cpp
@@ -5,20 +5,20 @@
 #include "MockMediaResource.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
 
 namespace mozilla
 {
 
-MockMediaResource::MockMediaResource(const char* aFileName)
+MockMediaResource::MockMediaResource(const char* aFileName, const nsACString& aContentType)
   : mFileHandle(nullptr)
   , mFileName(aFileName)
-  , mContentType(NS_LITERAL_CSTRING("video/mp4"))
+  , mContentType(aContentType)
 {
 }
 
 nsresult
 MockMediaResource::Open(nsIStreamListener** aStreamListener)
 {
   mFileHandle = fopen(mFileName, "rb");
   if (mFileHandle == nullptr) {
--- a/dom/media/gtest/MockMediaResource.h
+++ b/dom/media/gtest/MockMediaResource.h
@@ -10,17 +10,17 @@
 #include "mozilla/Atomics.h"
 
 namespace mozilla
 {
 
 class MockMediaResource : public MediaResource
 {
 public:
-  explicit MockMediaResource(const char* aFileName);
+  explicit MockMediaResource(const char* aFileName, const nsACString& aMimeType = NS_LITERAL_CSTRING("video/mp4"));
   nsIURI* URI() const override { return nullptr; }
   nsresult Close() override { return NS_OK; }
   void Suspend(bool aCloseImmediately) override {}
   void Resume() override {}
   already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override
   {
     return nullptr;
   }
@@ -70,14 +70,14 @@ public:
 protected:
   virtual ~MockMediaResource();
 
 private:
   FILE* mFileHandle;
   const char* mFileName;
   MediaByteRangeSet mRanges;
   Atomic<int> mEntry;
-  nsCString mContentType;
+  const nsCString mContentType;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/gtest/TestMP4Demuxer.cpp
+++ b/dom/media/gtest/TestMP4Demuxer.cpp
@@ -14,17 +14,17 @@
 #include "MockMediaResource.h"
 #include "VideoUtils.h"
 
 using namespace mozilla;
 using namespace mp4_demuxer;
 
 class AutoTaskQueue;
 
-#define DO_FAIL []()->void { EXPECT_TRUE(false); }
+#define DO_FAIL [binding]()->void { EXPECT_TRUE(false); binding->mTaskQueue->BeginShutdown(); }
 
 class MP4DemuxerBinding
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MP4DemuxerBinding);
 
   RefPtr<MockMediaResource> resource;
   RefPtr<MP4Demuxer> mDemuxer;
@@ -45,27 +45,28 @@ public:
   {
     EXPECT_EQ(NS_OK, resource->Open(nullptr));
   }
 
   template<typename Function>
   void RunTestAndWait(const Function& aFunction)
   {
     Function func(aFunction);
+    RefPtr<MP4DemuxerBinding> binding = this;
     mDemuxer->Init()->Then(mTaskQueue, __func__, Move(func), DO_FAIL);
     mTaskQueue->AwaitShutdownAndIdle();
   }
 
   RefPtr<GenericPromise>
   CheckTrackKeyFrame(MediaTrackDemuxer* aTrackDemuxer)
   {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
 
     RefPtr<MediaTrackDemuxer> track = aTrackDemuxer;
-    RefPtr<MP4DemuxerBinding> self = this;
+    RefPtr<MP4DemuxerBinding> binding = this;
 
     int64_t time = -1;
     while (mIndex < mSamples.Length()) {
       uint32_t i = mIndex++;
       if (mSamples[i]->mKeyframe) {
         time = mSamples[i]->mTime;
         break;
       }
@@ -75,23 +76,23 @@ public:
 
     if (time == -1) {
       mCheckTrackKeyFramePromise.Resolve(true, __func__);
       return p;
     }
 
 
     DispatchTask(
-      [track, time, self] () {
-        track->Seek(media::TimeUnit::FromMicroseconds(time))->Then(self->mTaskQueue, __func__,
-          [track, time, self] () {
-            track->GetSamples()->Then(self->mTaskQueue, __func__,
-              [track, time, self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
+      [track, time, binding] () {
+        track->Seek(media::TimeUnit::FromMicroseconds(time))->Then(binding->mTaskQueue, __func__,
+          [track, time, binding] () {
+            track->GetSamples()->Then(binding->mTaskQueue, __func__,
+              [track, time, binding] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
                 EXPECT_EQ(time, aSamples->mSamples[0]->mTime);
-                self->CheckTrackKeyFrame(track);
+                binding->CheckTrackKeyFrame(track);
               },
               DO_FAIL
             );
           },
           DO_FAIL
         );
       }
     );
@@ -100,42 +101,42 @@ public:
   }
 
   RefPtr<GenericPromise>
   CheckTrackSamples(MediaTrackDemuxer* aTrackDemuxer)
   {
     MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
 
     RefPtr<MediaTrackDemuxer> track = aTrackDemuxer;
-    RefPtr<MP4DemuxerBinding> self = this;
+    RefPtr<MP4DemuxerBinding> binding = this;
 
     RefPtr<GenericPromise> p = mCheckTrackSamples.Ensure(__func__);
 
     DispatchTask(
-      [track, self] () {
-        track->GetSamples()->Then(self->mTaskQueue, __func__,
-          [track, self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
+      [track, binding] () {
+        track->GetSamples()->Then(binding->mTaskQueue, __func__,
+          [track, binding] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
             if (aSamples->mSamples.Length()) {
-              self->mSamples.AppendElements(aSamples->mSamples);
-              self->CheckTrackSamples(track);
+              binding->mSamples.AppendElements(aSamples->mSamples);
+              binding->CheckTrackSamples(track);
             }
           },
-          [self] (DemuxerFailureReason aReason) {
+          [binding] (DemuxerFailureReason aReason) {
             if (aReason == DemuxerFailureReason::DEMUXER_ERROR) {
               EXPECT_TRUE(false);
-              self->mCheckTrackSamples.Reject(NS_ERROR_FAILURE, __func__);
+              binding->mCheckTrackSamples.Reject(NS_ERROR_FAILURE, __func__);
             } else if (aReason == DemuxerFailureReason::END_OF_STREAM) {
-              EXPECT_TRUE(self->mSamples.Length() > 1);
-              for (uint32_t i = 0; i < (self->mSamples.Length() - 1); i++) {
-                EXPECT_LT(self->mSamples[i]->mTimecode, self->mSamples[i + 1]->mTimecode);
-                if (self->mSamples[i]->mKeyframe) {
-                  self->mKeyFrameTimecodes.AppendElement(self->mSamples[i]->mTimecode);
+              EXPECT_TRUE(binding->mSamples.Length() > 1);
+              for (uint32_t i = 0; i < (binding->mSamples.Length() - 1); i++) {
+                EXPECT_LT(binding->mSamples[i]->mTimecode, binding->mSamples[i + 1]->mTimecode);
+                if (binding->mSamples[i]->mKeyframe) {
+                  binding->mKeyFrameTimecodes.AppendElement(binding->mSamples[i]->mTimecode);
                 }
               }
-              self->mCheckTrackSamples.Resolve(true, __func__);
+              binding->mCheckTrackSamples.Resolve(true, __func__);
             }
           }
         );
       }
     );
 
     return p;
   }
@@ -194,17 +195,17 @@ ToCryptoString(const CryptoSample& aCryp
   } else {
     res.Append("no crypto");
   }
   return res;
 }
 
 #ifndef XP_WIN // VC2013 doesn't support C++11 array initialization.
 
-TEST(MP4Demuxer, CENCFrag)
+TEST(MP4Demuxer, CENCFragVideo)
 {
   const char* video[] = {
     "1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000000 5,684 5,16980",
     "1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000450 5,1826",
     "1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000004c3 5,1215",
     "1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000050f 5,1302",
     "1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000561 5,939",
     "1 16 7e571d037e571d037e571d037e571d03 0000000000000000000000000000059c 5,763",
@@ -275,17 +276,20 @@ TEST(MP4Demuxer, CENCFrag)
           for (uint32_t i = 0; i < binding->mSamples.Length(); i++) {
             nsCString text = ToCryptoString(binding->mSamples[i]->mCrypto);
             EXPECT_STREQ(video[i++], text.get());
           }
           EXPECT_EQ(ArrayLength(video), binding->mSamples.Length());
           binding->mTaskQueue->BeginShutdown();
         }, DO_FAIL);
   });
+}
 
+TEST(MP4Demuxer, CENCFragAudio)
+{
   const char* audio[] = {
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000000 0,281",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000012 0,257",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000023 0,246",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000033 0,257",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000044 0,260",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000055 0,260",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000066 0,272",
@@ -372,31 +376,32 @@ TEST(MP4Demuxer, CENCFrag)
     "1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000083e 0,469",
     "1 16 7e571d047e571d047e571d047e571d04 0000000000000000000000000000085c 0,431",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000877 0,437",
     "1 16 7e571d047e571d047e571d047e571d04 00000000000000000000000000000893 0,474",
     "1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000008b1 0,436",
     "1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000008cd 0,433",
     "1 16 7e571d047e571d047e571d047e571d04 000000000000000000000000000008e9 0,481",
   };
-  RefPtr<MP4DemuxerBinding> audiobinding = new MP4DemuxerBinding("gizmo-frag.mp4");
 
-  audiobinding->RunTestAndWait([audiobinding, audio] () {
+  RefPtr<MP4DemuxerBinding> binding = new MP4DemuxerBinding("gizmo-frag.mp4");
+
+  binding->RunTestAndWait([binding, audio] () {
     // grab all audio samples.
-    audiobinding->mAudioTrack = audiobinding->mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
-    audiobinding->CheckTrackSamples(audiobinding->mAudioTrack)
-      ->Then(audiobinding->mTaskQueue, __func__,
-        [audiobinding, audio] () {
-          EXPECT_TRUE(audiobinding->mSamples.Length() > 1);
-          for (uint32_t i = 0; i < audiobinding->mSamples.Length(); i++) {
-            nsCString text = ToCryptoString(audiobinding->mSamples[i]->mCrypto);
+    binding->mAudioTrack = binding->mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
+    binding->CheckTrackSamples(binding->mAudioTrack)
+      ->Then(binding->mTaskQueue, __func__,
+        [binding, audio] () {
+          EXPECT_TRUE(binding->mSamples.Length() > 1);
+          for (uint32_t i = 0; i < binding->mSamples.Length(); i++) {
+            nsCString text = ToCryptoString(binding->mSamples[i]->mCrypto);
             EXPECT_STREQ(audio[i++], text.get());
           }
-          EXPECT_EQ(ArrayLength(audio), audiobinding->mSamples.Length());
-          audiobinding->mTaskQueue->BeginShutdown();
+          EXPECT_EQ(ArrayLength(audio), binding->mSamples.Length());
+          binding->mTaskQueue->BeginShutdown();
         }, DO_FAIL);
   });
 }
 
 #endif
 
 TEST(MP4Demuxer, GetNextKeyframe)
 {
@@ -440,8 +445,10 @@ TEST(MP4Demuxer, ZeroInLastMoov)
 TEST(MP4Demuxer, ZeroInMoovQuickTime)
 {
   RefPtr<MP4DemuxerBinding> binding = new MP4DemuxerBinding("short-zero-inband.mov");
   binding->RunTestAndWait([binding] () {
     // It demuxes without error. That is sufficient.
     binding->mTaskQueue->BeginShutdown();
   });
 }
+
+#undef DO_FAIL
new file mode 100644
--- /dev/null
+++ b/dom/media/gtest/TestMediaDataDecoder.cpp
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "Benchmark.h"
+#include "MockMediaResource.h"
+#include "DecoderTraits.h"
+#include "MP4Demuxer.h"
+#include "WebMDemuxer.h"
+
+using namespace mozilla;
+
+class BenchmarkRunner
+{
+public:
+  explicit BenchmarkRunner(Benchmark* aBenchmark)
+    : mBenchmark(aBenchmark) {}
+
+  uint32_t Run()
+  {
+    bool done = false;
+    uint32_t result = 0;
+
+    mBenchmark->Init();
+    mBenchmark->Run()->Then(
+      AbstractThread::MainThread(), __func__,
+      [&](uint32_t aDecodeFps) { result = aDecodeFps; done = true; },
+      [&]() { done = true; });
+
+    // Wait until benchmark completes.
+    while (!done) {
+      NS_ProcessNextEvent();
+    }
+    return result;
+  }
+
+private:
+  RefPtr<Benchmark> mBenchmark;
+};
+
+TEST(MediaDataDecoder, H264)
+{
+  if (!DecoderTraits::IsMP4TypeAndEnabled(NS_LITERAL_CSTRING("video/mp4"))) {
+    EXPECT_TRUE(true);
+  } else {
+    RefPtr<MediaResource> resource =
+      new MockMediaResource("gizmo.mp4", NS_LITERAL_CSTRING("video/mp4"));
+    nsresult rv = resource->Open(nullptr);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+    BenchmarkRunner runner(new Benchmark(new MP4Demuxer(resource)));
+    EXPECT_GT(runner.Run(), 0u);
+  }
+}
+
+TEST(MediaDataDecoder, VP9)
+{
+  if (!DecoderTraits::IsWebMTypeAndEnabled(NS_LITERAL_CSTRING("video/webm"))) {
+    EXPECT_TRUE(true);
+  } else {
+    RefPtr<MediaResource> resource =
+      new MockMediaResource("vp9cake.webm", NS_LITERAL_CSTRING("video/webm"));
+    nsresult rv = resource->Open(nullptr);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+    BenchmarkRunner runner(new Benchmark(new WebMDemuxer(resource)));
+    EXPECT_GT(runner.Run(), 0u);
+  }
+}
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -6,16 +6,17 @@
 
 UNIFIED_SOURCES += [
     'MockMediaResource.cpp',
     'TestAudioCompactor.cpp',
     'TestGMPCrossOrigin.cpp',
     'TestGMPRemoveAndDelete.cpp',
     'TestGMPUtils.cpp',
     'TestIntervalSet.cpp',
+    'TestMediaDataDecoder.cpp',
     'TestMediaEventSource.cpp',
     'TestMediaFormatReader.cpp',
     'TestMozPromise.cpp',
     'TestMP3Demuxer.cpp',
     'TestMP4Demuxer.cpp',
     # 'TestMP4Reader.cpp', disabled so we can turn check tests back on (bug 1175752)
     'TestTrackEncoder.cpp',
     'TestVideoSegment.cpp',
@@ -38,16 +39,17 @@ if CONFIG['MOZ_WEBM_ENCODER']:
 if CONFIG['MOZ_RUST']:
     SOURCES += ['hello.rs',]
     UNIFIED_SOURCES += ['TestRust.cpp',]
 
 
 TEST_HARNESS_FILES.gtest += [
     '../test/gizmo-frag.mp4',
     '../test/gizmo.mp4',
+    '../test/vp9cake.webm',
     'dash_dashinit.mp4',
     'id3v2header.mp3',
     'mediasource_test.mp4',
     'noise.mp3',
     'noise_vbr.mp3',
     'short-zero-in-moov.mp4',
     'short-zero-inband.mov',
     'small-shot.mp3',
--- a/dom/media/mediasource/test/mochitest.ini
+++ b/dom/media/mediasource/test/mochitest.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g' # b2g( ReferenceError: MediaSource is not defined)
+subsuite = media
 support-files =
   mediasource.js
   seek.webm seek.webm^headers^
   seek_lowres.webm seek_lowres.webm^headers^
   bipbop/bipbop2s.mp4 bipbop/bipbop2s.mp4^headers^
   bipbop/bipbopinit.mp4 bipbop/bipbop_audioinit.mp4 bipbop/bipbop_videoinit.mp4
   bipbop/bipbop1.m4s bipbop/bipbop_audio1.m4s bipbop/bipbop_video1.m4s
   bipbop/bipbop2.m4s bipbop/bipbop_audio2.m4s bipbop/bipbop_video2.m4s
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -77,41 +77,41 @@ PDMFactory::Init()
   MOZ_ASSERT(NS_IsMainThread());
   static bool alreadyInitialized = false;
   if (alreadyInitialized) {
     return;
   }
   alreadyInitialized = true;
 
   Preferences::AddBoolVarCache(&sUseBlankDecoder,
-                               "media.use-blank-decoder");
+                               "media.use-blank-decoder", false);
 #ifdef MOZ_GONK_MEDIACODEC
   Preferences::AddBoolVarCache(&sGonkDecoderEnabled,
-                               "media.gonk.enabled", false);
+                               "media.gonk.enabled", true);
 #endif
 #ifdef MOZ_WIDGET_ANDROID
   Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled,
                                "media.android-media-codec.enabled", false);
   Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred,
                                "media.android-media-codec.preferred", false);
 #endif
 
   Preferences::AddBoolVarCache(&sGMPDecoderEnabled,
-                               "media.gmp.decoder.enabled", false);
+                               "media.gmp.decoder.enabled", true);
 #ifdef MOZ_FFMPEG
   Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled,
-                               "media.ffmpeg.enabled", false);
+                               "media.ffmpeg.enabled", true);
 #endif
 #ifdef MOZ_FFVPX
   Preferences::AddBoolVarCache(&sFFVPXDecoderEnabled,
-                               "media.ffvpx.enabled", false);
+                               "media.ffvpx.enabled", true);
 #endif
 #ifdef XP_WIN
   Preferences::AddBoolVarCache(&sWMFDecoderEnabled,
-                               "media.wmf.enabled", false);
+                               "media.wmf.enabled", true);
 #endif
 
   Preferences::AddBoolVarCache(&sEnableFuzzingWrapper,
                                "media.decoder.fuzzing.enabled", false);
   Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms,
                                "media.decoder.fuzzing.video-output-minimum-interval-ms", 0);
   Preferences::AddBoolVarCache(&sDontDelayInputExhausted,
                                "media.decoder.fuzzing.dont-delay-inputexhausted", false);
--- a/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
+++ b/dom/media/platforms/ffmpeg/ffvpx/FFVPXRuntimeLinker.cpp
@@ -3,20 +3,23 @@
 /* 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 "FFVPXRuntimeLinker.h"
 #include "FFmpegLibWrapper.h"
 #include "FFmpegLog.h"
 #include "nsIFile.h"
-#include "nsXPCOMPrivate.h" // for XUL_DLL
 #include "prmem.h"
 #include "prlink.h"
 
+// We use a known symbol located in lgpllibs to determine its location.
+// soundtouch happens to be always included in lgpllibs
+#include "soundtouch/SoundTouch.h"
+
 namespace mozilla
 {
 
 template <int V> class FFmpegDecoderModule
 {
 public:
   static already_AddRefed<PlatformDecoderModule> Create(FFmpegLibWrapper*);
 };
@@ -27,33 +30,43 @@ FFVPXRuntimeLinker::LinkStatus FFVPXRunt
   LinkStatus_INIT;
 
 static PRLibrary*
 MozAVLink(const char* aName)
 {
   PRLibSpec lspec;
   lspec.type = PR_LibSpec_Pathname;
   lspec.value.pathname = aName;
-  return PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
+  PRLibrary* lib = PR_LoadLibraryWithFlags(lspec, PR_LD_NOW | PR_LD_LOCAL);
+  if (!lib) {
+    FFMPEG_LOG("unable to load library %s", aName);
+  }
+  return lib;
 }
 
 /* static */ bool
 FFVPXRuntimeLinker::Init()
 {
   if (sLinkStatus) {
     return sLinkStatus == LinkStatus_SUCCEEDED;
   }
 
   MOZ_ASSERT(NS_IsMainThread());
   sLinkStatus = LinkStatus_FAILED;
 
-  // We retrieve the path of the XUL library as this is where mozavcodec and
-  // mozavutil libs are located.
+  // We retrieve the path of the lgpllibs library as this is where mozavcodec
+  // and mozavutil libs are located.
+  char* lgpllibsname = PR_GetLibraryName(nullptr, "lgpllibs");
+  if (!lgpllibsname) {
+    return false;
+  }
   char* path =
-    PR_GetLibraryFilePathname(XUL_DLL, (PRFuncPtr)&FFVPXRuntimeLinker::Init);
+    PR_GetLibraryFilePathname(lgpllibsname,
+                              (PRFuncPtr)&soundtouch::SoundTouch::getVersionId);
+  PR_FreeLibraryName(lgpllibsname);
   if (!path) {
     return false;
   }
   nsCOMPtr<nsIFile> xulFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
   if (!xulFile ||
       NS_FAILED(xulFile->InitWithNativePath(nsDependentCString(path)))) {
     PR_Free(path);
     return false;
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -17,17 +17,18 @@
 # throws an error (and does not cause a crash or hang), just add it to
 # gErrorTests in manifest.js.
 
 # To test for a specific bug in handling a specific resource type, make the
 # test first check canPlayType for the type, and if it's not supported, just
 # do ok(true, "Type not supported") and stop the test.
 
 [DEFAULT]
-skip-if = buildapp == 'mulet' || (os == 'win' && strictContentSandbox) || android_version == '18' # strictContentSandbox (Bug 1042735)
+subsuite = media
+skip-if = buildapp == 'mulet' || android_version == '18'
 support-files =
   16bit_wave_extrametadata.wav
   16bit_wave_extrametadata.wav^headers^
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
   VID_0001.ogg
--- a/dom/media/tests/mochitest/identity/mochitest.ini
+++ b/dom/media/tests/mochitest/identity/mochitest.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
-# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
+# Android 2.3 - bug 981881
 # won't run on b2g desktop tests - bug 1119993
 # broken HTTPS on b2g emulator - bug 1135339
-skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || android_version == '18' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk') || buildapp == 'mulet'
+subsuite = media
+skip-if = android_version == '10' || android_version == '18' || (buildapp == 'b2g' && toolkit != 'gonk') || (buildapp == 'b2g' && toolkit == 'gonk') || buildapp == 'mulet'
 support-files =
   /.well-known/idp-proxy/idp.js
   identityPcTest.js
 tags = msg
 
 [test_idpproxy.html]
 support-files =
   /.well-known/idp-proxy/idp-redirect-http.js
--- a/dom/media/tests/mochitest/ipc/mochitest.ini
+++ b/dom/media/tests/mochitest/ipc/mochitest.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
 tags=msg
+subsuite=media
 support-files =
   ipc.json
 
 skip-if = e10s
 
 [test_ipc.html]
 skip-if =  buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' #bug 910661 # b2g(nested ipc not working) b2g-debug(debug-only failure) b2g-desktop(nested ipc not working)
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,12 +1,14 @@
 [DEFAULT]
-# strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
+# Android 2.3 - bug 981881
 tags = msg webrtc
-skip-if = (os == 'win' && strictContentSandbox) || android_version == '10' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
+<<<<<<< local
+subsuite = media
+skip-if = android_version == '10' || (buildapp == 'mulet') || (toolkit == 'gonk' && debug) # b2g(Either bug 1171118 or bug 1169838, take your pick)
 support-files =
   head.js
   dataChannel.js
   mediaStreamPlayback.js
   network.js
   nonTrickleIce.js
   pc.js
   templates.js
--- a/dom/media/webaudio/test/mochitest.ini
+++ b/dom/media/webaudio/test/mochitest.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 tags=msg
 tags = webaudio
-skip-if = ((buildapp == 'b2g') && (toolkit != 'gonk' || debug)) || (os == 'win' && strictContentSandbox) #b2g-debug,b2g-desktop(bug 916135); strictContentSandbox(Bug 1042735)
+subsuite = media
+skip-if = ((buildapp == 'b2g') && (toolkit != 'gonk' || debug)) #b2g-debug,b2g-desktop(bug 916135)
 support-files =
   audio-expected.wav
   audio-mono-expected-2.wav
   audio-mono-expected.wav
   audio-quad.wav
   audio.ogv
   audioBufferSourceNodeDetached_worker.js
   corsServer.sjs
--- a/dom/media/webspeech/recognition/test/mochitest.ini
+++ b/dom/media/webspeech/recognition/test/mochitest.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 tags=msg
 skip-if = buildapp == 'b2g' || (e10s && debug && os == 'win') # Bug 1191270, bug 1037287, bug 967606, bug 1096400, bug 1238542 etc
+subsuite = media
 support-files =
   head.js
   hello.ogg
   hello.ogg^headers^
   silence.ogg
   silence.ogg^headers^
 [test_abort.html]
 skip-if = toolkit == 'android' # bug 1037287
--- a/dom/media/webspeech/synth/test/mochitest.ini
+++ b/dom/media/webspeech/synth/test/mochitest.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 tags=msg
+subsuite = media
 support-files =
   common.js
   file_bfcache_frame.html
   file_setup.html
   file_speech_queue.html
   file_speech_simple.html
   file_speech_cancel.html
   file_speech_error.html
--- a/dom/messagechannel/MessagePort.cpp
+++ b/dom/messagechannel/MessagePort.cpp
@@ -66,16 +66,20 @@ public:
   NS_IMETHOD
   Run() override
   {
     MOZ_ASSERT(mPort);
     MOZ_ASSERT(mPort->mPostMessageRunnable == this);
 
     nsresult rv = DispatchMessage();
 
+    // We must check if we were waiting for this message in order to shutdown
+    // the port.
+    mPort->UpdateMustKeepAlive();
+
     mPort->mPostMessageRunnable = nullptr;
     mPort->Dispatch();
 
     return rv;
   }
 
   NS_IMETHOD
   Cancel() override
@@ -85,17 +89,16 @@ public:
     return NS_OK;
   }
 
 private:
   nsresult
   DispatchMessage() const
   {
     nsCOMPtr<nsIGlobalObject> globalObject = mPort->GetParentObject();
-    MOZ_ASSERT(globalObject);
 
     AutoJSAPI jsapi;
     if (!globalObject || !jsapi.Init(globalObject)) {
       NS_WARNING("Failed to initialize AutoJSAPI object.");
       return NS_ERROR_FAILURE;
     }
 
     JSContext* cx = jsapi.cx();
@@ -146,19 +149,16 @@ private:
     RefPtr<MessagePortList> portList =
       new MessagePortList(static_cast<dom::Event*>(event.get()),
                           ports);
     event->SetPorts(portList);
 
     bool dummy;
     mPort->DispatchEvent(static_cast<dom::Event*>(event.get()), &dummy);
 
-    // We must check if we were waiting for this message in order to shutdown
-    // the port.
-    mPort->UpdateMustKeepAlive();
     return NS_OK;
   }
 
 private:
   ~PostMessageRunnable()
   {}
 
   RefPtr<MessagePort> mPort;
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -529,17 +529,17 @@ TCPSocket::FireDataStringEvent(const nsA
 
   bool ok = ToJSValue(cx, NS_ConvertASCIItoUTF16(aString), &val);
   if (ok) {
     return FireDataEvent(cx, aType, val);
   }
   return NS_ERROR_FAILURE;
 }
 
-NS_IMETHODIMP
+nsresult
 TCPSocket::FireDataEvent(JSContext* aCx, const nsAString& aType, JS::Handle<JS::Value> aData)
 {
   MOZ_ASSERT(!mSocketBridgeParent);
 
   RootedDictionary<TCPSocketEventInit> init(aCx);
   init.mBubbles = false;
   init.mCancelable = false;
   init.mData = aData;
--- a/dom/network/TCPSocket.h
+++ b/dom/network/TCPSocket.h
@@ -178,16 +178,20 @@ private:
   void ActivateTLS();
   // Dispatch an error event if necessary, then dispatch a "close" event.
   nsresult MaybeReportErrorAndCloseIfOpen(nsresult status);
 #ifdef MOZ_WIDGET_GONK
   // Store and reset any saved network stats for this socket.
   void SaveNetworkStats(bool aEnforce);
 #endif
 
+  // Helper for FireDataStringEvent/FireDataArrayEvent.
+  nsresult FireDataEvent(JSContext* aCx, const nsAString& aType,
+                         JS::Handle<JS::Value> aData);
+
   TCPReadyState mReadyState;
   // Whether to use strings or array buffers for the "data" event.
   bool mUseArrayBuffers;
   nsString mHost;
   uint16_t mPort;
   // Whether this socket is using a secure transport.
   bool mSsl;
 
--- a/dom/network/interfaces/nsITCPSocketCallback.idl
+++ b/dom/network/interfaces/nsITCPSocketCallback.idl
@@ -33,19 +33,16 @@ interface nsITCPSocketCallback : nsISupp
   void fireErrorEvent(in AString name, in AString type);
 
   // Dispatch a "data" event at this object with a string
   void fireDataStringEvent(in DOMString type, in ACString data);
 
   // Dispatch a "data" event at this object with an Array
   void fireDataArrayEvent(in DOMString type, [const] in nsUint8TArrayRef data);
 
-  // Dispatch a "data" event at this object with an ArrayBuffer argument
-  void fireDataEvent(in JSContextPtr cx, in DOMString type, in jsval data);
-
   // Dispatch an event of the given type at this object.
   void fireEvent(in DOMString type);
 
   // Update the DOM object's readyState.
   // @param readyState
   //        new ready state
   void updateReadyState(in unsigned long readystate);
 
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -1044,17 +1044,18 @@ Notification::Constructor(const GlobalOb
   UNWRAP_WORKER_OBJECT(ServiceWorkerGlobalScope, aGlobal.Get(), scope);
   if (scope) {
     aRv.ThrowTypeError<MSG_NOTIFICATION_NO_CONSTRUCTOR_IN_SERVICEWORKER>();
     return nullptr;
   }
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<Notification> notification =
-    CreateAndShow(global, aTitle, aOptions, EmptyString(), aRv);
+    CreateAndShow(aGlobal.Context(), global, aTitle, aOptions,
+                  EmptyString(), aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   // This is be ok since we are on the worker thread where this function will
   // run to completion before the Notification has a chance to go away.
   return notification.forget();
 }
@@ -2587,17 +2588,18 @@ public:
   {
     return mRv;
   }
 
 };
 
 /* static */
 already_AddRefed<Promise>
-Notification::ShowPersistentNotification(nsIGlobalObject *aGlobal,
+Notification::ShowPersistentNotification(JSContext* aCx,
+                                         nsIGlobalObject *aGlobal,
                                          const nsAString& aScope,
                                          const nsAString& aTitle,
                                          const NotificationOptions& aOptions,
                                          ErrorResult& aRv)
 {
   MOZ_ASSERT(aGlobal);
 
   // Validate scope.
@@ -2664,48 +2666,40 @@ Notification::ShowPersistentNotification
   }
 
   // "Otherwise, resolve promise with undefined."
   // The Notification may still not be shown due to other errors, but the spec
   // is not concerned with those.
   p->MaybeResolve(JS::UndefinedHandleValue);
 
   RefPtr<Notification> notification =
-    CreateAndShow(aGlobal, aTitle, aOptions, aScope, aRv);
+    CreateAndShow(aCx, aGlobal, aTitle, aOptions, aScope, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return p.forget();
 }
 
 /* static */ already_AddRefed<Notification>
-Notification::CreateAndShow(nsIGlobalObject* aGlobal,
+Notification::CreateAndShow(JSContext* aCx,
+                            nsIGlobalObject* aGlobal,
                             const nsAString& aTitle,
                             const NotificationOptions& aOptions,
                             const nsAString& aScope,
                             ErrorResult& aRv)
 {
   MOZ_ASSERT(aGlobal);
 
-  AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(aGlobal)))
-  {
-    aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
-    return nullptr;
-  }
-
-  JSContext* cx = jsapi.cx();
-
   RefPtr<Notification> notification = CreateInternal(aGlobal, EmptyString(),
-                                                       aTitle, aOptions);
+                                                     aTitle, aOptions);
 
   // Make a structured clone of the aOptions.mData object
-  JS::Rooted<JS::Value> data(cx, aOptions.mData);
-  notification->InitFromJSVal(cx, data, aRv);
+  JS::Rooted<JS::Value> data(aCx, aOptions.mData);
+  notification->InitFromJSVal(aCx, data, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   notification->SetScope(aScope);
 
   auto ref = MakeUnique<NotificationRef>(notification);
   if (NS_WARN_IF(!ref->Initialized())) {
--- a/dom/notification/Notification.h
+++ b/dom/notification/Notification.h
@@ -254,18 +254,23 @@ public:
 
   static already_AddRefed<Promise> WorkerGet(workers::WorkerPrivate* aWorkerPrivate,
                                              const GetNotificationOptions& aFilter,
                                              const nsAString& aScope,
                                              ErrorResult& aRv);
 
   // Notification implementation of
   // ServiceWorkerRegistration.showNotification.
+  //
+  //
+  // Note that aCx may not be in the compartment of aGlobal, but aOptions will
+  // have its JS things in the compartment of aCx.
   static already_AddRefed<Promise>
-  ShowPersistentNotification(nsIGlobalObject* aGlobal,
+  ShowPersistentNotification(JSContext* aCx,
+                             nsIGlobalObject* aGlobal,
                              const nsAString& aScope,
                              const nsAString& aTitle,
                              const NotificationOptions& aOptions,
                              ErrorResult& aRv);
 
   void Close();
 
   nsPIDOMWindowInner* GetParentObject()
@@ -412,18 +417,22 @@ protected:
 
 private:
   virtual ~Notification();
 
   // Creates a Notification and shows it. Returns a reference to the
   // Notification if result is NS_OK. The lifetime of this Notification is tied
   // to an underlying NotificationRef. Do not hold a non-stack raw pointer to
   // it. Be careful about thread safety if acquiring a strong reference.
+  //
+  // Note that aCx may not be in the compartment of aGlobal, but aOptions will
+  // have its JS things in the compartment of aCx.
   static already_AddRefed<Notification>
-  CreateAndShow(nsIGlobalObject* aGlobal,
+  CreateAndShow(JSContext* aCx,
+                nsIGlobalObject* aGlobal,
                 const nsAString& aTitle,
                 const NotificationOptions& aOptions,
                 const nsAString& aScope,
                 ErrorResult& aRv);
 
   nsIPrincipal* GetPrincipal();
 
   nsresult PersistNotification();
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -635,25 +635,30 @@ nsresult nsPluginHost::FindProxyForURL(c
   if (NS_FAILED(res) || !proxyService)
     return res;
 
   RefPtr<nsProtocolProxyService> rawProxyService = do_QueryObject(proxyService);
   if (!rawProxyService) {
     return NS_ERROR_FAILURE;
   }
 
-  nsCOMPtr<nsIIOService> ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &res);
-  if (NS_FAILED(res) || !ioService)
-    return res;
-
   // make a temporary channel from the argument url
+  nsCOMPtr<nsIURI> uri;
+  res = NS_NewURI(getter_AddRefs(uri), nsDependentCString(url));
+  NS_ENSURE_SUCCESS(res, res);
+
+  nsCOMPtr<nsIPrincipal> nullPrincipal = nsNullPrincipal::Create();
+  NS_ENSURE_TRUE(nullPrincipal, NS_ERROR_FAILURE);
+  // The following channel is never openend, so it does not matter what
+  // securityFlags we pass; let's follow the principle of least privilege.
   nsCOMPtr<nsIChannel> tempChannel;
-  res = ioService->NewChannel(nsDependentCString(url), nullptr, nullptr, getter_AddRefs(tempChannel));
-  if (NS_FAILED(res))
-    return res;
+  res = NS_NewChannel(getter_AddRefs(tempChannel), uri, nullPrincipal,
+                      nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
+                      nsIContentPolicy::TYPE_OTHER);
+  NS_ENSURE_SUCCESS(res, res);
 
   nsCOMPtr<nsIProxyInfo> pi;
 
   // Remove this deprecated call in the future (see Bug 778201):
   res = rawProxyService->DeprecatedBlockingResolve(tempChannel, 0, getter_AddRefs(pi));
   if (NS_FAILED(res))
     return res;
 
--- a/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -120,17 +120,17 @@ skip-if = toolkit != "cocoa"
 [test_src_url_change.html]
 [test_streamNotify.html]
 [test_stringHandling.html]
 [test_streamatclose.html]
 [test_twostreams.html]
 [test_windowed_invalidate.html]
 skip-if = os != "win"
 [test_windowless_flash.html]
-skip-if = !(os == "win" && processor == "x86_64")
+skip-if = !(os == "win" && processor == "x86_64" && !e10s) # Bug 1253957
 [test_windowless_ime.html]
 skip-if = os != "win" || e10s
 [test_visibility.html]
 skip-if = toolkit == "cocoa"
 [test_zero_opacity.html]
 [test_bug1165981.html]
-skip-if = !(os == "win" && processor == "x86_64")
+skip-if = !(os == "win" && processor == "x86_64" && !e10s) # Bug 1253957
 [test_bug1245545.html]
\ No newline at end of file
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -359,17 +359,17 @@ Promise::PromiseCapability::RejectWithEx
   if (mNativePromise) {
     mNativePromise->MaybeRejectInternal(aCx, exn);
     return;
   }
 
   JS::Rooted<JS::Value> ignored(aCx);
   if (!JS::Call(aCx, JS::UndefinedHandleValue, mReject, JS::HandleValueArray(exn),
                 &ignored)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
   }
 }
 
 JS::Value
 Promise::PromiseCapability::PromiseValue() const
 {
   MOZ_ASSERT(mNativePromise || mPromise,
              "NewPromiseCapability didn't succeed");
@@ -532,33 +532,33 @@ Promise::Create(nsIGlobalObject* aGlobal
 already_AddRefed<Promise>
 Promise::Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
                  JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
   JSAutoCompartment ac(aCx, aGlobal->GetGlobalJSObject());
   JS::Rooted<JSObject*> p(aCx,
                           JS::CallOriginalPromiseResolve(aCx, aValue));
   if (!p) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return nullptr;
   }
 
   return CreateFromExisting(aGlobal, p);
 }
 
 // static
 already_AddRefed<Promise>
 Promise::Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
                 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
   JSAutoCompartment ac(aCx, aGlobal->GetGlobalJSObject());
   JS::Rooted<JSObject*> p(aCx,
                           JS::CallOriginalPromiseReject(aCx, aValue));
   if (!p) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return nullptr;
   }
 
   return CreateFromExisting(aGlobal, p);
 }
 
 // static
 already_AddRefed<Promise>
@@ -571,33 +571,33 @@ Promise::All(const GlobalObject& aGlobal
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   JSContext* cx = aGlobal.Context();
 
   JS::AutoObjectVector promises(cx);
   if (!promises.reserve(aPromiseList.Length())) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(cx);
     return nullptr;
   }
 
   for (auto& promise : aPromiseList) {
     JS::Rooted<JSObject*> promiseObj(cx, promise->PromiseObj());
     // Just in case, make sure these are all in the context compartment.
     if (!JS_WrapObject(cx, &promiseObj)) {
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(cx);
       return nullptr;
     }
     promises.infallibleAppend(promiseObj);
   }
 
   JS::Rooted<JSObject*> result(cx, JS::GetWaitForAllPromise(cx, promises));
   if (!result) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(cx);
     return nullptr;
   }
 
   return CreateFromExisting(global, result);
 }
 
 void
 Promise::Then(JSContext* aCx,
@@ -610,43 +610,43 @@ Promise::Then(JSContext* aCx,
 {
   // Let's hope this does the right thing with Xrays...  Ensure everything is
   // just in the caller compartment; that ought to do the trick.  In theory we
   // should consider aCalleeGlobal, but in practice our only caller is
   // DOMRequest::Then, which is not working with a Promise subclass, so things
   // should be OK.
   JS::Rooted<JSObject*> promise(aCx, PromiseObj());
   if (!JS_WrapObject(aCx, &promise)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
 
   JS::Rooted<JSObject*> resolveCallback(aCx);
   if (aResolveCallback) {
     resolveCallback = aResolveCallback->Callback();
     if (!JS_WrapObject(aCx, &resolveCallback)) {
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(aCx);
       return;
     }
   }
 
   JS::Rooted<JSObject*> rejectCallback(aCx);
   if (aRejectCallback) {
     rejectCallback = aRejectCallback->Callback();
     if (!JS_WrapObject(aCx, &rejectCallback)) {
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(aCx);
       return;
     }
   }
 
   JS::Rooted<JSObject*> retval(aCx);
   retval = JS::CallOriginalPromiseThen(aCx, promise, resolveCallback,
                                        rejectCallback);
   if (!retval) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
 
   aRetval.setObject(*retval);
 }
 
 // We need a dummy function to pass to JS::NewPromiseObject.
 static bool
@@ -1126,16 +1126,21 @@ Promise::CallInitFunction(const GlobalOb
     return;
   }
 
   aInit.Call(resolveFunc, rejectFunc, aRv, "promise initializer",
              CallbackObject::eRethrowExceptions, Compartment());
   aRv.WouldReportJSException();
 
   if (aRv.Failed()) {
+    if (aRv.IsUncatchableException()) {
+      // Just propagate this to the caller.
+      return;
+    }
+
     // There are two possibilities here.  Either we've got a rethrown exception,
     // or we reported that already and synthesized a generic NS_ERROR_FAILURE on
     // the ErrorResult.  In the former case, it doesn't much matter how we get
     // the exception JS::Value from the ErrorResult to us, since we'll just end
     // up wrapping it into the right compartment as needed if we hand it to
     // someone.  But in the latter case we have to ensure that the new exception
     // object we create is created in our reflector compartment, not in our
     // current compartment, because in the case when we're a Promise constructor
@@ -1225,23 +1230,23 @@ Promise::NewPromiseCapability(JSContext*
     // be in, though; we'll need it later.
     JS::Rooted<JSObject*> callerGlobal(aCx, JS::CurrentGlobalOrNull(aCx));
     JSAutoCompartment ac(aCx, global);
 
     // Now wrap aConstructor into the compartment of aGlobal, so comparing it to
     // the canonical Promise for that compartment actually makes sense.
     JS::Rooted<JS::Value> constructorValue(aCx, aConstructor);
     if (!MaybeWrapObjectValue(aCx, &constructorValue)) {
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(aCx);
       return;
     }
 
     JSObject* defaultCtor = PromiseBinding::GetConstructorObject(aCx, global);
     if (!defaultCtor) {
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(aCx);
       return;
     }
     if (defaultCtor == &constructorValue.toObject()) {
       // This is the canonical Promise constructor.
       aCapability.mNativePromise = Promise::Create(aGlobal, aRv);
       if (aForceCallbackCreation) {
         // We have to be a bit careful here.  We want to create these functions
         // in the compartment in which they would be created if we actually
@@ -1255,26 +1260,26 @@ Promise::NewPromiseCapability(JSContext*
         MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(&aConstructor.toObject()) ||
                    callerGlobal == global);
         JSAutoCompartment ac2(aCx, callerGlobal);
 
         JSObject* resolveFuncObj =
           CreateFunction(aCx, aCapability.mNativePromise,
                          PromiseCallback::Resolve);
         if (!resolveFuncObj) {
-          aRv.NoteJSContextException();
+          aRv.NoteJSContextException(aCx);
           return;
         }
         aCapability.mResolve.setObject(*resolveFuncObj);
 
         JSObject* rejectFuncObj =
           CreateFunction(aCx, aCapability.mNativePromise,
                          PromiseCallback::Reject);
         if (!rejectFuncObj) {
-          aRv.NoteJSContextException();
+          aRv.NoteJSContextException(aCx);
           return;
         }
         aCapability.mReject.setObject(*rejectFuncObj);
       }
       return;
     }
   }
 
@@ -1302,17 +1307,17 @@ Promise::NewPromiseCapability(JSContext*
 
   // Step 6 and step 7.
   JS::Rooted<JS::Value> getCapabilities(aCx,
                                         JS::ObjectValue(*getCapabilitiesObj));
   JS::Rooted<JSObject*> promiseObj(aCx);
   if (!JS::Construct(aCx, aConstructor,
                      JS::HandleValueArray(getCapabilities),
                      &promiseObj)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
 
   // Step 8 plus copying over the value to the PromiseCapability.
   JS::Rooted<JS::Value> v(aCx);
   v = js::GetFunctionNativeReserved(getCapabilitiesObj,
                                     GET_CAPABILITIES_EXECUTOR_RESOLVE_SLOT);
   if (!v.isObject() || !JS::IsCallable(&v.toObject())) {
@@ -1363,17 +1368,17 @@ Promise::Resolve(const GlobalObject& aGl
   if (aValue.isObject()) {
     JS::Rooted<JSObject*> valueObj(cx, &aValue.toObject());
     Promise* nextPromise;
     nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise);
 
     if (NS_SUCCEEDED(rv)) {
       JS::Rooted<JS::Value> constructor(cx);
       if (!JS_GetProperty(cx, valueObj, "constructor", &constructor)) {
-        aRv.NoteJSContextException();
+        aRv.NoteJSContextException(cx);
         return;
       }
 
       // Cheat instead of calling JS_SameValue, since we know one's an object.
       if (aThisv == constructor) {
         aRetval.setObject(*valueObj);
         return;
       }
@@ -1395,17 +1400,17 @@ Promise::Resolve(const GlobalObject& aGl
     p->mFullfillmentStack = p->mAllocationStack;
   } else {
     JS::Rooted<JS::Value> value(cx, aValue);
     JS::Rooted<JS::Value> ignored(cx);
     if (!JS::Call(cx, JS::UndefinedHandleValue /* thisVal */,
                   capability.mResolve, JS::HandleValueArray(value),
                   &ignored)) {
       // Step 7.
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(cx);
       return;
     }
   }
 
   // Step 8.
   aRetval.set(capability.PromiseValue());
 }
 
@@ -1460,17 +1465,17 @@ Promise::Reject(const GlobalObject& aGlo
     p->mRejectionStack = p->mAllocationStack;
   } else {
     JS::Rooted<JS::Value> value(cx, aValue);
     JS::Rooted<JS::Value> ignored(cx);
     if (!JS::Call(cx, JS::UndefinedHandleValue /* thisVal */,
                   capability.mReject, JS::HandleValueArray(value),
                   &ignored)) {
       // Step 6.
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(cx);
       return;
     }
   }
 
   // Step 7.
   aRetval.set(capability.PromiseValue());
 }
 
@@ -1500,17 +1505,17 @@ SpeciesConstructor(JSContext* aCx,
 
   // Step 1.
   MOZ_ASSERT(promise);
 
   // Step 2.
   JS::Rooted<JS::Value> constructorVal(aCx);
   if (!JS_GetProperty(aCx, promise, "constructor", &constructorVal)) {
     // Step 3.
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
 
   // Step 4.
   if (constructorVal.isUndefined()) {
     ctor.set(defaultCtor);
     return;
   }
@@ -1523,17 +1528,17 @@ SpeciesConstructor(JSContext* aCx,
 
   // Step 6.
   JS::Rooted<jsid> species(aCx,
     SYMBOL_TO_JSID(JS::GetWellKnownSymbol(aCx, JS::SymbolCode::species)));
   JS::Rooted<JS::Value> speciesVal(aCx);
   JS::Rooted<JSObject*> constructorObj(aCx, &constructorVal.toObject());
   if (!JS_GetPropertyById(aCx, constructorObj, species, &speciesVal)) {
     // Step 7.
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
 
   // Step 8.
   if (speciesVal.isNullOrUndefined()) {
     ctor.set(defaultCtor);
     return;
   }
@@ -1555,17 +1560,17 @@ Promise::Then(JSContext* aCx, JS::Handle
               JS::MutableHandle<JS::Value> aRetval, ErrorResult& aRv)
 {
   // Implements
   // http://www.ecma-international.org/ecma-262/6.0/#sec-promise.prototype.then
 
   // Step 1.
   JS::Rooted<JS::Value> promiseVal(aCx, JS::ObjectValue(*GetWrapper()));
   if (!MaybeWrapObjectValue(aCx, &promiseVal)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
   JS::Rooted<JSObject*> promiseObj(aCx, &promiseVal.toObject());
   MOZ_ASSERT(promiseObj);
 
   // Step 2 was done by the bindings.
 
   // Step 3.  We want to use aCalleeGlobal here because it will do the
@@ -1573,37 +1578,37 @@ Promise::Then(JSContext* aCx, JS::Handle
   // our promise constructor for now).
   JS::Rooted<JSObject*> calleeGlobal(aCx, aCalleeGlobal);
   JS::Rooted<JS::Value> defaultCtorVal(aCx);
   { // Scope for JSAutoCompartment
     JSAutoCompartment ac(aCx, aCalleeGlobal);
     JSObject* defaultCtor =
       PromiseBinding::GetConstructorObject(aCx, calleeGlobal);
     if (!defaultCtor) {
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(aCx);
       return;
     }
     defaultCtorVal.setObject(*defaultCtor);
   }
   if (!MaybeWrapObjectValue(aCx, &defaultCtorVal)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
 
   JS::Rooted<JS::Value> constructor(aCx);
   SpeciesConstructor(aCx, promiseObj, defaultCtorVal, &constructor, aRv);
   if (aRv.Failed()) {
     // Step 4.
     return;
   }
 
   // Step 5.
   GlobalObject globalObj(aCx, GetWrapper());
   if (globalObj.Failed()) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
   nsCOMPtr<nsIGlobalObject> globalObject =
     do_QueryInterface(globalObj.GetAsSupports());
   if (!globalObject) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
@@ -1692,35 +1697,35 @@ Promise::Catch(JSContext* aCx, AnyCallba
 {
   // Implements
   // http://www.ecma-international.org/ecma-262/6.0/#sec-promise.prototype.catch
 
   // We can't call Promise::Then directly, because someone might have
   // overridden Promise.prototype.then.
   JS::Rooted<JS::Value> promiseVal(aCx, JS::ObjectValue(*GetWrapper()));
   if (!MaybeWrapObjectValue(aCx, &promiseVal)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
     return;
   }
   JS::Rooted<JSObject*> promiseObj(aCx, &promiseVal.toObject());
   MOZ_ASSERT(promiseObj);
   JS::AutoValueArray<2> callbacks(aCx);
   callbacks[0].setUndefined();
   if (aRejectCallback) {
     callbacks[1].setObject(*aRejectCallback->Callable());
     // It could be in any compartment, so put it in ours.
     if (!MaybeWrapObjectValue(aCx, callbacks[1])) {
-      aRv.NoteJSContextException();
+      aRv.NoteJSContextException(aCx);
       return;
     }
   } else {
     callbacks[1].setNull();
   }
   if (!JS_CallFunctionName(aCx, promiseObj, "then", callbacks, aRetval)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(aCx);
   }
 }
 
 /**
  * The CountdownHolder class encapsulates Promise.all countdown functions and
  * the countdown holder parts of the Promises spec. It maintains the result
  * array and AllResolveElementFunctions use SetValue() to set the array indices.
  */
@@ -1970,17 +1975,17 @@ Promise::All(const GlobalObject& aGlobal
   MOZ_ASSERT(aThisv.isObject(), "How did NewPromiseCapability succeed?");
   JS::Rooted<JSObject*> constructorObj(cx, &aThisv.toObject());
 
   // After this point we have a useful promise value in "capability", so just go
   // ahead and put it in our retval now.  Every single return path below would
   // want to do that anyway.
   aRetval.set(capability.PromiseValue());
   if (!MaybeWrapValue(cx, aRetval)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(cx);
     return;
   }
 
   // The arguments we're going to be passing to "then" on each loop iteration.
   // The second one we know already; the first one will be created on each
   // iteration of the loop.
   JS::AutoValueArray<2> callbackFunctions(cx);
   callbackFunctions[1].set(capability.mReject);
@@ -2257,17 +2262,17 @@ Promise::Race(const GlobalObject& aGloba
   MOZ_ASSERT(aThisv.isObject(), "How did NewPromiseCapability succeed?");
   JS::Rooted<JSObject*> constructorObj(cx, &aThisv.toObject());
 
   // After this point we have a useful promise value in "capability", so just go
   // ahead and put it in our retval now.  Every single return path below would
   // want to do that anyway.
   aRetval.set(capability.PromiseValue());
   if (!MaybeWrapValue(cx, aRetval)) {
-    aRv.NoteJSContextException();
+    aRv.NoteJSContextException(cx);
     return;
   }
 
   // The arguments we're going to be passing to "then" on each loop iteration.
   JS::AutoValueArray<2> callbackFunctions(cx);
   callbackFunctions[0].set(capability.mResolve);
   callbackFunctions[1].set(capability.mReject);
 
--- a/dom/promise/PromiseCallback.cpp
+++ b/dom/promise/PromiseCallback.cpp
@@ -336,16 +336,21 @@ WrapperPromiseCallback::Call(JSContext* 
   mCallback->Call(value, &retValue, rv, "promise callback",
                   CallbackObject::eRethrowExceptions,
                   compartment);
 
   rv.WouldReportJSException();
 
   // PromiseReactionTask step 7
   if (rv.Failed()) {
+    if (rv.IsUncatchableException()) {
+      // We have nothing to resolve/reject the promise with.
+      return rv.StealNSResult();
+    }
+
     JS::Rooted<JS::Value> value(aCx);
     { // Scope for JSAutoCompartment
       // Convert the ErrorResult to a JS exception object that we can reject
       // ourselves with.  This will be exactly the exception that would get
       // thrown from a binding method whose ErrorResult ended up with whatever
       // is on "rv" right now.  Do this in the promise reflector compartment.
       Maybe<JSAutoCompartment> ac;
       if (mNextPromise) {
--- a/dom/promise/tests/mochitest.ini
+++ b/dom/promise/tests/mochitest.ini
@@ -1,15 +1,19 @@
 [DEFAULT]
 # Support files for chrome tests that we want to load over HTTP need
 # to go in here, not chrome.ini, apparently.
-support-files = file_promise_xrays.html
+support-files =
+  file_promise_xrays.html
+  promise_uncatchable_exception.js
 
 [test_bug883683.html]
 [test_promise.html]
+[test_promise_uncatchable_exception.html]
+skip-if = debug == false
 [test_promise_utils.html]
 [test_resolve.html]
 [test_resolver_return_value.html]
 [test_thenable_vs_promise_ordering.html]
 [test_promise_and_timeout_ordering.html]
 support-files = file_promise_and_timeout_ordering.js
 [test_promise_and_timeout_ordering_workers.html]
 support-files = file_promise_and_timeout_ordering.js
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/promise_uncatchable_exception.js
@@ -0,0 +1,9 @@
+postMessage("Done", "*");
+
+var p = new Promise(function(resolve, reject) {
+  TestFunctions.throwUncatchableException();
+  ok(false, "Shouldn't get here!");
+}).catch(function(exception) {
+  ok(false, "Shouldn't get here!");
+});
+ok(false, "Shouldn't get here!");
new file mode 100644
--- /dev/null
+++ b/dom/promise/tests/test_promise_uncatchable_exception.html
@@ -0,0 +1,35 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Promise - uncatchable exceptions</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+onmessage = function(evt) {
+  ok(true, "finished");
+  SimpleTest.finish();
+}
+
+function go() {
+  var script = document.createElement("script");
+  script.src = "promise_uncatchable_exception.js";
+  document.body.appendChild(script);
+}
+
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({set: [['dom.expose_test_interfaces', true]]}, go);
+</script>
+</pre>
+</body>
+</html>
--- a/dom/security/test/mixedcontentblocker/file_main_bug803225.html
+++ b/dom/security/test/mixedcontentblocker/file_main_bug803225.html
@@ -101,26 +101,29 @@ https://bugzilla.mozilla.org/show_bug.cg
     parent.postMessage({"test": "data_protocol", "msg": "resource with data protocol loaded"}, "http://mochi.test:8888");
   }
   newscript.onerror = function() {
     parent.postMessage({"test": "data_protocol", "msg": "resource with data protocol did not load"}, "http://mochi.test:8888");
   }
   testContent.appendChild(newscript);
 
   // Test 7: mailto protocol
-  var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"].
-     getService(SpecialPowers.Ci.nsIIOService);
+  SpecialPowers.loadChromeScript(function launchHandler() {
+    var { classes: Cc, interfaces: Ci } = Components;
+    var ioService = Cc["@mozilla.org/network/io-service;1"].
+                      getService(Ci.nsIIOService);
 
-  var webHandler = SpecialPowers.Cc["@mozilla.org/uriloader/web-handler-app;1"].
-                   createInstance(SpecialPowers.Ci.nsIWebHandlerApp);
-  webHandler.name = "Web Handler";
-  webHandler.uriTemplate = "http://example.com/tests/dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html?s=%";
+    var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
+                       createInstance(Ci.nsIWebHandlerApp);
+    webHandler.name = "Web Handler";
+    webHandler.uriTemplate = "http://example.com/tests/dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html?s=%";
 
-  var uri = ioService.newURI("mailto:foo@bar.com", null, null);
-  webHandler.launchWithURI(uri);
+    var uri = ioService.newURI("mailto:foo@bar.com", null, null);
+    webHandler.launchWithURI(uri);
+  });
 
   var mailto = false;
 
   // listen for a messages from a new window
   var os = SpecialPowers.Cc["@mozilla.org/observer-service;1"].
      getService(SpecialPowers.Components.interfaces.nsIObserverService);
   var observer = {
     observe: function(subject, topic, data) {
--- a/dom/security/test/mixedcontentblocker/mochitest.ini
+++ b/dom/security/test/mixedcontentblocker/mochitest.ini
@@ -11,11 +11,11 @@ support-files =
   file_main.html
   file_main_bug803225.html
   file_main_bug803225_websocket_wsh.py
   file_server.sjs
 
 [test_main.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT, SSL_REQUIRED # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_bug803225.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #TIMED_OUT, SSL_REQUIRED # Bug 1141029 Mulet parity with B2G Desktop for TC
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT, SSL_REQUIRED # Bug 1141029 Mulet parity with B2G Desktop for TC
 [test_frameNavigation.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT, SSL_REQUIRED # Bug 1141029 Mulet parity with B2G Desktop for TC
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -925,21 +925,18 @@ bool DefineOSFileConstants(JSContext *cx
   JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(64));
 #else
   JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(32));
 #endif //defined (HAVE_64BIT_BUILD)
   if (!JS_SetProperty(cx, objSys, "bits", valBits)) {
     return false;
   }
 
-  dom::ConstantSpec umask_cs[] = {
-    { "umask", JS::NumberValue(gUserUmask) },
-    PROP_END
-  };
-  if (!dom::DefineConstants(cx, objSys, umask_cs)) {
+  if (!JS_DefineProperty(cx, objSys, "umask", gUserUmask,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
       return false;
   }
 
   // Build OS.Constants.Path
 
   JS::Rooted<JSObject*> objPath(cx);
   if (!(objPath = GetOrCreateObjectProperty(cx, objConstants, "Path"))) {
     return false;
--- a/dom/tests/mochitest/gamepad/gamepad_frame_state.html
+++ b/dom/tests/mochitest/gamepad/gamepad_frame_state.html
@@ -3,14 +3,14 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>frame</title>
   <script type="text/javascript">
     var gamepad;
     window.addEventListener("gamepadconnected", function(e) {
       gamepad = e.gamepad;
-});
+    });
   </script>
 </head>
 <body>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/gamepad/gamepad_service_test_chrome_script.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+const { Services } = Cu.import('resource://gre/modules/Services.jsm');
+
+var GamepadService = (function() {
+  return Cc["@mozilla.org/gamepad-test;1"].getService(Ci.nsIGamepadServiceTest);
+})();
+
+
+addMessageListener('add-gamepad', function(message) {
+  var index = GamepadService.addGamepad(message.name,
+                                        message.mapping,
+                                        message.buttons,
+                                        message.axes);
+  sendAsyncMessage('new-gamepad-index', index);
+});
+
+addMessageListener('new-button-event', function(message) {
+  GamepadService.newButtonEvent(message.index,
+                                message.button,
+                                message.status);
+});
+
+addMessageListener('new-button-value-event', function(message) {
+  GamepadService.newButtonValueEvent(message.index,
+                                     message.button,
+                                     message.status,
+                                     message.value);
+});
+
+addMessageListener('remove-gamepad', function(message) {
+  GamepadService.removeGamepad(message.index);
+});
+
--- a/dom/tests/mochitest/gamepad/mochitest.ini
+++ b/dom/tests/mochitest/gamepad/mochitest.ini
@@ -1,13 +1,14 @@
 [DEFAULT]
-skip-if=e10s || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
+skip-if=(buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 support-files =
   gamepad_frame.html
   gamepad_frame_state.html
   mock_gamepad.js
+  gamepad_service_test_chrome_script.js
 
 [test_check_timestamp.html]
 [test_gamepad.html]
 [test_gamepad_connect_events.html]
 [test_gamepad_frame_state_sync.html]
 [test_gamepad_hidden_frame.html]
 [test_navigator_gamepads.html]
--- a/dom/tests/mochitest/gamepad/mock_gamepad.js
+++ b/dom/tests/mochitest/gamepad/mock_gamepad.js
@@ -1,5 +1,71 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
-var GamepadService = (function() {
-  return SpecialPowers.Cc["@mozilla.org/gamepad-test;1"].getService(SpecialPowers.Ci.nsIGamepadServiceTest);
-})();
+
+// Determine whether this process is a parent or child process.
+let appInfo = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"];
+let isParentProcess =
+      !appInfo || appInfo.getService(SpecialPowers.Ci.nsIXULRuntime)
+  .processType == SpecialPowers.Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+
+var GamepadService;
+var GamepadScript;
+
+// sendAsyncMessage fails when running in process, so if we're not e10s, just
+// use GamepadServiceTest directly.
+if (isParentProcess) {
+  GamepadService = SpecialPowers.Cc["@mozilla.org/gamepad-test;1"].getService(SpecialPowers.Ci.nsIGamepadServiceTest);
+} else {
+  // If we're e10s, use the proxy script to access GamepadServiceTest in the
+  // parent process.
+  let url = SimpleTest.getTestFileURL("gamepad_service_test_chrome_script.js");
+  GamepadScript = SpecialPowers.loadChromeScript(url);
+
+  GamepadService = {
+    addGamepad: function (name, mapping, buttons, axes) {
+      GamepadScript.sendAsyncMessage("add-gamepad", {
+        name: name,
+        mapping: mapping,
+        buttons: buttons,
+        axes: axes
+      });
+    },
+    newButtonEvent: function (index, button, status) {
+      GamepadScript.sendAsyncMessage("new-button-event", {
+        index: index,
+        button: button,
+        status: status
+      });
+    },
+    newButtonValueEvent: function (index, button, status, value) {
+      GamepadScript.sendAsyncMessage("new-button-value-event", {
+        index: index,
+        button: button,
+        status: status,
+        value: value
+      });
+    },
+    removeGamepad: function (index) {
+      GamepadScript.sendAsyncMessage("remove-gamepad", {
+        index: index
+      });
+    },
+    finish: function () {
+      GamepadScript.destroy();
+    }
+  };
+}
+
+var addGamepad = function(name, mapping, buttons, axes) {
+  return new Promise((resolve, reject) => {
+    if (isParentProcess) {
+      resolve(GamepadService.addGamepad(name, mapping, buttons, axes));
+    } else {
+      var listener = (index) => {
+        GamepadScript.removeMessageListener('new-gamepad-index', listener);
+        resolve(index);
+      };
+      GamepadScript.addMessageListener('new-gamepad-index', listener);
+      GamepadService.addGamepad(name, mapping, buttons, axes);
+    }
+  });
+}
--- a/dom/tests/mochitest/gamepad/test_check_timestamp.html
+++ b/dom/tests/mochitest/gamepad/test_check_timestamp.html
@@ -7,46 +7,53 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <script type="text/javascript" src="mock_gamepad.js"></script>
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
-var index = GamepadService.addGamepad("test gamepad", // id
-                                      SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
-                                      4, // buttons
-                                      2);// axes
+var index;
+addGamepad("test gamepad 1", // id
+           SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
+           4, // buttons
+           2).then(function(i) {
+             index = i;
+             // Press a button to make the gamepad visible to the page.
+             GamepadService.newButtonEvent(index, 0, true);
+             GamepadService.newButtonEvent(index, 0, true);
+           });
 
 var timea=0;
 window.addEventListener("gamepadbuttondown", buttonpresshandler);
 
 var firstPress = true;
-GamepadService.newButtonEvent(index, 0, true);
-GamepadService.newButtonEvent(index, 0, true);
+var testOver = false;
 
 function cleanup(){
   SpecialPowers.executeSoon(function() {
     GamepadService.removeGamepad(index);
     SimpleTest.finish();
   });
 }
 
 function buttonpresshandler(e) {
-  if(timea == 0){
-    timea = e.gamepad.timestamp;
+  if (testOver) {
+    return;
   }
-  else{
-    ok(timea <= e.gamepad.timestamp);
+  if (timea == 0){
+    timea = e.gamepad.timestamp;
+  } else {
+    ok(timea <= e.gamepad.timestamp, "Timestamp less than last timestamp");
   }
   GamepadService.newButtonEvent(index, 0, false);
   if (!firstPress) {
+    testOver = true;
     SpecialPowers.executeSoon(cleanup);
-  }
-  else {
+  } else {
     firstPress = false;
   }
 }
 
 </script>
 </body>
 </html>
--- a/dom/tests/mochitest/gamepad/test_gamepad.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad.html
@@ -6,42 +6,48 @@
   <title>Test gamepad</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <script type="text/javascript" src="mock_gamepad.js"></script>
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
+// Due to gamepad being a polling API instead of event driven, test ordering
+// ends up being a little weird in order to deal with e10s. Calls to
+// GamepadService are async across processes, so we'll need to make sure
+// we account for timing before checking values.
 window.addEventListener("gamepadconnected", connecthandler);
+var index;
 // Add a gamepad
-var index = GamepadService.addGamepad("test gamepad", // id
-                                      SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING,
-                                      4, // buttons
-                                      2);// axes
-GamepadService.newButtonEvent(index, 0, true);
+addGamepad("test gamepad", // id
+           SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING,
+           4,
+           2).then(function(i) {
+             index = i;
+             // Simulate button events on the gamepad we added
+             GamepadService.newButtonEvent(index, 0, true);
+             GamepadService.newButtonValueEvent(index, 1, true, 0.5);
+           });
+
 function connecthandler(e) {
   ok(e.gamepad.timestamp <= performance.now(),
      "gamepad.timestamp should less than or equal to performance.now()");
   is(e.gamepad.index, 0, "correct gamepad index");
   is(e.gamepad.id, "test gamepad", "correct gamepad name");
   is(e.gamepad.mapping, "standard", "standard mapping");
   is(e.gamepad.buttons.length, 4, "correct number of buttons");
   is(e.gamepad.axes.length, 2, "correct number of axes");
-  // Press a button
-  GamepadService.newButtonEvent(index, 0, true);
-  gamepads = navigator.getGamepads();
-  is(gamepads[0].buttons[0].pressed, true, "gamepad button should register as pressed")
-  GamepadService.newButtonValueEvent(index, 1, true, 0.5);
-  gamepads = navigator.getGamepads();
-  is(gamepads[0].buttons[1].pressed, true, "gamepad button should register as pressed")
-  is(gamepads[0].buttons[1].value, 0.5, "gamepad button value should be 0.5")
-
+  // Execute button event tests later, since we need to make sure button
+  // event updates executed on the parent process first.
   SimpleTest.executeSoon(function() {
+    gamepads = navigator.getGamepads();
+    is(gamepads[0].buttons[0].pressed, true, "gamepad button should register as pressed");
+    is(gamepads[0].buttons[1].pressed, true, "gamepad button should register as pressed");
+    is(gamepads[0].buttons[1].value, 0.5, "gamepad button value should be 0.5");
     GamepadService.removeGamepad(index);
     SimpleTest.finish();
   });
 }
-
 </script>
 </body>
 </html>
 
--- a/dom/tests/mochitest/gamepad/test_gamepad_connect_events.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad_connect_events.html
@@ -9,28 +9,37 @@
   <title>Test hidden frames</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <script type="text/javascript" src="mock_gamepad.js"></script>
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
-var index = GamepadService.addGamepad("test gamepad", // id
-                                      SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
-                                      4, // buttons
-                                      2);// axes
+
+var gamepad_index;
 
 function pressButton() {
-  GamepadService.newButtonEvent(index, 0, true);
-  GamepadService.newButtonEvent(index, 0, false);
+  GamepadService.newButtonEvent(gamepad_index, 0, true);
+  GamepadService.newButtonEvent(gamepad_index, 0, false);
+}
+
+ // Add a gamepad
+function startTests() {
+   addGamepad("test gamepad", // id
+              SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING,
+              4, // buttons
+              2).then(function(i) {
+                gamepad_index = i;
+                gamepad_connected()
+              });
 }
 
 var f1, f2;
-function frame_loaded() {
+function gamepad_connected() {
   f1 = document.getElementById('f1');
   pressButton();
 }
 
 window.addEventListener("gamepadbuttondown", function() {
   // Wait to ensure that all frames received the button press as well.
   SpecialPowers.executeSoon(tests[testNum++]);
 });
@@ -52,16 +61,16 @@ function test1() {
   });
   f2.src = "gamepad_frame.html";
   document.body.appendChild(f2);
 }
 
 function test2() {
   is(f1.contentWindow.connectedEvents, 1, "right number of connection events in frame 1");
   is(f2.contentWindow.connectedEvents, 1, "right number of connection events in frame 2");
-  GamepadService.removeGamepad(index);
+  GamepadService.removeGamepad(gamepad_index);
   SimpleTest.finish();
 }
 
 </script>
-<iframe id="f1" src="gamepad_frame.html" onload="frame_loaded()"></iframe>
+<iframe id="f1" src="gamepad_frame.html" onload="startTests()"></iframe>
 </body>
 </html>
--- a/dom/tests/mochitest/gamepad/test_gamepad_frame_state_sync.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad_frame_state_sync.html
@@ -6,37 +6,44 @@
   <title>Test hidden frames</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <script type="text/javascript" src="mock_gamepad.js"></script>
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
-var index = GamepadService.addGamepad("test gamepad", // id
-                                      SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
-                                      4, // buttons
-                                      2);// axes
+ // Add a gamepad
+var index;
 
 function setFrameVisible(f, visible) {
   var Ci = SpecialPowers.Ci;
   var docshell = SpecialPowers.wrap(f.contentWindow).QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShell);
   docshell.isActive = visible;
 }
 
 var frames_loaded = 0;
-var f1, f2;
-function frame_loaded() {
+function startTest() {
   frames_loaded++;
   if (frames_loaded == 2) {
-    f1 = document.getElementById('f1');
-    f2 = document.getElementById('f2');
-    // Now press the button, but don't release it.
-    GamepadService.newButtonEvent(index, 0, true);
- }
+    addGamepad("test gamepad", // id
+               SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING,
+               4, // buttons
+               2).then(function(i) {
+                 index = i;
+                 gamepad_loaded();
+               });
+  }
+}
+var f1, f2;
+function gamepad_loaded() {
+  f1 = document.getElementById('f1');
+  f2 = document.getElementById('f2');
+  // Now press the button, but don't release it.
+  GamepadService.newButtonEvent(index, 0, true);
 }
 
 window.addEventListener("gamepadbuttondown", function() {
   // Wait to ensure that all frames received the button press as well.
  SpecialPowers.executeSoon(tests[testNum++]);
 });
 
 var testNum = 0;
@@ -47,20 +54,24 @@ var tests = [
 
 function check_button_pressed() {
   // At this point the both frames should see the button as pressed.
   ok(f1.contentWindow.gamepad.buttons[0].pressed, "frame 1 sees button pressed");
   ok(f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 sees button pressed");
 
   // Now release the button, then hide the second frame.
   GamepadService.newButtonEvent(index, 0, false);
-  setFrameVisible(f2, false);
   SpecialPowers.executeSoon(function() {
     // Now press the button, but don't release it.
-    GamepadService.newButtonEvent(index, 0, true);
+    ok(!f1.contentWindow.gamepad.buttons[0].pressed, "frame 1 no button pressed");
+    ok(!f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 no button pressed");
+    setFrameVisible(f2, false);
+    SpecialPowers.executeSoon(function() {
+      GamepadService.newButtonEvent(index, 0, true);
+    });
   });
 }
 
 function check_second_frame_no_button_press () {
   /*
    * At this point the first frame should see the button as pressed,
    * but the second frame should not, since it's hidden.
    */
@@ -75,12 +86,12 @@ function check_second_frame_no_button_pr
     ok(f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 sees button pressed");
     // cleanup
     GamepadService.removeGamepad(index);
     SimpleTest.finish();
   });
 }
 
 </script>
-<iframe id="f1" src="gamepad_frame_state.html" onload="frame_loaded()"></iframe>
-<iframe id="f2" src="gamepad_frame_state.html" onload="frame_loaded()"></iframe>
+<iframe id="f1" src="gamepad_frame_state.html" onload="startTest()"></iframe>
+<iframe id="f2" src="gamepad_frame_state.html" onload="startTest()"></iframe>
 </body>
 </html>
--- a/dom/tests/mochitest/gamepad/test_gamepad_hidden_frame.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad_hidden_frame.html
@@ -6,42 +6,47 @@
   <title>Test hidden frames</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <script type="text/javascript" src="mock_gamepad.js"></script>
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
-var index = GamepadService.addGamepad("test gamepad", // id
-                                      SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
-                                      4, // buttons
-                                      2);// axes
 
 function pressButton() {
   GamepadService.newButtonEvent(index, 0, true);
   GamepadService.newButtonEvent(index, 0, false);
 }
 
 function setFrameVisible(f, visible) {
   var Ci = SpecialPowers.Ci;
   var docshell = SpecialPowers.wrap(f.contentWindow).QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation).QueryInterface(Ci.nsIDocShell);
   docshell.isActive = visible;
 }
 
 var frames_loaded = 0;
-var f1, f2;
-function frame_loaded() {
+function startTest() {
   frames_loaded++;
- if (frames_loaded == 2) {
-    f1 = document.getElementById('f1');
-    f2 = document.getElementById('f2');
-    pressButton();
+   if (frames_loaded == 2) {
+    addGamepad("test gamepad", // id
+               SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING,
+               4, // buttons
+               2).then(function(i) {
+                 index = i;
+                 gamepad_loaded();
+               });
   }
 }
+var f1, f2;
+function gamepad_loaded() {
+  f1 = document.getElementById('f1');
+  f2 = document.getElementById('f2');
+  pressButton();
+}
 
 window.addEventListener("gamepadbuttondown", function() {
   // Wait to ensure that all frames received the button press as well.
  SpecialPowers.executeSoon(tests[testNum++]);
 });
 
 var testNum = 0;
 var tests = [
@@ -61,12 +66,12 @@ function test1() {
 function test2() {
   is(f1.contentWindow.buttonPresses, 2, "right number of button presses in frame 1");
   is(f2.contentWindow.buttonPresses, 1, "right number of button presses in frame 2");
   GamepadService.removeGamepad(index);
   SimpleTest.finish();
 }
 
 </script>
-<iframe id="f1" src="gamepad_frame.html" onload="frame_loaded()"></iframe>
-<iframe id="f2" src="gamepad_frame.html" onload="frame_loaded()"></iframe>
+<iframe id="f1" src="gamepad_frame.html" onload="startTest()"></iframe>
+<iframe id="f2" src="gamepad_frame.html" onload="startTest()"></iframe>
 </body>
 </html>
--- a/dom/tests/mochitest/gamepad/test_navigator_gamepads.html
+++ b/dom/tests/mochitest/gamepad/test_navigator_gamepads.html
@@ -22,55 +22,60 @@ var tests = [
 
 function run_next_test(event) {
   SpecialPowers.executeSoon(function() { tests[testNum++](event); });
 }
 
 // gamepads should be empty first
 is(navigator.getGamepads().length, 0, "should be zero gamepads exposed");
 
-function connecthandler(e) {
+function buttonhandler(e) {
  run_next_test(e);
 }
 
 function disconnecthandler(e) {
   run_next_test(e);
 }
-window.addEventListener("gamepadconnected", connecthandler);
+window.addEventListener("gamepadbuttondown", buttonhandler);
 window.addEventListener("gamepaddisconnected", disconnecthandler);
 // Add a gamepad
-var internal_index1 = GamepadService.addGamepad("test gamepad 1", // id
-                                       SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
-                                       4, // buttons
-                                       2);// axes
+addGamepad("test gamepad 1", // id
+           SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
+           4, // buttons
+           2).then(function(index) {
+             internal_index1 = index;
+             // Press a button to make the gamepad visible to the page.
+             GamepadService.newButtonEvent(internal_index1, 0, true);
+           });
+
 var content_index1 = 0;
 var internal_index2;
 var content_index2 = 1;
 
-// Press a button to make the gamepad visible to the page.
-GamepadService.newButtonEvent(internal_index1, 0, true);
-
 function check_first_gamepad(e) {
   ok(true, "Checking first gamepad");
   // First gamepad gets added.
   is(e.gamepad.id, "test gamepad 1", "correct gamepad name");
   var gamepads = navigator.getGamepads();
   is(gamepads.length, 1, "should have one gamepad exposed");
   is(gamepads[e.gamepad.index], e.gamepad, "right gamepad exposed at index");
   is(gamepads[content_index1], e.gamepad, "gamepad counter working correctly");
   // Add a second gamepad, should automatically show up.
-  internal_index2 = GamepadService.addGamepad("test gamepad 2", // id
-                                     SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
-                                     4, // buttons
-                                     2);// axes
+  addGamepad("test gamepad 2", // id
+             SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
+             4, // buttons
+             2).then(function(index) {
+               internal_index2 = index;
+               GamepadService.newButtonEvent(internal_index2, 0, true);
+             });
   ok(true, "Done checking first gamepad");
 }
 
 function check_second_gamepad(e) {
-  ok(true, "Checking seceond gamepad");
+  ok(true, "Checking second gamepad");
   // Second gamepad gets added.
   is(e.gamepad.index, 1, "gamepad index should be 1")
   is(e.gamepad.id, "test gamepad 2", "correct gamepad name");
   var gamepads = navigator.getGamepads();
   is(gamepads.length, 2, "should have two gamepads exposed");
   is(gamepads[e.gamepad.index], e.gamepad, "right gamepad exposed at index");
   is(gamepads[content_index2], e.gamepad, "gamepad counter working correctly");
   // Now remove the first one.
@@ -95,9 +100,8 @@ function check_no_gamepads(e) {
   // Second gamepad gets removed.
   var gamepads = navigator.getGamepads();
   is(gamepads.length, 0, "gamepads should be empty");
   SimpleTest.finish();
 }
 </script>
 </body>
 </html>
-
new file mode 100644
--- /dev/null
+++ b/dom/webidl/TestFunctions.webidl
@@ -0,0 +1,12 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+// A dumping ground for random testing functions
+[Pref="dom.expose_test_interfaces"]
+interface TestFunctions {
+  [Throws]
+  static void throwUncatchableException();
+};
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -88,20 +88,20 @@ typedef any Transferable;
 Window implements GlobalEventHandlers;
 Window implements WindowEventHandlers;
 
 // http://www.whatwg.org/specs/web-apps/current-work/
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface WindowTimers {
   [Throws] long setTimeout(Function handler, optional long timeout = 0, any... arguments);
   [Throws] long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
-  [Throws] void clearTimeout(optional long handle = 0);
+  void clearTimeout(optional long handle = 0);
   [Throws] long setInterval(Function handler, optional long timeout, any... arguments);
   [Throws] long setInterval(DOMString handler, optional long timeout, any... unused);
-  [Throws] void clearInterval(optional long handle = 0);
+  void clearInterval(optional long handle = 0);
 };
 Window implements WindowTimers;
 
 // http://www.whatwg.org/specs/web-apps/current-work/
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface WindowBase64 {
   [Throws] DOMString btoa(DOMString btoa);
   [Throws] DOMString atob(DOMString atob);
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -683,17 +683,18 @@ WEBIDL_FILES += [
     'StyleRuleChangeEvent.webidl',
     'StyleSheetApplicableStateChangeEvent.webidl',
     'StyleSheetChangeEvent.webidl',
 ]
 
 # We only expose our prefable test interfaces in debug builds, just to be on
 # the safe side.
 if CONFIG['MOZ_DEBUG']:
-    WEBIDL_FILES += ['TestInterfaceJS.webidl',
+    WEBIDL_FILES += ['TestFunctions.webidl',
+                     'TestInterfaceJS.webidl',
                      'TestInterfaceJSDictionaries.webidl',
                      'TestInterfaceJSMaplikeSetlikeIterable.webidl']
 
 if CONFIG['MOZ_B2G_BT']:
     WEBIDL_FILES += [
         'BluetoothAdapter.webidl',
         'BluetoothClassOfDevice.webidl',
         'BluetoothDevice.webidl',
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -724,18 +724,18 @@ ServiceWorkerRegistrationMainThread::Sho
   RefPtr<workers::ServiceWorker> worker = GetActive();
   if (!worker) {
     aRv.ThrowTypeError<MSG_NO_ACTIVE_WORKER>(mScope);
     return nullptr;
   }
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(window);
   RefPtr<Promise> p =
-    Notification::ShowPersistentNotification(global,
-                                             mScope, aTitle, aOptions, aRv);
+    Notification::ShowPersistentNotification(aCx, global, mScope, aTitle,
+                                             aOptions, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return p.forget();
 }
 
 already_AddRefed<Promise>
@@ -1207,17 +1207,17 @@ ServiceWorkerRegistrationWorkerThread::S
                                                         const NotificationOptions& aOptions,
                                                         ErrorResult& aRv)
 {
   // Until Bug 1131324 exposes ServiceWorkerContainer on workers,
   // ShowPersistentNotification() checks for valid active worker while it is
   // also verifying scope so that we block the worker on the main thread only
   // once.
   RefPtr<Promise> p =
-    Notification::ShowPersistentNotification(mWorkerPrivate->GlobalScope(),
+    Notification::ShowPersistentNotification(aCx, mWorkerPrivate->GlobalScope(),
                                              mScope, aTitle, aOptions, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   return p.forget();
 }
 
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -5790,17 +5790,23 @@ WorkerPrivate::ReportError(JSContext* aC
     exnType = JSExnType(aReport->exnType);
   }
   else {
     lineNumber = columnNumber = errorNumber = 0;
     flags = nsIScriptError::errorFlag | nsIScriptError::exceptionFlag;
   }
 
   if (message.IsEmpty()) {
-    message = NS_ConvertUTF8toUTF16(aFallbackMessage);
+    nsDependentCString fallbackMessage(aFallbackMessage);
+    if (!AppendUTF8toUTF16(fallbackMessage, message, mozilla::fallible)) {
+      // Try again, with only a 1 KB string. Do this infallibly this time.
+      // If the user doesn't have 1 KB to spare we're done anyways.
+      nsDependentCString truncatedFallbackMessage(aFallbackMessage, 1024);
+      AppendUTF8toUTF16(truncatedFallbackMessage, message);
+    }
   }
 
   mErrorHandlerRecursionCount++;
 
   // Don't want to run the scope's error handler if this is a recursive error or
   // if there was an error in the close handler or if we ran out of memory.
   bool fireAtScope = mErrorHandlerRecursionCount == 1 &&
                      !mCloseHandlerStarted &&
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -241,17 +241,17 @@ WorkerGlobalScope::SetTimeout(JSContext*
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   Sequence<JS::Value> dummy;
   return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr,
                                     aHandler, aTimeout, dummy, false, aRv);
 }
 
 void
-WorkerGlobalScope::ClearTimeout(int32_t aHandle, ErrorResult& aRv)
+WorkerGlobalScope::ClearTimeout(int32_t aHandle)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   mWorkerPrivate->ClearTimeout(aHandle);
 }
 
 int32_t
 WorkerGlobalScope::SetInterval(JSContext* aCx,
                                Function& aHandler,
@@ -282,17 +282,17 @@ WorkerGlobalScope::SetInterval(JSContext
   bool isInterval = aTimeout.WasPassed();
   int32_t timeout = aTimeout.WasPassed() ? aTimeout.Value() : 0;
 
   return mWorkerPrivate->SetTimeout(GetCurrentThreadJSContext(), nullptr,
                                     aHandler, timeout, dummy, isInterval, aRv);
 }
 
 void
-WorkerGlobalScope::ClearInterval(int32_t aHandle, ErrorResult& aRv)
+WorkerGlobalScope::ClearInterval(int32_t aHandle)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
   mWorkerPrivate->ClearTimeout(aHandle);
 }
 
 void
 WorkerGlobalScope::Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const
 {
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -110,27 +110,27 @@ public:
   int32_t
   SetTimeout(JSContext* aCx, Function& aHandler, const int32_t aTimeout,
              const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
   int32_t
   SetTimeout(JSContext* /* unused */, const nsAString& aHandler,
              const int32_t aTimeout, const Sequence<JS::Value>& /* unused */,
              ErrorResult& aRv);
   void
-  ClearTimeout(int32_t aHandle, ErrorResult& aRv);
+  ClearTimeout(int32_t aHandle);
   int32_t
   SetInterval(JSContext* aCx, Function& aHandler,
               const Optional<int32_t>& aTimeout,
               const Sequence<JS::Value>& aArguments, ErrorResult& aRv);
   int32_t
   SetInterval(JSContext* /* unused */, const nsAString& aHandler,
               const Optional<int32_t>& aTimeout,
               const Sequence<JS::Value>& /* unused */, ErrorResult& aRv);
   void
-  ClearInterval(int32_t aHandle, ErrorResult& aRv);
+  ClearInterval(int32_t aHandle);
 
   void
   Atob(const nsAString& aAtob, nsAString& aOutput, ErrorResult& aRv) const;
   void
   Btoa(const nsAString& aBtoa, nsAString& aOutput, ErrorResult& aRv) const;
 
   IMPL_EVENT_HANDLER(online)
   IMPL_EVENT_HANDLER(offline)
--- a/embedding/ios/confvars.sh
+++ b/embedding/ios/confvars.sh
@@ -10,9 +10,8 @@ MOZ_CHROME_FILE_FORMAT=omni
 MOZ_APP_VERSION=$MOZILLA_VERSION
 MOZ_PLACES=1
 MOZ_EXTENSIONS_DEFAULT=" gio"
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_CRYPTO=1
 MOZ_SERVICES_SYNC=1
 MOZ_MEDIA_NAVIGATOR=1
 MOZ_SERVICES_HEALTHREPORT=1
-MOZ_DISABLE_EXPORT_JS=1
--- a/gfx/2d/Matrix.h
+++ b/gfx/2d/Matrix.h
@@ -543,16 +543,34 @@ public:
   Matrix4x4Typed& ProjectTo2D() {
     _31 = 0.0f;
     _32 = 0.0f;
     _13 = 0.0f;
     _23 = 0.0f;
     _33 = 1.0f;
     _43 = 0.0f;
     _34 = 0.0f;
+    // Some matrices, such as those derived from perspective transforms,
+    // can modify _44 from 1, while leaving the rest of the fourth column
+    // (_14, _24) at 0. In this case, after resetting the third row and
+    // third column above, the value of _44 functions only to scale the
+    // coordinate transform divide by W. The matrix can be converted to
+    // a true 2D matrix by normalizing out the scaling effect of _44 on
+    // the remaining components ahead of time.
+    if (_14 == 0.0f && _24 == 0.0f &&
+        _44 != 1.0f && _44 != 0.0f) {
+      Float scale = 1.0f / _44;
+      _11 *= scale;
+      _12 *= scale;
+      _21 *= scale;
+      _22 *= scale;
+      _41 *= scale;
+      _42 *= scale;
+      _44 = 1.0f;
+    }
     return *this;
   }
 
   template<class F>
   Point4DTyped<TargetUnits, F>
   ProjectPoint(const PointTyped<SourceUnits, F>& aPoint) const {
     // Find a value for z that will transform to 0.
 
--- a/gfx/cairo/libpixman/src/pixman-sse2.c
+++ b/gfx/cairo/libpixman/src/pixman-sse2.c
@@ -5677,16 +5677,86 @@ FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888
 			       uint32_t, uint32_t, uint32_t,
 			       NONE, FLAG_NONE)
 FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_normal_SRC,
 			       scaled_bilinear_scanline_sse2_8888_8888_SRC, NULL,
 			       uint32_t, uint32_t, uint32_t,
 			       NORMAL, FLAG_NONE)
 
 static force_inline void
+scaled_bilinear_scanline_sse2_x888_8888_SRC (uint32_t *       dst,
+					     const uint32_t * mask,
+					     const uint32_t * src_top,
+					     const uint32_t * src_bottom,
+					     int32_t          w,
+					     int              wt,
+					     int              wb,
+					     pixman_fixed_t   vx_,
+					     pixman_fixed_t   unit_x_,
+					     pixman_fixed_t   max_vx,
+					     pixman_bool_t    zero_src)
+{
+    intptr_t vx = vx_;
+    intptr_t unit_x = unit_x_;
+    BILINEAR_DECLARE_VARIABLES;
+    uint32_t pix1, pix2, pix3, pix4;
+
+    while (w && ((uintptr_t)dst & 15))
+    {
+	BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
+	*dst++ = pix1 | 0xFF000000;
+	w--;
+    }
+
+    while ((w -= 4) >= 0) {
+	__m128i xmm_src;
+        BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
+        BILINEAR_INTERPOLATE_ONE_PIXEL (pix2);
+        BILINEAR_INTERPOLATE_ONE_PIXEL (pix3);
+        BILINEAR_INTERPOLATE_ONE_PIXEL (pix4);
+
+        xmm_src = _mm_set_epi32 (pix4, pix3, pix2, pix1);
+        _mm_store_si128 ((__m128i *)dst, _mm_or_si128 (xmm_src, mask_ff000000));
+        dst += 4;
+    }
+
+    if (w & 2)
+    {
+	BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
+	BILINEAR_INTERPOLATE_ONE_PIXEL (pix2);
+	*dst++ = pix1 | 0xFF000000;
+	*dst++ = pix2 | 0xFF000000;
+    }
+
+    if (w & 1)
+    {
+	BILINEAR_INTERPOLATE_ONE_PIXEL (pix1);
+	*dst = pix1 | 0xFF000000;
+    }
+}
+
+FAST_BILINEAR_MAINLOOP_COMMON (sse2_x888_8888_cover_SRC,
+			       scaled_bilinear_scanline_sse2_x888_8888_SRC, NULL,
+			       uint32_t, uint32_t, uint32_t,
+			       COVER, FLAG_NONE)
+FAST_BILINEAR_MAINLOOP_COMMON (sse2_x888_8888_pad_SRC,
+			       scaled_bilinear_scanline_sse2_x888_8888_SRC, NULL,
+			       uint32_t, uint32_t, uint32_t,
+			       PAD, FLAG_NONE)
+FAST_BILINEAR_MAINLOOP_COMMON (sse2_x888_8888_normal_SRC,
+			       scaled_bilinear_scanline_sse2_x888_8888_SRC, NULL,
+			       uint32_t, uint32_t, uint32_t,
+			       NORMAL, FLAG_NONE)
+#if 0
+FAST_BILINEAR_MAINLOOP_COMMON (sse2_8888_8888_pad_OVER,
+			       scaled_bilinear_scanline_sse2_8888_8888_OVER, NULL,
+			       uint32_t, uint32_t, uint32_t,
+			       PAD, FLAG_NONE)
+#endif
+static force_inline void
 scaled_bilinear_scanline_sse2_8888_8888_OVER (uint32_t *       dst,
 					      const uint32_t * mask,
 					      const uint32_t * src_top,
 					      const uint32_t * src_bottom,
 					      int32_t          w,
 					      int              wt,
 					      int              wb,
 					      pixman_fixed_t   vx,
@@ -6218,16 +6288,23 @@ static const pixman_fast_path_t sse2_fas
 
     SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (SRC, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (SRC, x8r8g8b8, x8r8g8b8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (SRC, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (SRC, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (SRC, x8b8g8r8, x8b8g8r8, sse2_8888_8888),
 
+    SIMPLE_BILINEAR_FAST_PATH_COVER  (SRC, x8r8g8b8, a8r8g8b8, sse2_x888_8888),
+    SIMPLE_BILINEAR_FAST_PATH_COVER  (SRC, x8b8g8r8, a8b8g8r8, sse2_x888_8888),
+    SIMPLE_BILINEAR_FAST_PATH_PAD    (SRC, x8r8g8b8, a8r8g8b8, sse2_x888_8888),
+    SIMPLE_BILINEAR_FAST_PATH_PAD    (SRC, x8b8g8r8, a8b8g8r8, sse2_x888_8888),
+    SIMPLE_BILINEAR_FAST_PATH_NORMAL (SRC, x8r8g8b8, a8r8g8b8, sse2_x888_8888),
+    SIMPLE_BILINEAR_FAST_PATH_NORMAL (SRC, x8b8g8r8, a8b8g8r8, sse2_x888_8888),
+
     SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_8888),
     SIMPLE_BILINEAR_FAST_PATH (OVER, a8b8g8r8, a8b8g8r8, sse2_8888_8888),
 
     SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, x8r8g8b8, sse2_8888_n_8888),
     SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH (OVER, a8b8g8r8, x8b8g8r8, sse2_8888_n_8888),
     SIMPLE_BILINEAR_SOLID_MASK_FAST_PATH (OVER, a8r8g8b8, a8r8g8b8, sse2_8888_n_8888),
--- a/gfx/gl/SharedSurfaceD3D11Interop.cpp
+++ b/gfx/gl/SharedSurfaceD3D11Interop.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
 /* 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 "SharedSurfaceD3D11Interop.h"
 
 #include <d3d11.h>
+#include "gfxPrefs.h"
 #include "GLContext.h"
 #include "WGLLibrary.h"
 
 namespace mozilla {
 namespace gl {
 
 /*
 Sample Code for WGL_NV_DX_interop2:
@@ -259,69 +260,57 @@ SharedSurface_D3D11Interop::Create(const
     HANDLE objectWGL = dxgl->RegisterObject(textureD3D, renderbufferGL,
                                             LOCAL_GL_RENDERBUFFER,
                                             LOCAL_WGL_ACCESS_WRITE_DISCARD_NV);
     if (!objectWGL) {
         NS_WARNING("Failed to register D3D object with WGL.");
         return nullptr;
     }
 
-    GLuint fence = 0;
-    if (gl->IsExtensionSupported(GLContext::NV_fence)) {
-        gl->MakeCurrent();
-        gl->fGenFences(1, &fence);
-    }
-
     typedef SharedSurface_D3D11Interop ptrT;
     UniquePtr<ptrT> ret ( new ptrT(gl, size, hasAlpha, renderbufferGL, dxgl, objectWGL,
-                                   textureD3D, sharedHandle, keyedMutex, fence) );
+                                   textureD3D, sharedHandle, keyedMutex) );
     return Move(ret);
 }
 
 SharedSurface_D3D11Interop::SharedSurface_D3D11Interop(GLContext* gl,
                                                        const gfx::IntSize& size,
                                                        bool hasAlpha,
                                                        GLuint renderbufferGL,
                                                        const RefPtr<DXGLDevice>& dxgl,
                                                        HANDLE objectWGL,
                                                        const RefPtr<ID3D11Texture2D>& textureD3D,
                                                        HANDLE sharedHandle,
-                                                       const RefPtr<IDXGIKeyedMutex>& keyedMutex,
-                                                       GLuint fence)
+                                                       const RefPtr<IDXGIKeyedMutex>& keyedMutex)
     : SharedSurface(SharedSurfaceType::DXGLInterop2,
                     AttachmentType::GLRenderbuffer,
                     gl,
                     size,
                     hasAlpha,
                     true)
     , mProdRB(renderbufferGL)
     , mDXGL(dxgl)
     , mObjectWGL(objectWGL)
     , mTextureD3D(textureD3D)
+    , mNeedsFinish(gfxPrefs::WebGLDXGLNeedsFinish())
     , mSharedHandle(sharedHandle)
     , mKeyedMutex(keyedMutex)
-    , mFence(fence)
     , mLockedForGL(false)
 { }
 
 SharedSurface_D3D11Interop::~SharedSurface_D3D11Interop()
 {
     MOZ_ASSERT(!mLockedForGL);
 
     mGL->fDeleteRenderbuffers(1, &mProdRB);
 
     if (!mDXGL->UnregisterObject(mObjectWGL)) {
         NS_WARNING("Failed to release a DXGL object, possibly leaking it.");
     }
 
-    if (mFence) {
-        mGL->MakeCurrent();
-        mGL->fDeleteFences(1, &mFence);
-    }
-
     // mDXGL is closed when it runs out of refs.
 }
 
 void
 SharedSurface_D3D11Interop::LockProdImpl()
 { }
 
 void
@@ -359,27 +348,28 @@ SharedSurface_D3D11Interop::ProducerRele
 
     mLockedForGL = false;
 
     // Now we have unlocked for GL, we can release to consumer.
     if (mKeyedMutex) {
         mKeyedMutex->ReleaseSync(0);
     }
 
-    // TODO fence properly. This kills performance.
-    mGL->fFinish();
+    if (mNeedsFinish) {
+        mGL->fFinish();
+    }
 }
 
 bool
 SharedSurface_D3D11Interop::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
 {
     gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
                                           : gfx::SurfaceFormat::B8G8R8X8;
-    *out_descriptor = layers::SurfaceDescriptorD3D10((WindowsHandle)GetSharedHandle(),
-                                                     format, mSize);
+    *out_descriptor = layers::SurfaceDescriptorD3D10(WindowsHandle(mSharedHandle), format,
+                                                     mSize);
     return true;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 // Factory
 
 /*static*/ UniquePtr<SurfaceFactory_D3D11Interop>
 SurfaceFactory_D3D11Interop::Create(GLContext* gl, const SurfaceCaps& caps,
--- a/gfx/gl/SharedSurfaceD3D11Interop.h
+++ b/gfx/gl/SharedSurfaceD3D11Interop.h
@@ -17,27 +17,29 @@ namespace gl {
 
 class DXGLDevice;
 class GLContext;
 class WGLLibrary;
 
 class SharedSurface_D3D11Interop
     : public SharedSurface
 {
+public:
     const GLuint mProdRB;
     const RefPtr<DXGLDevice> mDXGL;
     const HANDLE mObjectWGL;
     const HANDLE mSharedHandle;
     const RefPtr<ID3D11Texture2D> mTextureD3D;
+    const bool mNeedsFinish;
+
+protected:
     RefPtr<IDXGIKeyedMutex> mKeyedMutex;
     RefPtr<IDXGIKeyedMutex> mConsumerKeyedMutex;
     RefPtr<ID3D11Texture2D> mConsumerTexture;
-    const GLuint mFence;
 
-protected:
     bool mLockedForGL;
 
 public:
     static UniquePtr<SharedSurface_D3D11Interop> Create(const RefPtr<DXGLDevice>& dxgl,
                                                         GLContext* gl,
                                                         const gfx::IntSize& size,
                                                         bool hasAlpha);
 
@@ -51,38 +53,32 @@ protected:
     SharedSurface_D3D11Interop(GLContext* gl,
                                const gfx::IntSize& size,
                                bool hasAlpha,
                                GLuint renderbufferGL,
                                const RefPtr<DXGLDevice>& dxgl,
                                HANDLE objectWGL,
                                const RefPtr<ID3D11Texture2D>& textureD3D,
                                HANDLE sharedHandle,
-                               const RefPtr<IDXGIKeyedMutex>& keyedMutex,
-                               GLuint fence);
+                               const RefPtr<IDXGIKeyedMutex>& keyedMutex);
 
 public:
     virtual ~SharedSurface_D3D11Interop();
 
     virtual void LockProdImpl() override;
     virtual void UnlockProdImpl() override;
 
     virtual void ProducerAcquireImpl() override;
     virtual void ProducerReleaseImpl() override;
 
     virtual GLuint ProdRenderbuffer() override {
         return mProdRB;
     }
 
     virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
-
-    // Implementation-specific functions below:
-    HANDLE GetSharedHandle() const {
-        return mSharedHandle;
-    }
 };
 
 
 class SurfaceFactory_D3D11Interop
     : public SurfaceFactory
 {
 public:
     const RefPtr<DXGLDevice> mDXGL;
--- a/gfx/graphite2/src/Collider.cpp
+++ b/gfx/graphite2/src/Collider.cpp
@@ -21,17 +21,17 @@
 
 Alternatively, the contents of this file may be used under the terms of the
 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
 License, as published by the Free Software Foundation, either version 2
 of the License or (at your option) any later version.
 */
 #include <algorithm>
 #include <limits>
-#include <math.h>
+#include <cmath>
 #include <string>
 #include <functional>
 #include "inc/Collider.h"
 #include "inc/Segment.h"
 #include "inc/Slot.h"
 #include "inc/GlyphCache.h"
 #include "inc/Sparse.h"
 
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stack>
 #include "APZCTreeManager.h"
 #include "AsyncPanZoomController.h"
 #include "Compositor.h"                 // for Compositor
+#include "DragTracker.h"                // for DragTracker
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "HitTestingTreeNode.h"         // for HitTestingTreeNode
 #include "InputBlockState.h"            // for InputBlockState
 #include "InputData.h"                  // for InputData, etc
 #include "Layers.h"                     // for Layer, etc
 #include "mozilla/dom/Touch.h"          // for Touch
 #include "mozilla/gfx/Logging.h"        // for gfx::TreeLog
 #include "mozilla/gfx/Point.h"          // for Point
@@ -613,20 +614,16 @@ WillHandleWheelEvent(WidgetWheelEvent* a
          (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE ||
           aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL ||
           aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE);
 }
 
 static bool
 WillHandleMouseEvent(const WidgetMouseEventBase& aEvent)
 {
-  if (!gfxPrefs::APZDragEnabled()) {
-    return false;
-  }
-
   return aEvent.mMessage == eMouseMove ||
          aEvent.mMessage == eMouseDown ||
          aEvent.mMessage == eMouseUp;
 }
 
 template<typename PanGestureOrScrollWheelInput>
 static bool
 WillHandleInput(const PanGestureOrScrollWheelInput& aPanInput)
@@ -669,40 +666,70 @@ APZCTreeManager::ReceiveInputEvent(Input
   switch (aEvent.mInputType) {
     case MULTITOUCH_INPUT: {
       MultiTouchInput& touchInput = aEvent.AsMultiTouchInput();
       result = ProcessTouchInput(touchInput, aOutTargetGuid, aOutInputBlockId);
       break;
     } case MOUSE_INPUT: {
       MouseInput& mouseInput = aEvent.AsMouseInput();
 
+      if (DragTracker::StartsDrag(mouseInput)) {
+        // If this is the start of a drag we need to unambiguously know if it's
+        // going to land on a scrollbar or not. We can't apply an untransform
+        // here without knowing that, so we need to ensure the untransform is
+        // a no-op.
+        FlushRepaintsToClearScreenToGeckoTransform();
+      }
+
+      bool hitScrollbar = false;
       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(mouseInput.mOrigin,
-                                                            &hitResult);
+            &hitResult, &hitScrollbar);
 
       // When the mouse is outside the window we still want to handle dragging
       // but we won't find an APZC. Fallback to root APZC then.
       if (!apzc && mRootNode) {
         apzc = mRootNode->GetApzc();
       }
 
       if (apzc) {
         result = mInputQueue->ReceiveInputEvent(
           apzc,
           /* aTargetConfirmed = */ false,
           mouseInput, aOutInputBlockId);
 
+        if (result == nsEventStatus_eConsumeDoDefault) {
+          // This input event is part of a drag block, so whether or not it is
+          // directed at a scrollbar depends on whether the drag block started
+          // on a scrollbar.
+          hitScrollbar = mInputQueue->IsDragOnScrollbar(hitScrollbar);
+        }
+
         // Update the out-parameters so they are what the caller expects.
         apzc->GetGuid(aOutTargetGuid);
 
-        // TODO Dagging on a scrollbar probably behaves differently from
-        // the other input types in that the gecko coordinates are the same
-        // as the screen coordinates even though the async transform on the APZC
-        // is changing. I'm not really sure at this point and it'll take some
-        // though to figure out properly.
-        //mouseInput.mOrigin = untransformedOrigin;
+        if (!hitScrollbar) {
+          // The input was not targeted at a scrollbar, so we untransform it
+          // like we do for other content. Scrollbars are "special" because they
+          // have special handling in AsyncCompositionManager when resolution is
+          // applied. TODO: we should find a better way to deal with this.
+          ScreenToParentLayerMatrix4x4 transformToApzc = GetScreenToApzcTransform(apzc);
+          ParentLayerToScreenMatrix4x4 transformToGecko = GetApzcToGeckoTransform(apzc);
+          ScreenToScreenMatrix4x4 outTransform = transformToApzc * transformToGecko;
+          Maybe<ScreenPoint> untransformedRefPoint = UntransformBy(
+            outTransform, mouseInput.mOrigin);
+          if (untransformedRefPoint) {
+            mouseInput.mOrigin = *untransformedRefPoint;
+          }
+        } else {
+          // Likewise, if the input was targeted at a scrollbar, we don't want to
+          // apply the callback transform in the main thread, so we remove the
+          // scrollid from the guid. We need to keep the layersId intact so
+          // that the response from the child process doesn't get discarded.
+          aOutTargetGuid->mScrollId = FrameMetrics::NULL_SCROLL_ID;
+        }
       }
       break;
     } case SCROLLWHEEL_INPUT: {
       FlushRepaintsToClearScreenToGeckoTransform();
 
       ScrollWheelInput& wheelInput = aEvent.AsScrollWheelInput();
 
       wheelInput.mHandledByAPZ = WillHandleInput(wheelInput);
@@ -1089,20 +1116,19 @@ APZCTreeManager::ProcessWheelEvent(Widge
   return status;
 }
 
 nsEventStatus
 APZCTreeManager::ReceiveInputEvent(WidgetInputEvent& aEvent,
                                    ScrollableLayerGuid* aOutTargetGuid,
                                    uint64_t* aOutInputBlockId)
 {
-  // This function will be removed once metro code is modified to use the
-  // InputData version of ReceiveInputEvent.
   // In general it is preferable to use the version of ReceiveInputEvent
-  // that takes an InputData, as that is usable from off-main-thread.
+  // that takes an InputData, as that is usable from off-main-thread. On some
+  // platforms OMT input isn't possible, and there we can use this version.
 
   MOZ_ASSERT(NS_IsMainThread());
   APZThreadUtils::AssertOnControllerThread();
 
   // Initialize aOutInputBlockId to a sane value, and then later we overwrite
   // it if the input event goes into a block.
   if (aOutInputBlockId) {
     *aOutInputBlockId = InputBlockState::NO_BLOCK_ID;
@@ -1533,23 +1559,26 @@ APZCTreeManager::GetTargetNode(const Scr
         }
         return matches;
       }
   );
   return target.forget();
 }
 
 already_AddRefed<AsyncPanZoomController>
-APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint, HitTestResult* aOutHitResult)
+APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
+                               HitTestResult* aOutHitResult,
+                               bool* aOutHitScrollbar)
 {
   MutexAutoLock lock(mTreeLock);
   HitTestResult hitResult = HitNothing;
   ParentLayerPoint point = ViewAs<ParentLayerPixel>(aPoint,
     PixelCastJustification::ScreenIsParentLayerForRoot);
-  RefPtr<AsyncPanZoomController> target = GetAPZCAtPoint(mRootNode, point, &hitResult);
+  RefPtr<AsyncPanZoomController> target = GetAPZCAtPoint(mRootNode, point,
+      &hitResult, aOutHitScrollbar);
 
   if (aOutHitResult) {
     *aOutHitResult = hitResult;
   }
   return target.forget();
 }
 
 static bool
@@ -1652,17 +1681,18 @@ APZCTreeManager::FindScrollNode(const As
       [&aDragMetrics](HitTestingTreeNode* aNode) {
         return aNode->MatchesScrollDragMetrics(aDragMetrics);
       });
 }
 
 AsyncPanZoomController*
 APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
                                 const ParentLayerPoint& aHitTestPoint,
-                                HitTestResult* aOutHitResult)
+                                HitTestResult* aOutHitResult,
+                                bool* aOutHitScrollbar)
 {
   mTreeLock.AssertCurrentThreadOwns();
 
   // This walks the tree in depth-first, reverse order, so that it encounters
   // APZCs front-to-back on the screen.
   HitTestingTreeNode* resultNode;
   HitTestingTreeNode* root = aNode;
   std::stack<ParentLayerPoint> hitTestPoints;
@@ -1704,16 +1734,23 @@ APZCTreeManager::GetAPZCAtPoint(HitTesti
           return TraversalFlag::Abort;
         }
         return TraversalFlag::Continue;
       }
   );
 
   if (*aOutHitResult != HitNothing) {
       MOZ_ASSERT(resultNode);
+      if (aOutHitScrollbar) {
+        for (HitTestingTreeNode* n = resultNode; n; n = n->GetParent()) {
+          if (n->IsScrollbarNode()) {
+            *aOutHitScrollbar = true;
+          }
+        }
+      }
       AsyncPanZoomController* result = resultNode->GetNearestContainingApzcWithSameLayersId();
       if (!result) {
         result = FindRootApzcForLayersId(resultNode->GetLayersId());
         MOZ_ASSERT(result);
       }
       APZCTM_LOG("Successfully matched APZC %p via node %p (hit result %d)\n",
           result, aNode, *aOutHitResult);
       return result;
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -433,17 +433,18 @@ public:
   /* Some helper functions to find an APZC given some identifying input. These functions
      lock the tree of APZCs while they find the right one, and then return an addref'd
      pointer to it. This allows caller code to just use the target APZC without worrying
      about it going away. These are public for testing code and generally should not be
      used by other production code.
   */
   RefPtr<HitTestingTreeNode> GetRootNode() const;
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint,
-                                                         HitTestResult* aOutHitResult);
+                                                         HitTestResult* aOutHitResult,
+                                                         bool* aOutHitScrollbar = nullptr);
   ScreenToParentLayerMatrix4x4 GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const;
   ParentLayerToScreenMatrix4x4 GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const;
 private:
   typedef bool (*GuidComparator)(const ScrollableLayerGuid&, const ScrollableLayerGuid&);
 
   /* Helpers */
   void AttachNodeToTree(HitTestingTreeNode* aNode,
                         HitTestingTreeNode* aParent,
@@ -451,17 +452,18 @@ private:
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
   already_AddRefed<HitTestingTreeNode> GetTargetNode(const ScrollableLayerGuid& aGuid,
                                                      GuidComparator aComparator);
   HitTestingTreeNode* FindTargetNode(HitTestingTreeNode* aNode,
                                      const ScrollableLayerGuid& aGuid,
                                      GuidComparator aComparator);
   AsyncPanZoomController* GetAPZCAtPoint(HitTestingTreeNode* aNode,
                                          const ParentLayerPoint& aHitTestPoint,
-                                         HitTestResult* aOutHitResult);
+                                         HitTestResult* aOutHitResult,
+                                         bool* aOutHitScrollbar);
   AsyncPanZoomController* FindRootApzcForLayersId(uint64_t aLayersId) const;
   AsyncPanZoomController* FindRootContentApzcForLayersId(uint64_t aLayersId) const;
   AsyncPanZoomController* FindRootContentOrRootApzc() const;
   already_AddRefed<AsyncPanZoomController> GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const;
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const MultiTouchInput& aEvent,
                                                                   HitTestResult* aOutHitResult);
   nsEventStatus ProcessTouchInput(MultiTouchInput& aInput,
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -1028,16 +1028,20 @@ static float GetAxisScale(AsyncDragMetri
   } else {
     return aValue.yScale;
   }
 }
 
 nsEventStatus AsyncPanZoomController::HandleDragEvent(const MouseInput& aEvent,
                                                       const AsyncDragMetrics& aDragMetrics)
 {
+  if (!gfxPrefs::APZDragEnabled()) {
+    return nsEventStatus_eIgnore;
+  }
+
   if (!GetApzcTreeManager()) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   RefPtr<HitTestingTreeNode> node =
     GetApzcTreeManager()->FindScrollNode(aDragMetrics);
   if (!node) {
     return nsEventStatus_eConsumeNoDefault;
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/DragTracker.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DragTracker.h"
+
+#include "InputData.h"
+
+#define DRAG_LOG(...)
+// #define DRAG_LOG(...) printf_stderr("DRAG: " __VA_ARGS__)
+
+namespace mozilla {
+namespace layers {
+
+DragTracker::DragTracker()
+  : mInDrag(false)
+{
+}
+
+/*static*/ bool
+DragTracker::StartsDrag(const MouseInput& aInput)
+{
+  return aInput.IsLeftButton() && aInput.mType == MouseInput::MOUSE_DOWN;
+}
+
+/*static*/ bool
+DragTracker::EndsDrag(const MouseInput& aInput)
+{
+  return aInput.IsLeftButton() && aInput.mType == MouseInput::MOUSE_UP;
+}
+
+void
+DragTracker::Update(const MouseInput& aInput)
+{
+  if (StartsDrag(aInput)) {
+    DRAG_LOG("Starting drag\n");
+    mInDrag = true;
+  } else if (EndsDrag(aInput)) {
+    DRAG_LOG("Ending drag\n");
+    mInDrag = false;
+    mOnScrollbar = Nothing();
+  }
+}
+
+bool
+DragTracker::InDrag() const
+{
+  return mInDrag;
+}
+
+bool
+DragTracker::IsOnScrollbar(bool aOnScrollbar)
+{
+  if (!mOnScrollbar) {
+    DRAG_LOG("Setting hitscrollbar %d\n", aOnScrollbar);
+    mOnScrollbar = Some(aOnScrollbar);
+  }
+  return mOnScrollbar.value();
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/DragTracker.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layers_DragTracker_h
+#define mozilla_layers_DragTracker_h
+
+#include "mozilla/EventForwards.h"
+
+namespace mozilla {
+
+class MouseInput;
+
+namespace layers {
+
+// DragTracker simply tracks a sequence of mouse inputs and allows us to tell
+// if we are in a drag or not (i.e. the left mouse button went down and hasn't
+// gone up yet).
+class DragTracker
+{
+public:
+  DragTracker();
+  static bool StartsDrag(const MouseInput& aInput);
+  static bool EndsDrag(const MouseInput& aInput);
+  void Update(const MouseInput& aInput);
+  bool InDrag() const;
+  bool IsOnScrollbar(bool aOnScrollbar);
+
+private:
+  Maybe<bool> mOnScrollbar;
+  bool mInDrag;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* mozilla_layers_DragTracker_h */
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -109,16 +109,22 @@ HitTestingTreeNode::MatchesScrollDragMet
 }
 
 int32_t
 HitTestingTreeNode::GetScrollSize() const
 {
   return mScrollSize;
 }
 
+bool
+HitTestingTreeNode::IsScrollbarNode() const
+{
+  return (mScrollDir != Layer::NONE);
+}
+
 void
 HitTestingTreeNode::SetPrevSibling(HitTestingTreeNode* aSibling)
 {
   mPrevSibling = aSibling;
   if (aSibling) {
     aSibling->mParent = mParent;
 
     if (aSibling->GetApzc()) {
--- a/gfx/layers/apz/src/HitTestingTreeNode.h
+++ b/gfx/layers/apz/src/HitTestingTreeNode.h
@@ -90,16 +90,17 @@ public:
                       const EventRegionsOverride& aOverride);
   bool IsOutsideClip(const ParentLayerPoint& aPoint) const;
 
   /* Scrollbar info */
 
   void SetScrollbarData(FrameMetrics::ViewID aScrollViewId, Layer::ScrollDirection aDir, int32_t aScrollSize);
   bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const;
   int32_t GetScrollSize() const;
+  bool IsScrollbarNode() const;
 
   /* Convert aPoint into the LayerPixel space for the layer corresponding to
    * this node. */
   Maybe<LayerPoint> Untransform(const ParentLayerPoint& aPoint) const;
   /* Assuming aPoint is inside the clip region for this node, check which of the
    * event region spaces it falls inside. */
   HitTestResult HitTest(const ParentLayerPoint& aPoint) const;
   /* Returns the mOverride flag. */
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -180,29 +180,41 @@ nsEventStatus
 InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
                               bool aTargetConfirmed,
                               const MouseInput& aEvent,
                               uint64_t* aOutInputBlockId) {
   MOZ_ASSERT(!aTargetConfirmed); // We wont know the target until content tells us
 
   // On a new mouse down we can have a new target so we must force a new block
   // with a new target.
-  bool newBlock = aEvent.mType == MouseInput::MOUSE_DOWN && aEvent.IsLeftButton();
+  bool newBlock = DragTracker::StartsDrag(aEvent);
 
   DragBlockState* block = nullptr;
   if (!newBlock && !mInputBlockQueue.IsEmpty()) {
     block = mInputBlockQueue.LastElement()->AsDragBlock();
   }
 
   if (block && block->HasReceivedMouseUp()) {
     block = nullptr;
   }
 
+  if (!block && mDragTracker.InDrag()) {
+    // If there's no current drag block, but we're getting a move with a button
+    // down, we need to start a new drag block because we're obviously already
+    // in the middle of a drag (it probably got interrupted by something else).
+    INPQ_LOG("got a drag event outside a drag block, need to create a block to hold it\n");
+    newBlock = true;
+  }
+
+  mDragTracker.Update(aEvent);
+
   if (!newBlock && !block) {
-    return nsEventStatus_eConsumeDoDefault;
+    // This input event is not in a drag block, so we're not doing anything
+    // with it, return eIgnore.
+    return nsEventStatus_eIgnore;
   }
 
   if (!block) {
     MOZ_ASSERT(newBlock);
     block = new DragBlockState(aTarget, aTargetConfirmed, aEvent);
     if (aOutInputBlockId) {
       *aOutInputBlockId = block->GetBlockId();
     }
@@ -213,35 +225,34 @@ InputQueue::ReceiveMouseInput(const RefP
     SweepDepletedBlocks();
     mInputBlockQueue.AppendElement(block);
 
     CancelAnimationsForNewBlock(block);
     MaybeRequestContentResponse(aTarget, block);
 
     block->AddEvent(aEvent.AsMouseInput());
 
-    // The first event will confirm the block or not.
+    // This input event created a new drag block, so return DoDefault.
     return nsEventStatus_eConsumeDoDefault;
   }
 
   if (aOutInputBlockId) {
     *aOutInputBlockId = block->GetBlockId();
   }
 
   if (!MaybeHandleCurrentBlock(block, aEvent)) {
     block->AddEvent(aEvent.AsMouseInput());
   }
 
-  bool mouseUp = aEvent.mType == MouseInput::MOUSE_UP && aEvent.IsLeftButton();
-  if (mouseUp) {
+  if (DragTracker::EndsDrag(aEvent)) {
     block->MarkMouseUpReceived();
   }
 
-  // If we're not the first event then we need to wait for the confirmation of
-  // the block.
+  // The event was added to the drag block and could potentially cause
+  // scrolling, so return DoDefault.
   return nsEventStatus_eConsumeDoDefault;
 }
 
 nsEventStatus
 InputQueue::ReceiveScrollWheelInput(const RefPtr<AsyncPanZoomController>& aTarget,
                                     bool aTargetConfirmed,
                                     const ScrollWheelInput& aEvent,
                                     uint64_t* aOutInputBlockId) {
@@ -535,16 +546,29 @@ InputQueue::AllowScrollHandoff() const
     return CurrentBlock()->AsWheelBlock()->AllowScrollHandoff();
   }
   if (CurrentBlock()->AsPanGestureBlock()) {
     return CurrentBlock()->AsPanGestureBlock()->AllowScrollHandoff();
   }
   return true;
 }
 
+bool
+InputQueue::IsDragOnScrollbar(bool aHitScrollbar)
+{
+  if (!mDragTracker.InDrag()) {
+    return false;
+  }
+  // Now that we know we are in a drag, get the info from the drag tracker.
+  // We keep it in the tracker rather than the block because the block can get
+  // interrupted by something else (like a wheel event) and then a new block
+  // will get created without the info we want. The tracker will persist though.
+  return mDragTracker.IsOnScrollbar(aHitScrollbar);
+}
+
 void
 InputQueue::ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTarget, uint64_t aInputBlockId) {
   INPQ_LOG("scheduling main thread timeout for target %p\n", aTarget.get());
   aTarget->PostDelayedTask(
     NewRunnableMethod(this, &InputQueue::MainThreadTimeout, aInputBlockId),
     gfxPrefs::APZContentResponseTimeout());
 }
 
--- a/gfx/layers/apz/src/InputQueue.h
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_InputQueue_h
 #define mozilla_layers_InputQueue_h
 
 #include "APZUtils.h"
+#include "DragTracker.h"
 #include "InputData.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/UniquePtr.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 
@@ -113,16 +114,22 @@ public:
   /**
    * Remove all input blocks from the input queue.
    */
   void Clear();
   /**
    * Whether the current pending block allows scroll handoff.
    */
   bool AllowScrollHandoff() const;
+  /**
+   * If there is currently a drag in progress, return whether or not it was
+   * targeted at a scrollbar. If the drag was newly-created and doesn't know,
+   * use the provided |aOnScrollbar| to populate that information.
+   */
+  bool IsDragOnScrollbar(bool aOnScrollbar);
 
 private:
   ~InputQueue();
 
   TouchBlockState* StartNewTouchBlock(const RefPtr<AsyncPanZoomController>& aTarget,
                                       bool aTargetConfirmed,
                                       bool aCopyPropertiesFromCurrent);
 
@@ -177,14 +184,17 @@ private:
   // This member must only be accessed on the controller/UI thread.
   nsTArray<UniquePtr<CancelableBlockState>> mInputBlockQueue;
 
   // The APZC to which the last event was delivered
   RefPtr<AsyncPanZoomController> mLastActiveApzc;
 
   // Track touches so we know when to clear mLastActiveApzc
   TouchCounter mTouchCounter;
+
+  // Track mouse inputs so we know if we're in a drag or not
+  DragTracker mDragTracker;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_InputQueue_h
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -531,23 +531,29 @@ APZCCallbackHelper::ApplyCallbackTransfo
                                            const CSSToLayoutDeviceScale& aScale)
 {
     LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y);
     point = ApplyCallbackTransform(point / aScale, aGuid) * aScale;
     return gfx::RoundedToInt(point);
 }
 
 void
-APZCCallbackHelper::ApplyCallbackTransform(WidgetTouchEvent& aEvent,
+APZCCallbackHelper::ApplyCallbackTransform(WidgetEvent& aEvent,
                                            const ScrollableLayerGuid& aGuid,
                                            const CSSToLayoutDeviceScale& aScale)
 {
-  for (size_t i = 0; i < aEvent.touches.Length(); i++) {
-    aEvent.touches[i]->mRefPoint = ApplyCallbackTransform(
-        aEvent.touches[i]->mRefPoint, aGuid, aScale);
+  if (aEvent.AsTouchEvent()) {
+    WidgetTouchEvent& event = *(aEvent.AsTouchEvent());
+    for (size_t i = 0; i < event.touches.Length(); i++) {
+      event.touches[i]->mRefPoint = ApplyCallbackTransform(
+          event.touches[i]->mRefPoint, aGuid, aScale);
+    }
+  } else {
+    aEvent.refPoint = ApplyCallbackTransform(
+        aEvent.refPoint, aGuid, aScale);
   }
 }
 
 nsEventStatus
 APZCCallbackHelper::DispatchWidgetEvent(WidgetGUIEvent& aEvent)
 {
   nsEventStatus status = nsEventStatus_eConsumeNoDefault;
   if (aEvent.widget) {
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -94,19 +94,19 @@ public:
     /* Same as above, but operates on LayoutDeviceIntPoint.
        Requires an additonal |aScale| parameter to convert between CSS and
        LayoutDevice space. */
     static mozilla::LayoutDeviceIntPoint
     ApplyCallbackTransform(const LayoutDeviceIntPoint& aPoint,
                            const ScrollableLayerGuid& aGuid,
                            const CSSToLayoutDeviceScale& aScale);
 
-    /* Convenience function for applying a callback transform to all touch
-     * points of a touch event. */
-    static void ApplyCallbackTransform(WidgetTouchEvent& aEvent,
+    /* Convenience function for applying a callback transform to all refpoints
+     * in the input event. */
+    static void ApplyCallbackTransform(WidgetEvent& aEvent,
                                        const ScrollableLayerGuid& aGuid,
                                        const CSSToLayoutDeviceScale& aScale);
 
     /* Dispatch a widget event via the widget stored in the event, if any.
      * In a child process, allows the TabParent event-capture mechanism to
      * intercept the event. */
     static nsEventStatus DispatchWidgetEvent(WidgetGUIEvent& aEvent);
 
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -544,37 +544,41 @@ CompositorD3D11::CreateTexture(const gfx
     HandleError(hr);
     return nullptr;
   }
 
   if (aSource) {
     const CompositingRenderTargetD3D11* sourceD3D11 =
       static_cast<const CompositingRenderTargetD3D11*>(aSource);
 
-    D3D11_BOX srcBox;
-    srcBox.left = aSourcePoint.x;
-    srcBox.top = aSourcePoint.y;
-    srcBox.front = 0;
-    srcBox.right = aSourcePoint.x + aRect.width;
-    srcBox.bottom = aSourcePoint.y + aRect.height;
-    srcBox.back = 1;
-
     const IntSize& srcSize = sourceD3D11->GetSize();
     MOZ_ASSERT(srcSize.width >= 0 && srcSize.height >= 0,
                "render targets should have nonnegative sizes");
-    if (srcBox.left < srcBox.right &&
-        srcBox.top < srcBox.bottom &&
-        srcBox.right <= static_cast<uint32_t>(srcSize.width) &&
-        srcBox.bottom <= static_cast<uint32_t>(srcSize.height)) {
+
+    IntRect srcRect(IntPoint(), srcSize);
+    IntRect copyRect(aSourcePoint, aRect.Size());
+    if (!srcRect.Contains(copyRect)) {
+      NS_WARNING("Could not copy the whole copy rect from the render target");
+    }
+
+    copyRect = copyRect.Intersect(srcRect);
+
+    if (!copyRect.IsEmpty()) {
+      D3D11_BOX copyBox;
+      copyBox.front = 0;
+      copyBox.back = 1;
+      copyBox.left = copyRect.x;
+      copyBox.top = copyRect.y;
+      copyBox.right = copyRect.XMost();
+      copyBox.bottom = copyRect.YMost();
+
       mContext->CopySubresourceRegion(texture, 0,
                                       0, 0, 0,
                                       sourceD3D11->GetD3D11Texture(), 0,
-                                      &srcBox);
-    } else {
-      NS_WARNING("Could not copy render target - source rect out of bounds");
+                                      &copyBox);
     }
   }
 
   return texture;
 }
 
 already_AddRefed<CompositingRenderTarget>
 CompositorD3D11::CreateRenderTargetFromSource(const gfx::IntRect &aRect,
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -254,16 +254,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
         'ipc/ShadowLayerUtilsGralloc.cpp',
     ]
 
 UNIFIED_SOURCES += [
     'apz/src/APZCTreeManager.cpp',
     'apz/src/AsyncPanZoomController.cpp',
     'apz/src/Axis.cpp',
     'apz/src/CheckerboardEvent.cpp',
+    'apz/src/DragTracker.cpp',
     'apz/src/GestureEventListener.cpp',
     'apz/src/HitTestingTreeNode.cpp',
     'apz/src/InputBlockState.cpp',
     'apz/src/InputQueue.cpp',
     'apz/src/OverscrollHandoffState.cpp',
     'apz/src/PotentialCheckerboardDurationTracker.cpp',
     'apz/src/TouchCounter.cpp',
     'apz/src/WheelScrollAnimation.cpp',
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -427,17 +427,18 @@ private:
   DECL_GFX_PREF(Live, "webgl.angle.force-d3d11",               WebGLANGLEForceD3D11, bool, false);
   DECL_GFX_PREF(Live, "webgl.angle.try-d3d11",                 WebGLANGLETryD3D11, bool, false);
   DECL_GFX_PREF(Once, "webgl.angle.force-warp",                WebGLANGLEForceWARP, bool, false);
   DECL_GFX_PREF(Live, "webgl.bypass-shader-validation",        WebGLBypassShaderValidator, bool, true);
   DECL_GFX_PREF(Live, "webgl.can-lose-context-in-foreground",  WebGLCanLoseContextInForeground, bool, true);
   DECL_GFX_PREF(Live, "webgl.default-no-alpha",                WebGLDefaultNoAlpha, bool, false);
   DECL_GFX_PREF(Live, "webgl.disable-angle",                   WebGLDisableANGLE, bool, false);
   DECL_GFX_PREF(Live, "webgl.disable-extensions",              WebGLDisableExtensions, bool, false);
-  DECL_GFX_PREF(Once, "webgl.dxgl.enabled",                    WebGLDXGLEnabled, bool, false);
+  DECL_GFX_PREF(Live, "webgl.dxgl.enabled",                    WebGLDXGLEnabled, bool, false);
+  DECL_GFX_PREF(Live, "webgl.dxgl.needs-finish",               WebGLDXGLNeedsFinish, bool, false);
 
   DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat",
                 WebGLDisableFailIfMajorPerformanceCaveat, bool, false);
   DECL_GFX_PREF(Live, "webgl.disable-DOM-blit-uploads",
                 WebGLDisableDOMBlitUploads, bool, false);
 
   DECL_GFX_PREF(Live, "webgl.disabled",                        WebGLDisabled, bool, false);
 
--- a/image/decoders/nsIconDecoder.cpp
+++ b/image/decoders/nsIconDecoder.cpp
@@ -1,38 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIconDecoder.h"
-#include "nsIInputStream.h"
-#include "nspr.h"
-#include "nsRect.h"
-#include "nsError.h"
 #include "RasterImage.h"
-#include <algorithm>
+#include "SurfacePipeFactory.h"
 
 using namespace mozilla::gfx;
 
-using std::min;
-
 namespace mozilla {
 namespace image {
 
 static const uint32_t ICON_HEADER_SIZE = 2;
 
 nsIconDecoder::nsIconDecoder(RasterImage* aImage)
  : Decoder(aImage)
  , mLexer(Transition::To(State::HEADER, ICON_HEADER_SIZE))
- , mWidth()         // set by ReadHeader()
- , mHeight()        // set by ReadHeader()
  , mBytesPerRow()   // set by ReadHeader()
- , mCurrentRow(0)
 {
   // Nothing to do
 }
 
 nsIconDecoder::~nsIconDecoder()
 { }
 
 void
@@ -61,76 +52,80 @@ nsIconDecoder::WriteInternal(const char*
     PostDataError();
   }
 }
 
 LexerTransition<nsIconDecoder::State>
 nsIconDecoder::ReadHeader(const char* aData)
 {
   // Grab the width and height.
-  mWidth  = uint8_t(aData[0]);
-  mHeight = uint8_t(aData[1]);
+  uint8_t width  = uint8_t(aData[0]);
+  uint8_t height = uint8_t(aData[1]);
 
   // The input is 32bpp, so we expect 4 bytes of data per pixel.
-  mBytesPerRow = mWidth * 4;
+  mBytesPerRow = width * 4;
 
   // Post our size to the superclass.
-  PostSize(mWidth, mHeight);
+  PostSize(width, height);
 
   // Icons have alpha.
   PostHasTransparency();
 
   // If we're doing a metadata decode, we're done.
   if (IsMetadataDecode()) {
     return Transition::TerminateSuccess();
   }
 
   MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
   IntSize targetSize = mDownscaler ? mDownscaler->TargetSize() : GetSize();
-  nsresult rv = AllocateFrame(0, targetSize,
-                              IntRect(IntPoint(), targetSize),
-                              gfx::SurfaceFormat::B8G8R8A8);
-  if (NS_FAILED(rv)) {
+  IntRect targetFrameRect(IntPoint(0, 0), targetSize);
+
+  Maybe<SurfacePipe> pipe =
+    SurfacePipeFactory::CreateSurfacePipe(this, 0, GetSize(), targetSize,
+                                          targetFrameRect, SurfaceFormat::B8G8R8A8,
+                                          SurfacePipeFlags());
+  if (!pipe) {
     return Transition::TerminateFailure();
   }
-  MOZ_ASSERT(mImageData, "Should have a buffer now");
 
-  if (mDownscaler) {
-    nsresult rv = mDownscaler->BeginFrame(GetSize(), Nothing(),
-                                          mImageData, /* aHasAlpha = */ true);
-    if (NS_FAILED(rv)) {
-      return Transition::TerminateFailure();
-    }
-  }
+  mPipe = Move(*pipe);
+
+  MOZ_ASSERT(mImageData, "Should have a buffer now");
 
   return Transition::To(State::ROW_OF_PIXELS, mBytesPerRow);
 }
 
 LexerTransition<nsIconDecoder::State>
 nsIconDecoder::ReadRowOfPixels(const char* aData, size_t aLength)
 {
-  if (mDownscaler) {
-    memcpy(mDownscaler->RowBuffer(), aData, mBytesPerRow);
-    mDownscaler->CommitRow();
+  MOZ_ASSERT(aLength % 4 == 0, "Rows should contain a multiple of four bytes");
 
-    if (mDownscaler->HasInvalidation()) {
-      DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
-      PostInvalidation(invalidRect.mOriginalSizeRect,
-                       Some(invalidRect.mTargetSizeRect));
+  auto result = mPipe.WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
+    if (aLength == 0) {
+      return AsVariant(WriteState::NEED_MORE_DATA);  // Done with this row.
     }
-  } else {
-    memcpy(mImageData + mCurrentRow * mBytesPerRow, aData, mBytesPerRow);
+
+    uint32_t pixel = *reinterpret_cast<const uint32_t*>(aData);
+    aData += 4;
+    aLength -= 4;
 
-    PostInvalidation(IntRect(0, mCurrentRow, mWidth, 1));
+    return AsVariant(pixel);
+  });
+
+  MOZ_ASSERT(result != WriteState::FAILURE);
+
+  Maybe<SurfaceInvalidRect> invalidRect = mPipe.TakeInvalidRect();
+  if (invalidRect) {
+    PostInvalidation(invalidRect->mInputSpaceRect,
+                     Some(invalidRect->mOutputSpaceRect));
   }
-  mCurrentRow++;
 
-  return (mCurrentRow < mHeight)
-       ? Transition::To(State::ROW_OF_PIXELS, mBytesPerRow)
-       : Transition::To(State::FINISH, 0);
+  return result == WriteState::FINISHED
+       ? Transition::To(State::FINISH, 0)
+       : Transition::To(State::ROW_OF_PIXELS, mBytesPerRow);
 }
 
 LexerTransition<nsIconDecoder::State>
 nsIconDecoder::Finish()
 {
   PostFrameStop();
   PostDecodeDone();
 
--- a/image/decoders/nsIconDecoder.h
+++ b/image/decoders/nsIconDecoder.h
@@ -4,38 +4,36 @@
  * 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_image_decoders_nsIconDecoder_h
 #define mozilla_image_decoders_nsIconDecoder_h
 
 #include "Decoder.h"
 #include "StreamingLexer.h"
-#include "nsCOMPtr.h"
+#include "SurfacePipe.h"
 
 namespace mozilla {
 namespace image {
+
 class RasterImage;
 
 ////////////////////////////////////////////////////////////////////////////////
 // The icon decoder is a decoder specifically tailored for loading icons
 // from the OS. We've defined our own little format to represent these icons
 // and this decoder takes that format and converts it into 24-bit RGB with
 // alpha channel support. It was modeled a bit off the PPM decoder.
 //
-// Assumptions about the decoder:
-// (1) We receive ALL of the data from the icon channel in one OnDataAvailable
-//     call. We don't support multiple ODA calls yet.
-// (2) the format of the incoming data is as follows:
-//     The first two bytes contain the width and the height of the icon.
-//     The remaining bytes contain the icon data, 4 bytes per pixel, in
-//       ARGB order (platform endianness, A in highest bits, B in lowest
-//       bits), row-primary, top-to-bottom, left-to-right, with
-//       premultiplied alpha.
+// The format of the incoming data is as follows:
 //
+// The first two bytes contain the width and the height of the icon.
+// The remaining bytes contain the icon data, 4 bytes per pixel, in
+// ARGB order (platform endianness, A in highest bits, B in lowest
+// bits), row-primary, top-to-bottom, left-to-right, with
+// premultiplied alpha.
 //
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsIconDecoder : public Decoder
 {
 public:
   virtual ~nsIconDecoder();
 
@@ -53,19 +51,16 @@ private:
     FINISH
   };
 
   LexerTransition<State> ReadHeader(const char* aData);
   LexerTransition<State> ReadRowOfPixels(const char* aData, size_t aLength);
   LexerTransition<State> Finish();
 
   StreamingLexer<State> mLexer;
-  uint8_t mWidth;
-  uint8_t mHeight;
+  SurfacePipe mPipe;
   uint32_t mBytesPerRow;
-  uint32_t mBytesTotal;
-  uint32_t mCurrentRow;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // mozilla_image_decoders_nsIconDecoder_h
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -432,44 +432,29 @@ bool Pickle::ReadString(void** iter, std
 bool Pickle::ReadWString(void** iter, std::wstring* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   int len;
   if (!ReadLength(iter, &len))
     return false;
+  // Avoid integer multiplication overflow.
+  if (len > INT_MAX / static_cast<int>(sizeof(wchar_t)))
+    return false;
   if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
     return false;
 
   wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
   result->assign(chars, len);
 
   UpdateIter(iter, len * sizeof(wchar_t));
   return true;
 }
 
-bool Pickle::ReadString16(void** iter, string16* result) const {
-  DCHECK(iter);
-  if (!*iter)
-    *iter = const_cast<char*>(payload());
-
-  int len;
-  if (!ReadLength(iter, &len))
-    return false;
-  if (!IteratorHasRoomFor(*iter, len))
-    return false;
-
-  char16* chars = reinterpret_cast<char16*>(*iter);
-  result->assign(chars, len);
-
-  UpdateIter(iter, len * sizeof(char16));
-  return true;
-}
-
 bool Pickle::ReadBytes(void** iter, const char** data, int length,
                        uint32_t alignment) const {
   DCHECK(iter);
   DCHECK(data);
   DCHECK(alignment == 4 || alignment == 8);
   DCHECK(intptr_t(header_) % alignment == 0);
 
   if (!*iter)
@@ -585,24 +570,16 @@ bool Pickle::WriteString(const std::stri
 bool Pickle::WriteWString(const std::wstring& value) {
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(),
                     static_cast<int>(value.size() * sizeof(wchar_t)));
 }
 
-bool Pickle::WriteString16(const string16& value) {
-  if (!WriteInt(static_cast<int>(value.size())))
-    return false;
-
-  return WriteBytes(value.data(),
-                    static_cast<int>(value.size()) * sizeof(char16));
-}
-
 bool Pickle::WriteData(const char* data, int length) {
   return WriteInt(length) && WriteBytes(data, length);
 }
 
 char* Pickle::BeginWriteData(int length) {
   DCHECK_EQ(variable_buffer_offset_, 0U) <<
     "There can only be one variable buffer in a Pickle";
 
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -81,17 +81,16 @@ class Pickle {
   MOZ_WARN_UNUSED_RESULT bool ReadUInt32(void** iter, uint32_t* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadInt64(void** iter, int64_t* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadUInt64(void** iter, uint64_t* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadDouble(void** iter, double* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadIntPtr(void** iter, intptr_t* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadUnsignedChar(void** iter, unsigned char* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadString(void** iter, std::string* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadWString(void** iter, std::wstring* result) const;
-  MOZ_WARN_UNUSED_RESULT bool ReadString16(void** iter, string16* result) const;
   MOZ_WARN_UNUSED_RESULT bool ReadData(void** iter, const char** data, int* length) const;
   MOZ_WARN_UNUSED_RESULT bool ReadBytes(void** iter, const char** data, int length,
 					uint32_t alignment = sizeof(memberAlignmentType)) const;
 
   // Safer version of ReadInt() checks for the result not being negative.
   // Use it for reading the object sizes.
   MOZ_WARN_UNUSED_RESULT bool ReadLength(void** iter, int* result) const;
 
@@ -146,17 +145,16 @@ class Pickle {
     // differ between architectures.
     return WriteInt64(int64_t(value));
   }
   bool WriteUnsignedChar(unsigned char value) {
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteString(const std::string& value);
   bool WriteWString(const std::wstring& value);
-  bool WriteString16(const string16& value);
   bool WriteData(const char* data, int length);
   bool WriteBytes(const void* data, int data_len,
                   uint32_t alignment = sizeof(memberAlignmentType));
 
   // Same as WriteData, but allows the caller to write directly into the
   // Pickle. This saves a copy in cases where the data is not already
   // available in a buffer. The caller should take care to not write more
   // than the length it declares it will. Use ReadData to get the data.
--- a/ipc/chromium/src/base/process_util.h
+++ b/ipc/chromium/src/base/process_util.h
@@ -107,20 +107,23 @@ ProcessId GetCurrentProcId();
 // Returns the ProcessHandle of the current process.
 ProcessHandle GetCurrentProcessHandle();
 
 // Converts a PID to a process handle. This handle must be closed by
 // CloseProcessHandle when you are done with it. Returns true on success.
 bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
 
 // Converts a PID to a process handle. On Windows the handle is opened
-// with more access rights and must only be used by trusted code.
+// with more access rights and must only be used by trusted code. Parameter
+// error can be used to get the error code in opening the process handle.
 // You have to close returned handle using CloseProcessHandle. Returns true
 // on success.
-bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle);
+bool OpenPrivilegedProcessHandle(ProcessId pid,
+                                 ProcessHandle* handle,
+                                 int64_t* error = nullptr);
 
 // Closes the process handle opened by OpenProcessHandle.
 void CloseProcessHandle(ProcessHandle process);
 
 // Returns the unique ID for the specified process. This is functionally the
 // same as Windows' GetProcessId(), but works on versions of Windows before
 // Win XP SP1 as well.
 ProcessId GetProcId(ProcessHandle process);
--- a/ipc/chromium/src/base/process_util_posix.cc
+++ b/ipc/chromium/src/base/process_util_posix.cc
@@ -43,19 +43,24 @@ ProcessHandle GetCurrentProcessHandle() 
 
 bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
   // On Posix platforms, process handles are the same as PIDs, so we
   // don't need to do anything.
   *handle = pid;
   return true;
 }
 
-bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
+bool OpenPrivilegedProcessHandle(ProcessId pid,
+                                 ProcessHandle* handle,
+                                 int64_t* error) {
   // On POSIX permissions are checked for each operation on process,
   // not when opening a "handle".
+  if (error) {
+    *error = 0;
+  }
   return OpenProcessHandle(pid, handle);
 }
 
 void CloseProcessHandle(ProcessHandle process) {
   // See OpenProcessHandle, nothing to do.
   return;
 }
 
--- a/ipc/chromium/src/base/process_util_win.cc
+++ b/ipc/chromium/src/base/process_util_win.cc
@@ -79,25 +79,30 @@ bool OpenProcessHandle(ProcessId pid, Pr
   if (result == NULL) {
     return false;
   }
 
   *handle = result;
   return true;
 }
 
-bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
+bool OpenPrivilegedProcessHandle(ProcessId pid,
+                                 ProcessHandle* handle,
+                                 int64_t* error) {
   ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
                                          PROCESS_TERMINATE |
                                          PROCESS_QUERY_INFORMATION |
                                          PROCESS_VM_READ |
                                          SYNCHRONIZE,
                                      FALSE, pid);
 
   if (result == NULL) {
+    if (error) {
+      *error = GetLastError();
+    }
     return false;
   }
 
   *handle = result;
   return true;
 }
 
 void CloseProcessHandle(ProcessHandle process) {
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -21,16 +21,17 @@
 #include "mozilla/Snprintf.h"
 #include "prenv.h"
 #include "nsXPCOMPrivate.h"
 
 #include "nsExceptionHandler.h"
 
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
+#include "nsPrintfCString.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/Omnijar.h"
 #include "ProtocolUtils.h"
 #include <sys/stat.h>
 
 #ifdef XP_WIN
@@ -1082,17 +1083,23 @@ GeckoChildProcessHost::PerformAsyncLaunc
 
 void
 GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid)
 {
   if (mChildProcessHandle) {
     MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
     return;
   }
-  if (!base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle)) {
+  int64_t error = 0;
+  if (!base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle, &error)) {
+#ifdef MOZ_CRASHREPORTER
+    CrashReporter::
+      AnnotateCrashReport(NS_LITERAL_CSTRING("LastError"),
+                          nsPrintfCString ("%lld", error));
+#endif
     NS_RUNTIMEABORT("can't open handle to child process");
   }
 }
 
 void
 GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid)
 {
   OpenPrivilegedHandle(peer_pid);
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -13,8 +13,58 @@ def js_shell_default(build_project, help
 
 js_option('--disable-js-shell', default=js_shell_default,
        help='Do not build the JS shell')
 
 @depends('--disable-js-shell')
 def js_shell(value):
     if not value:
         set_config('JS_DISABLE_SHELL', '1')
+
+
+# SpiderMonkey as a shared library, and how its symbols are exported
+# ==================================================================
+@depends(build_project, '--help')
+def js_shared_default(build_project, help):
+    return build_project == 'js'
+
+js_option('--disable-shared-js', default=js_shared_default,
+          help='Do not create a shared library')
+
+js_option('--disable-export-js', default=js_shared_default,
+          help='Do not mark JS symbols as DLL exported/visible')
+
+@depends('--disable-shared-js', '--disable-export-js')
+def static_js(shared_js, export_js):
+    if shared_js:
+        if not export_js:
+            error('Must export JS symbols when building a shared library.')
+        set_config('JS_SHARED_LIBRARY', '1')
+        add_old_configure_assignment('JS_SHARED_LIBRARY', '1')
+    else:
+        if export_js:
+            set_define('STATIC_EXPORTABLE_JS_API', '1')
+        else:
+            set_define('STATIC_JS_API', '1')
+        set_define('MOZ_STATIC_JS', '1')
+
+
+@deprecated_option(env='DISABLE_SHARED_JS', nargs='?')
+def disable_shared_js(value):
+    # DISABLE_SHARED_JS=1 gets us an empty PositiveOptionValue
+    if value and not len(value):
+        suggestion = '--disable-shared-js'
+    else:
+        suggestion = '--enable-shared-js'
+
+    error('Setting %s is deprecated, use %s instead.'
+          % (value.format('DISABLE_SHARED_JS'), suggestion))
+
+@deprecated_option(env='DISABLE_EXPORT_JS', nargs='?')
+def disable_export_js(value):
+    # DISABLE_EXPORT_JS=1 gets us an empty PositiveOptionValue
+    if value and not len(value):
+        suggestion = '--disable-export-js'
+    else:
+        suggestion = '--enable-export-js'
+
+    error('Setting %s is deprecated, use %s instead.'
+          % (value.format('DISABLE_EXPORT_JS'), suggestion))
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -5539,17 +5539,17 @@ CheckPos(FunctionValidator& f, ParseNode
 }
 
 static bool
 CheckNot(FunctionValidator& f, ParseNode* expr, Type* type)
 {
     MOZ_ASSERT(expr->isKind(PNK_NOT));
     ParseNode* operand = UnaryKid(expr);
 
-    if (!f.encoder().writeExpr(Expr::I32Not))
+    if (!f.encoder().writeExpr(Expr::I32Eqz))
         return false;
 
     Type operandType;
     if (!CheckExpr(f, operand, &operandType))
         return false;
 
     if (!operandType.isInt())
         return f.failf(operand, "%s is not a subtype of int", operandType.toChars());
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -633,20 +633,22 @@ DecodeExpr(FunctionDecoder& f, ExprType*
         return DecodeBlock(f, /* isLoop */ true, type);
       case Expr::If:
         return DecodeIfElse(f, /* hasElse */ false, type);
       case Expr::IfElse:
         return DecodeIfElse(f, /* hasElse */ true, type);
       case Expr::I32Clz:
       case Expr::I32Ctz:
       case Expr::I32Popcnt:
+      case Expr::I32Eqz:
         return DecodeUnaryOperator(f, ValType::I32, type);
       case Expr::I64Clz:
       case Expr::I64Ctz:
       case Expr::I64Popcnt:
+      case Expr::I64Eqz:
         return f.fail("NYI: i64") &&
                DecodeUnaryOperator(f, ValType::I64, type);
       case Expr::F32Abs:
       case Expr::F32Neg:
       case Expr::F32Ceil:
       case Expr::F32Floor:
       case Expr::F32Sqrt:
         return DecodeUnaryOperator(f, ValType::F32, type);
@@ -673,30 +675,36 @@ DecodeExpr(FunctionDecoder& f, ExprType*
       case Expr::I32RemU:
       case Expr::I32And:
       case Expr::I32Or:
       case Expr::I32Xor:
       case Expr::I32Shl:
       case Expr::I32ShrS:
       case Expr::I32ShrU:
         return DecodeBinaryOperator(f, ValType::I32, type);
+      case Expr::I32Rotl:
+      case Expr::I32Rotr:
+        return f.fail("NYI: rotate");
       case Expr::I64Add:
       case Expr::I64Sub:
       case Expr::I64Mul:
       case Expr::I64DivS:
       case Expr::I64DivU:
       case Expr::I64RemS:
       case Expr::I64RemU:
       case Expr::I64And:
       case Expr::I64Or:
       case Expr::I64Xor:
       case Expr::I64Shl:
       case Expr::I64ShrS:
       case Expr::I64ShrU:
         return DecodeBinaryOperator(f, ValType::I64, type);
+      case Expr::I64Rotl:
+      case Expr::I64Rotr:
+        return f.fail("NYI: rotate");
       case Expr::F32Add:
       case Expr::F32Sub:
       case Expr::F32Mul:
       case Expr::F32Div:
       case Expr::F32Min:
       case Expr::F32Max:
         return DecodeBinaryOperator(f, ValType::F32, type);
       case Expr::F32CopySign:
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -132,16 +132,17 @@ enum class Expr
     I32LeU                               = 0x52,
     I32GtS                               = 0x53,
     I32GeS                               = 0x54,
     I32GtU                               = 0x55,
     I32GeU                               = 0x56,
     I32Clz                               = 0x57,
     I32Ctz                               = 0x58,
     I32Popcnt                            = 0x59,
+    I32Eqz                               = 0x5a,
 
     // i64 operators
     I64Add                               = 0x5b,
     I64Sub                               = 0x5c,
     I64Mul                               = 0x5d,
     I64DivS                              = 0x5e,
     I64DivU                              = 0x5f,
     I64RemS                              = 0x60,
@@ -232,27 +233,35 @@ enum class Expr
     F64ConvertUI32                       = 0xaf,
     F64ConvertSI64                       = 0xb0,
     F64ConvertUI64                       = 0xb1,
     F64PromoteF32                        = 0xb2,
     F64ReinterpretI64                    = 0xb3,
     I32ReinterpretF32                    = 0xb4,
     I64ReinterpretF64                    = 0xb5,
 
+    // Bitwise rotates.
+    I32Rotr                              = 0xb6,
+    I32Rotl                              = 0xb7,
+    I64Rotr                              = 0xb8,
+    I64Rotl                              = 0xb9,
+
+    // i64.eqz.
+    I64Eqz                               = 0xba,
+
     // ------------------------------------------------------------------------
     // The rest of these operators are currently only emitted internally when
     // compiling asm.js and are rejected by wasm validation.
 
     // asm.js-specific operators
     Id                                   = 0xc0,
     LoadGlobal,
     StoreGlobal,
     I32Min,
     I32Max,
-    I32Not,
     I32Neg,
     I32BitNot,
     I32Abs,
     F32StoreF64,
     F64StoreF32,
     F64Mod,
     F64Sin,
     F64Cos,
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -2734,17 +2734,17 @@ EmitExpr(FunctionCompiler& f, MDefinitio
         return EmitDivOrMod(f, ValType::I32, IsDiv(true), IsUnsigned(op == Expr::I32DivU), def);
       case Expr::I32RemS:
       case Expr::I32RemU:
         return EmitDivOrMod(f, ValType::I32, IsDiv(false), IsUnsigned(op == Expr::I32RemU), def);
       case Expr::I32Min:
         return EmitMathMinMax(f, ValType::I32, IsMax(false), def);
       case Expr::I32Max:
         return EmitMathMinMax(f, ValType::I32, IsMax(true), def);
-      case Expr::I32Not:
+      case Expr::I32Eqz:
         return EmitUnary<MNot>(f, def);
       case Expr::I32TruncSF32:
       case Expr::I32TruncUF32:
         return EmitUnary<MTruncateToInt32>(f, def);
       case Expr::I32TruncSF64:
       case Expr::I32TruncUF64:
         return EmitUnary<MTruncateToInt32>(f, def);
       case Expr::I32WrapI64:
@@ -3031,16 +3031,21 @@ EmitExpr(FunctionCompiler& f, MDefinitio
       case Expr::I64Load:
       case Expr::I64Store8:
       case Expr::I64Store16:
       case Expr::I64Store32:
       case Expr::I64Store:
       case Expr::I64Clz:
       case Expr::I64Ctz:
       case Expr::I64Popcnt:
+      case Expr::I64Eqz:
+      case Expr::I32Rotr:
+      case Expr::I32Rotl:
+      case Expr::I64Rotr:
+      case Expr::I64Rotl:
       case Expr::MemorySize:
       case Expr::GrowMemory:
       case Expr::Unreachable:
         MOZ_CRASH("NYI");
         break;
       case Expr::Limit:;
     }
 
--- a/js/src/asmjs/WasmText.cpp
+++ b/js/src/asmjs/WasmText.cpp
@@ -1611,16 +1611,18 @@ WasmTokenStream::next()
                 break;
               case 'd':
                 if (consume(MOZ_UTF16("div_s")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I32DivS, begin, cur_);
                 if (consume(MOZ_UTF16("div_u")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I32DivU, begin, cur_);
                 break;
               case 'e':
+                if (consume(MOZ_UTF16("eqz")))
+                    return WasmToken(WasmToken::UnaryOpcode, Expr::I32Eqz, begin, cur_);
                 if (consume(MOZ_UTF16("eq")))
                     return WasmToken(WasmToken::ComparisonOpcode, Expr::I32Eq, begin, cur_);
                 break;
               case 'g':
                 if (consume(MOZ_UTF16("ge_s")))
                     return WasmToken(WasmToken::ComparisonOpcode, Expr::I32GeS, begin, cur_);
                 if (consume(MOZ_UTF16("ge_u")))
                     return WasmToken(WasmToken::ComparisonOpcode, Expr::I32GeU, begin, cur_);
@@ -1671,16 +1673,20 @@ WasmTokenStream::next()
               case 'r':
                 if (consume(MOZ_UTF16("reinterpret/f32")))
                     return WasmToken(WasmToken::UnaryOpcode, Expr::I32ReinterpretF32,
                                      begin, cur_);
                 if (consume(MOZ_UTF16("rem_s")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemS, begin, cur_);
                 if (consume(MOZ_UTF16("rem_u")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I32RemU, begin, cur_);
+                if (consume(MOZ_UTF16("rotr")))
+                    return WasmToken(WasmToken::BinaryOpcode, Expr::I32Rotr, begin, cur_);
+                if (consume(MOZ_UTF16("rotl")))
+                    return WasmToken(WasmToken::BinaryOpcode, Expr::I32Rotl, begin, cur_);
                 break;
               case 's':
                 if (consume(MOZ_UTF16("sub")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I32Sub, begin, cur_);
                 if (consume(MOZ_UTF16("shl")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I32Shl, begin, cur_);
                 if (consume(MOZ_UTF16("shr_s")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I32ShrS, begin, cur_);
@@ -1743,16 +1749,18 @@ WasmTokenStream::next()
                 break;
               case 'd':
                 if (consume(MOZ_UTF16("div_s")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I64DivS, begin, cur_);
                 if (consume(MOZ_UTF16("div_u")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I64DivU, begin, cur_);
                 break;
               case 'e':
+                if (consume(MOZ_UTF16("eqz")))
+                    return WasmToken(WasmToken::UnaryOpcode, Expr::I64Eqz, begin, cur_);
                 if (consume(MOZ_UTF16("eq")))
                     return WasmToken(WasmToken::ComparisonOpcode, Expr::I64Eq, begin, cur_);
                 if (consume(MOZ_UTF16("extend_s/i32")))
                     return WasmToken(WasmToken::ConversionOpcode, Expr::I64ExtendSI32,
                                      begin, cur_);
                 if (consume(MOZ_UTF16("extend_u/i32")))
                     return WasmToken(WasmToken::ConversionOpcode, Expr::I64ExtendUI32,
                                      begin, cur_);
@@ -1813,16 +1821,20 @@ WasmTokenStream::next()
               case 'r':
                 if (consume(MOZ_UTF16("reinterpret/f64")))
                     return WasmToken(WasmToken::UnaryOpcode, Expr::I64ReinterpretF64,
                                      begin, cur_);
                 if (consume(MOZ_UTF16("rem_s")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I64RemS, begin, cur_);
                 if (consume(MOZ_UTF16("rem_u")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I64RemU, begin, cur_);
+                if (consume(MOZ_UTF16("rotr")))
+                    return WasmToken(WasmToken::BinaryOpcode, Expr::I64Rotr, begin, cur_);
+                if (consume(MOZ_UTF16("rotl")))
+                    return WasmToken(WasmToken::BinaryOpcode, Expr::I64Rotl, begin, cur_);
                 break;
               case 's':
                 if (consume(MOZ_UTF16("sub")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I64Sub, begin, cur_);
                 if (consume(MOZ_UTF16("shl")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I64Shl, begin, cur_);
                 if (consume(MOZ_UTF16("shr_s")))
                     return WasmToken(WasmToken::BinaryOpcode, Expr::I64ShrS, begin, cur_);
--- a/js/src/devtools/automation/autospider.sh
+++ b/js/src/devtools/automation/autospider.sh
@@ -81,17 +81,17 @@ USE_64BIT=false
 if [[ "$OSTYPE" == darwin* ]]; then
   USE_64BIT=true
   if [ "$VARIANT" = "arm-sim-osx" ]; then
     USE_64BIT=false
   fi
   source "$ABSDIR/macbuildenv.sh"
 elif [ "$OSTYPE" = "linux-gnu" ]; then
   if [ -n "$AUTOMATION" ]; then
-      GCCDIR="${GCCDIR:-/tools/gcc-4.7.2-0moz1}"
+      GCCDIR="${GCCDIR:-$SOURCE/../gcc}"
       CONFIGURE_ARGS="$CONFIGURE_ARGS --with-ccache"
   fi
   UNAME_M=$(uname -m)
   MAKEFLAGS=-j4
   if [ "$VARIANT" = "arm-sim" ]; then
     USE_64BIT=false
   elif [ "$VARIANT" = "arm64-sim" ]; then
     USE_64BIT=true
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3940,27 +3940,32 @@ Parser<ParseHandler>::AutoPushStmtInfoPC
 template <typename ParseHandler>
 Parser<ParseHandler>::PossibleError::PossibleError(Parser<ParseHandler>& parser)
                                                    : parser_(parser)
 {
     state_ = ErrorState::None;
 }
 
 template <typename ParseHandler>
-void
+bool
 Parser<ParseHandler>::PossibleError::setPending(ParseReportKind kind, unsigned errorNumber,
                                                 bool strict)
 {
+    if (hasError())
+        return false;
+
     // If we report an error later, we'll do it from the position where we set
     // the state to pending.
     offset_      = parser_.pos().begin;
     reportKind_  = kind;
     strict_      = strict;
     errorNumber_ = errorNumber;
     state_       = ErrorState::Pending;
+
+    return true;
 }
 
 template <typename ParseHandler>
 void
 Parser<ParseHandler>::PossibleError::setResolved()
 {
     state_ = ErrorState::None;
 }
@@ -3972,19 +3977,18 @@ Parser<ParseHandler>::PossibleError::has
     return state_ == ErrorState::Pending;
 }
 
 template <typename ParseHandler>
 bool
 Parser<ParseHandler>::PossibleError::checkForExprErrors()
 {
     bool err = hasError();
-    if (err) {
+    if (err)
         parser_.reportWithOffset(reportKind_, strict_, offset_, errorNumber_);
-    }
     return !err;
 }
 
 template <typename ParseHandler>
 void
 Parser<ParseHandler>::PossibleError::transferErrorTo(PossibleError* other)
 {
     if (other) {
@@ -7823,17 +7827,16 @@ Parser<ParseHandler>::checkAndMarkAsAssi
 template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandling,
                                  TripledotHandling tripledotHandling,
                                  PossibleError* possibleError,
                                  InvokedPrediction invoked)
 {
     JS_CHECK_RECURSION(context, return null());
-    MOZ_ASSERT(!possibleError->hasError());
 
     // It's very common at this point to have a "detectably simple" expression,
     // i.e. a name/number/string token followed by one of the following tokens
     // that obviously isn't part of an expression: , ; : ) ] }
     //
     // (In Parsemark this happens 81.4% of the time;  in code with large
     // numeric arrays, such as some Kraken benchmarks, it happens more often.)
     //
@@ -9305,18 +9308,23 @@ Parser<ParseHandler>::objectLiteral(Yiel
                 return null();
 
             if (!seenCoverInitializedName) {
                 seenCoverInitializedName = true;
                 // "shorthand default" or "CoverInitializedName" syntax is only
                 // valid in the case of destructuring. Here we set a pending error so
                 // that later in the parse, once we've determined whether or not we're
                 // destructuring, the error can be reported or ignored appropriately.
-                if (possibleError)
-                    possibleError->setPending(ParseError, JSMSG_BAD_PROP_ID, false);
+                if (possibleError &&
+                    !possibleError->setPending(ParseError, JSMSG_BAD_PROP_ID, false)) {
+
+                    // Report any previously pending error.
+                    possibleError->checkForExprErrors();
+                    return null();
+                }
             }
 
         } else {
             // FIXME: Implement ES6 function "name" property semantics
             // (bug 883377).
             RootedPropertyName funName(context);
             switch (propType) {
               case PropertyType::Getter:
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -457,18 +457,19 @@ class Parser : private JS::AutoGCRooter,
         unsigned errorNumber_;
         ParseReportKind reportKind_;
         Parser<ParseHandler>& parser_;
         bool strict_;
 
         public:
           explicit PossibleError(Parser<ParseHandler>& parser);
 
-          // Set a pending error.
-          void setPending(ParseReportKind kind, unsigned errorNumber, bool strict);
+          // Set a pending error. Only a single error may be set per instance.
+          // Returns true on success or false on failure.
+          bool setPending(ParseReportKind kind, unsigned errorNumber, bool strict);
 
           // Resolve any pending error.
           void setResolved();
 
           // Return true if an error is pending without reporting
           bool hasError();
 
           // If there is a pending error report it and return false, otherwise return
--- a/js/src/gdb/moz.build
+++ b/js/src/gdb/moz.build
@@ -13,16 +13,17 @@ UNIFIED_SOURCES += [
     'tests/test-Interpreter.cpp',
     'tests/test-jsid.cpp',
     'tests/test-JSObject.cpp',
     'tests/test-JSString.cpp',
     'tests/test-JSSymbol.cpp',
     'tests/test-jsval.cpp',
     'tests/test-prettyprinters.cpp',
     'tests/test-Root.cpp',
+    'tests/test-unwind.cpp',
     'tests/typedef-printers.cpp',
 ]
 
 DEFINES['EXPORT_JS_API'] = True
 
 LOCAL_INCLUDES += [
     '!..',
     '..',
--- a/js/src/gdb/mozilla/autoload.py
+++ b/js/src/gdb/mozilla/autoload.py
@@ -11,20 +11,22 @@ import mozilla.prettyprinters
 import mozilla.GCCellPtr
 import mozilla.Interpreter
 import mozilla.JSObject
 import mozilla.JSString
 import mozilla.JSSymbol
 import mozilla.Root
 import mozilla.jsid
 import mozilla.jsval
+import mozilla.unwind
 
 # The user may have personal pretty-printers. Get those, too, if they exist.
 try:
     import my_mozilla_printers
 except ImportError:
     pass
 
 # Register our pretty-printers with |objfile|.
 def register(objfile):
     lookup = mozilla.prettyprinters.lookup_for_objfile(objfile)
     if lookup:
         gdb.printing.register_pretty_printer(objfile, lookup, replace=True)
+    mozilla.unwind.register_unwinder(objfile)
new file mode 100644
--- /dev/null
+++ b/js/src/gdb/mozilla/unwind.py
@@ -0,0 +1,436 @@
+# mozilla/unwind.py --- unwinder and frame filter for SpiderMonkey
+
+import gdb
+from gdb.FrameDecorator import FrameDecorator
+import re
+import platform
+
+# For ease of use in Python 2, we use "long" instead of "int"
+# everywhere.
+try:
+    long
+except NameError:
+    long = int
+
+# The Python 3 |map| built-in works lazily, but in Python 2 we need
+# itertools.imap to get this.
+try:
+    from itertools import imap
+except ImportError:
+    imap = map
+
+_have_unwinder = True
+try:
+    from gdb.unwinder import Unwinder
+except ImportError:
+    _have_unwinder = False
+    # We need something here; it doesn't matter what as no unwinder
+    # will ever be instantiated.
+    Unwinder = object
+
+def debug(something):
+    # print("@@ " + something)
+    pass
+
+# Maps frametype enum base names to corresponding class.
+SizeOfFramePrefix = {
+    'JitFrame_IonJS': 'ExitFrameLayout',
+    'JitFrame_BaselineJS': 'JitFrameLayout',
+    'JitFrame_BaselineStub': 'BaselineStubFrameLayout',
+    'JitFrame_IonStub': 'JitStubFrameLayout',
+    # Technically EntryFrameLayout, but that doesn't wind up in the
+    # debuginfo because there are no uses of it.
+    'JitFrame_Entry': 'JitFrameLayout',
+    'JitFrame_Rectifier': 'RectifierFrameLayout',
+    'JitFrame_IonAccessorIC': 'IonAccessorICFrameLayout',
+    'JitFrame_Exit': 'ExitFrameLayout',
+    'JitFrame_Bailout': 'JitFrameLayout',
+}
+
+# All types and symbols that we need are attached to an object that we
+# can dispose of as needed.
+class UnwinderTypeCache(object):
+    def __init__(self):
+        self.d = None
+        self.frame_enum_names = {}
+        self.frame_class_types = {}
+
+    # We take this bizarre approach to defer trying to look up any
+    # symbols until absolutely needed.  Without this, the loading
+    # approach taken by the gdb-tests would cause spurious exceptions.
+    def __getattr__(self, name):
+        if self.d is None:
+            self.initialize()
+        return self.d[name]
+
+    def value(self, name):
+        return long(gdb.parse_and_eval('js::jit::' + name))
+
+    def initialize(self):
+        self.d = {}
+        self.d['FRAMETYPE_MASK'] = (1 << self.value('FRAMETYPE_BITS')) - 1
+        self.d['FRAMESIZE_SHIFT'] = self.value('FRAMESIZE_SHIFT')
+        self.d['FRAME_HEADER_SIZE_SHIFT'] = self.value('FRAME_HEADER_SIZE_SHIFT')
+        self.d['FRAME_HEADER_SIZE_MASK'] = self.value('FRAME_HEADER_SIZE_MASK')
+
+        self.compute_frame_info()
+        commonFrameLayout = gdb.lookup_type('js::jit::CommonFrameLayout')
+        self.d['typeCommonFrameLayout'] = commonFrameLayout
+        self.d['typeCommonFrameLayoutPointer'] = commonFrameLayout.pointer()
+        self.d['per_tls_data'] = gdb.lookup_global_symbol('js::TlsPerThreadData')
+
+        self.d['void_starstar'] = gdb.lookup_type('void').pointer().pointer()
+
+    # Compute maps related to jit frames.
+    def compute_frame_info(self):
+        t = gdb.lookup_type('enum js::jit::FrameType')
+        for field in t.fields():
+            # Strip off "js::jit::".
+            name = field.name[9:]
+            self.d[name] = long(field.enumval)
+            self.frame_enum_names[long(field.enumval)] = name
+
+# gdb doesn't have a direct way to tell us if a given address is
+# claimed by some shared library or the executable.  See
+# https://sourceware.org/bugzilla/show_bug.cgi?id=19288
+# In the interest of not requiring a patched gdb, instead we read
+# /proc/.../maps.  This only works locally, but maybe could work
+# remotely using "remote get".  FIXME.
+def parse_proc_maps():
+    mapfile = '/proc/' + str(gdb.selected_inferior().pid) + '/maps'
+    # Note we only examine executable mappings here.
+    matcher = re.compile("^([a-fA-F0-9]+)-([a-fA-F0-9]+)\s+..x.\s+\S+\s+\S+\s+\S*(.*)$")
+    mappings = []
+    with open(mapfile, "r") as inp:
+        for line in inp:
+            match = matcher.match(line)
+            if not match:
+                # Header lines and such.
+                continue
+            start = match.group(1)
+            end = match.group(2)
+            name = match.group(3).strip()
+            if name is '' or (name.startswith('[') and name is not '[vdso]'):
+                # Skip entries not corresponding to a file.
+                continue
+            mappings.append((long(start, 16), long(end, 16)))
+    return mappings
+
+# This represents a single JIT frame for the purposes of display.
+# That is, the frame filter creates instances of this when it sees a
+# JIT frame in the stack.
+class JitFrameDecorator(FrameDecorator):
+    def __init__(self, base, info):
+        super(JitFrameDecorator, self).__init__(base)
+        self.info = info
+
+    def function(self):
+        if "name" in self.info:
+            return "<<" + self.info["name"] + ">>"
+        return FrameDecorator.function(self)
+
+# A frame filter for SpiderMonkey.
+class SpiderMonkeyFrameFilter(object):
+    # |state_holder| is either None, or an instance of
+    # SpiderMonkeyUnwinder.  If the latter, then this class will
+    # reference the |unwinder_state| attribute to find the current
+    # unwinder state.
+    def __init__(self, state_holder):
+        self.name = "SpiderMonkey"
+        self.enabled = True
+        self.priority = 100
+        self.state_holder = state_holder
+
+    def maybe_wrap_frame(self, frame):
+        if self.state_holder is None or self.state_holder.unwinder_state is None:
+            return frame
+        base = frame.inferior_frame()
+        info = self.state_holder.unwinder_state.get_frame(base)
+        if info is None:
+            return frame
+        return JitFrameDecorator(frame, info)
+
+    def filter(self, frame_iter):
+        return imap(self.maybe_wrap_frame, frame_iter)
+
+# A frame id class, as specified by the gdb unwinder API.
+class SpiderMonkeyFrameId(object):
+    def __init__(self, sp, pc):
+        self.sp = sp
+        self.pc = pc
+
+# This holds all the state needed during a given unwind.  Each time a
+# new unwind is done, a new instance of this class is created.  It
+# keeps track of all the state needed to unwind JIT frames.  Note that
+# this class is not directly instantiated.
+#
+# This is a base class, and must be specialized for each target
+# architecture, both because we need to use arch-specific register
+# names, and because entry frame unwinding is arch-specific.
+# See https://sourceware.org/bugzilla/show_bug.cgi?id=19286 for info
+# about the register name issue.
+#
+# Each subclass must define SP_REGISTER, PC_REGISTER, and
+# SENTINEL_REGISTER (see x64UnwinderState for info); and implement
+# unwind_entry_frame_registers.
+class UnwinderState(object):
+    def __init__(self, typecache):
+        self.next_sp = None
+        self.next_type = None
+        self.activation = None
+        # An unwinder instance is specific to a thread.  Record the
+        # selected thread for later verification.
+        self.thread = gdb.selected_thread()
+        self.frame_map = {}
+        self.proc_mappings = parse_proc_maps()
+        self.typecache = typecache
+
+    # If the given gdb.Frame was created by this unwinder, return the
+    # corresponding informational dictionary for the frame.
+    # Otherwise, return None.  This is used by the frame filter to
+    # display extra information about the frame.
+    def get_frame(self, frame):
+        sp = long(frame.read_register(self.SP_REGISTER))
+        if sp in self.frame_map:
+            return self.frame_map[sp]
+        return None
+
+    # Add information about a frame to the frame map.  This map is
+    # queried by |self.get_frame|.  |sp| is the frame's stack pointer,
+    # and |name| the frame's type as a string, e.g. "JitFrame_Exit".
+    def add_frame(self, sp, name):
+        self.frame_map[long(sp)] = { "name": name }
+
+    # See whether |pc| is claimed by some text mapping.  See
+    # |parse_proc_maps| for details on how the decision is made.
+    def text_address_claimed(self, pc):
+        for (start, end) in self.proc_mappings:
+            if (pc >= start and pc <= end):
+                return True
+        return False
+
+    # Check whether |self| is valid for the selected thread.
+    def check(self):
+        return gdb.selected_thread() is self.thread
+
+    # Essentially js::TlsPerThreadData.get().
+    def get_tls_per_thread_data(self):
+        return self.typecache.per_tls_data.value()['mValue']
+
+    # |common| is a pointer to a CommonFrameLayout object.  Return a
+    # tuple (local_size, header_size, frame_type), where |size| is the
+    # integer size of the previous frame's locals; |header_size| is
+    # the size of this frame's header; and |frame_type| is an integer
+    # representing the previous frame's type.
+    def unpack_descriptor(self, common):
+        value = long(common['descriptor_'])
+        local_size = value >> self.typecache.FRAMESIZE_SHIFT
+        header_size = ((value >> self.typecache.FRAME_HEADER_SIZE_SHIFT) &
+                       self.typecache.FRAME_HEADER_SIZE_MASK)
+        header_size = header_size * self.typecache.void_starstar.sizeof
+        frame_type = long(value & self.typecache.FRAMETYPE_MASK)
+        if frame_type == self.typecache.JitFrame_Entry:
+            # Trampoline-x64.cpp pushes a JitFrameLayout object, but
+            # the stack pointer is actually adjusted as if a
+            # CommonFrameLayout object was pushed.
+            header_size = self.typecache.typeCommonFrameLayout.sizeof
+        return (local_size, header_size, frame_type)
+
+    # Create a new frame for gdb.  This makes a new unwind info object
+    # and fills it in, then returns it.  It also registers any
+    # pertinent information with the frame filter for later display.
+    #
+    # |pc| is the PC from the pending frame
+    # |sp| is the stack pointer to use
+    # |frame| points to the CommonFrameLayout object
+    # |frame_type| is a integer, one of the |enum FrameType| values,
+    # describing the current frame.
+    # |pending_frame| is the pending frame (see the gdb unwinder
+    # documentation).
+    def create_frame(self, pc, sp, frame, frame_type, pending_frame):
+        # Make a frame_id that claims that |frame| is sort of like a
+        # frame pointer for this frame.
+        frame_id = SpiderMonkeyFrameId(frame, pc)
+
+        # Register this frame so the frame filter can find it.  This
+        # is registered using SP because we don't have any other good
+        # approach -- you can't get the frame id from a gdb.Frame.
+        # https://sourceware.org/bugzilla/show_bug.cgi?id=19800
+        frame_name = self.typecache.frame_enum_names[frame_type]
+        self.add_frame(sp, name = frame_name)
+
+        # Read the frame layout object to find the next such object.
+        # This lets us unwind the necessary registers for the next
+        # frame, and also update our internal state to match.
+        common = frame.cast(self.typecache.typeCommonFrameLayoutPointer)
+        next_pc = common['returnAddress_']
+        (local_size, header_size, next_type) = self.unpack_descriptor(common)
+        next_sp = frame + header_size + local_size
+
+        # Update internal state for the next unwind.
+        self.next_sp = next_sp
+        self.next_type = next_type
+
+        unwind_info = pending_frame.create_unwind_info(frame_id)
+        unwind_info.add_saved_register(self.PC_REGISTER, next_pc)
+        unwind_info.add_saved_register(self.SP_REGISTER, next_sp)
+        # FIXME it would be great to unwind any other registers here.
+        return unwind_info
+
+    # Unwind an "ordinary" JIT frame.  This is used for JIT frames
+    # other than enter and exit frames.  Returns the newly-created
+    # unwind info for gdb.
+    def unwind_ordinary(self, pc, pending_frame):
+        return self.create_frame(pc, self.next_sp, self.next_sp,
+                                 self.next_type, pending_frame)
+
+    # Unwind an exit frame.  Returns None if this cannot be done;
+    # otherwise returns the newly-created unwind info for gdb.
+    def unwind_exit_frame(self, pc, pending_frame):
+        if self.activation == 0:
+            # Reached the end of the list.
+            return None
+        elif self.activation is None:
+            ptd = self.get_tls_per_thread_data()
+            self.activation = ptd['runtime_']['jitActivation']
+            jittop = ptd['runtime_']['jitTop']
+        else:
+            jittop = self.activation['prevJitTop_']
+            self.activation = self.activation['prevJitActivation_']
+
+        if jittop == 0:
+            return None
+
+        exit_sp = pending_frame.read_register(self.SP_REGISTER)
+        frame_type = self.typecache.JitFrame_Exit
+        return self.create_frame(pc, exit_sp, jittop, frame_type, pending_frame)
+
+    # A wrapper for unwind_entry_frame_registers that handles
+    # architecture-independent boilerplate.
+    def unwind_entry_frame(self, pc, pending_frame):
+        sp = self.next_sp
+        # Notify the frame filter.
+        self.add_frame(sp, name = 'JitFrame_Entry')
+        # Make an unwind_info for the per-architecture code to fill in.
+        frame_id = SpiderMonkeyFrameId(sp, pc)
+        unwind_info = pending_frame.create_unwind_info(frame_id)
+        self.unwind_entry_frame_registers(sp, unwind_info)
+        self.next_sp = None
+        self.next_type = None
+        return unwind_info
+
+    # The main entry point that is called to try to unwind a JIT frame
+    # of any type.  Returns None if this cannot be done; otherwise
+    # returns the newly-created unwind info for gdb.
+    def unwind(self, pending_frame):
+        pc = pending_frame.read_register(self.PC_REGISTER)
+
+        # If some shared library claims this address, bail.  GDB
+        # defers to our unwinder by default, but we don't really want
+        # that kind of power.
+        if self.text_address_claimed(long(pc)):
+            return None
+
+        if self.next_sp is not None:
+            if self.next_type == self.typecache.JitFrame_Entry:
+                return self.unwind_entry_frame(pc, pending_frame)
+            return self.unwind_ordinary(pc, pending_frame)
+        # Maybe we've found an exit frame.  FIXME I currently don't
+        # know how to identify these precisely, so we'll just hope for
+        # the time being.
+        return self.unwind_exit_frame(pc, pending_frame)
+
+# The UnwinderState subclass for x86-64.
+class x64UnwinderState(UnwinderState):
+    SP_REGISTER = 'rsp'
+    PC_REGISTER = 'rip'
+
+    # A register unique to this architecture, that is also likely to
+    # have been saved in any frame.  The best thing to use here is
+    # some arch-specific name for PC or SP.
+    SENTINEL_REGISTER = 'rip'
+
+    # Must be in sync with Trampoline-x64.cpp:generateEnterJIT.  Note
+    # that rip isn't pushed there explicitly, but rather by the
+    # previous function's call.
+    PUSHED_REGS = ["r15", "r14", "r13", "r12", "rbx", "rbp", "rip"]
+
+    # Fill in the unwound registers for an entry frame.
+    def unwind_entry_frame_registers(self, sp, unwind_info):
+        sp = sp.cast(self.typecache.void_starstar)
+        # Skip the "result" push.
+        sp = sp + 1
+        for reg in self.PUSHED_REGS: