merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 28 Oct 2015 10:43:33 +0100
changeset 269907 fc706d376f0658e560a59c3dd520437b18e8c4a4
parent 269842 872927368b0e59155a52cabb46084d0a19ab4b5f (current diff)
parent 269906 95b404586f1dddf6738b550516ad5f93099b9665 (diff)
child 269914 1b20b3e0fad6e010e809d37ce4525e31462e9976
child 269939 75cb7b35f0213a448121f15f50511099fb8c58cb
child 269973 1d67c4e4858f3a6ea5bf39b31fe11bef3cd001ac
push id29593
push usercbook@mozilla.com
push dateWed, 28 Oct 2015 09:44:28 +0000
treeherdermozilla-central@fc706d376f06 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone44.0a1
first release with
nightly linux32
fc706d376f06 / 44.0a1 / 20151028030432 / files
nightly linux64
fc706d376f06 / 44.0a1 / 20151028030432 / files
nightly mac
fc706d376f06 / 44.0a1 / 20151028030432 / files
nightly win32
fc706d376f06 / 44.0a1 / 20151028030432 / files
nightly win64
fc706d376f06 / 44.0a1 / 20151028030432 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
b2g/config/aries-dogfood/releng-aries-dogfood.tt
b2g/config/aries-spark-ota/releng-aries-spark-ota.tt
b2g/config/dolphin-512/releng-dolphin-512.tt
b2g/config/flame-kk-ota/releng-flame-kk-ota.tt
image/BMPFileHeaders.h
js/src/tests/js1_6/extensions/regress-352392.js
--- a/addon-sdk/source/test/test-sandbox.js
+++ b/addon-sdk/source/test/test-sandbox.js
@@ -79,23 +79,16 @@ exports['test exceptions'] = function(as
     } + '();', 'foo.js', 2);
   }
   catch (error) {
     assert.equal(error.fileName, 'foo.js', 'correct fileName reported');
     assert.equal(error.lineNumber, 4, 'line number was opted');
   }
 };
 
-exports['test opt version'] = function(assert) {
-  let fixture = sandbox();
-  assert.throws(function() {
-    evaluate(fixture, 'let a = 2;', 'test.js', 1, '1.5');
-  }, 'No let in js 1.5');
-};
-
 exports['test load'] = function(assert) {
   let fixture = sandbox();
   load(fixture, fixturesURI + 'sandbox-normal.js');
   assert.equal(fixture.a, 1, 'global variable defined');
   assert.equal(fixture.b, 2, 'global via `this` property was set');
   assert.equal(fixture.f(), 4, 'function was defined');
 };
 
deleted file mode 100644
--- a/b2g/config/aries-dogfood/releng-aries-dogfood.tt
+++ /dev/null
@@ -1,16 +0,0 @@
-[
-{
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
-"algorithm": "sha512",
-"filename": "gcc.tar.xz",
-"unpack": true
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
-}
-]
deleted file mode 100644
--- a/b2g/config/aries-spark-ota/releng-aries-spark-ota.tt
+++ /dev/null
@@ -1,16 +0,0 @@
-[
-{
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
-"algorithm": "sha512",
-"filename": "gcc.tar.xz",
-"unpack": true
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
-}
-]
--- a/b2g/config/aries/config.json
+++ b/b2g/config/aries/config.json
@@ -34,17 +34,17 @@
         "VARIANT": "user",
         "MOZILLA_OFFICIAL": "1",
         "MOZ_TELEMETRY_REPORTING": "1",
         "B2G_UPDATE_CHANNEL": "nightly",
         "GAIA_KEYBOARD_LAYOUTS": "en,pt-BR,es,de,fr,pl,zh-Hans-Pinyin,zh-Hant-Zhuyin,en-Dvorak"
     },
     "b2g_manifest": "aries.xml",
     "b2g_manifest_intree": true,
-    "additional_source_tarballs": [],
+    "additional_source_tarballs": ["backup-aries.tar.xz"],
     "gecko_l10n_root": "https://hg.mozilla.org/l10n-central",
     "gaia": {
         "l10n": {
             "vcs": "hgtool",
             "root": "https://hg.mozilla.org/gaia-l10n"
         }
     }
 }
--- a/b2g/config/aries/releng-aries.tt
+++ b/b2g/config/aries/releng-aries.tt
@@ -1,16 +1,16 @@
 [
 {
+"size": 135359412,
+"digest": "45e677c9606cc4eec44ef4761df47ff431df1ffad17a5c6d21ce700a1c47f79e87a4aa9f30ae47ff060bd64f5b775d995780d88211f9a759ffa0d076beb4816b",
+"algorithm": "sha512",
+"filename": "backup-aries.tar.xz",
+"comment": "v18D"
+},
+{
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
 }
 ]
deleted file mode 100644
--- a/b2g/config/dolphin-512/releng-dolphin-512.tt
+++ /dev/null
@@ -1,16 +0,0 @@
-[
-{
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
-"algorithm": "sha512",
-"filename": "gcc.tar.xz",
-"unpack": true
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
-}
-]
--- a/b2g/config/dolphin/releng-dolphin.tt
+++ b/b2g/config/dolphin/releng-dolphin.tt
@@ -1,16 +1,9 @@
 [
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
 }
 ]
deleted file mode 100644
--- a/b2g/config/flame-kk-ota/releng-flame-kk-ota.tt
+++ /dev/null
@@ -1,16 +0,0 @@
-[
-{
-"size": 80458572,
-"digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
-"algorithm": "sha512",
-"filename": "gcc.tar.xz",
-"unpack": true
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
-}
-]
--- a/b2g/config/flame-kk/releng-flame-kk.tt
+++ b/b2g/config/flame-kk/releng-flame-kk.tt
@@ -7,17 +7,10 @@
 "comment": "v18D"
 },
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
 }
 ]
--- a/b2g/config/flame/releng-flame.tt
+++ b/b2g/config/flame/releng-flame.tt
@@ -5,17 +5,10 @@
 "algorithm": "sha512"
 },
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
 }
 ]
--- a/b2g/config/nexus-4-kk/releng-mako.tt
+++ b/b2g/config/nexus-4-kk/releng-mako.tt
@@ -18,18 +18,11 @@
 "filename": "lge-mako-kot49h-f59c98be.tgz"
 },
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
 }
 ]
 
--- a/b2g/config/nexus-4/releng-mako.tt
+++ b/b2g/config/nexus-4/releng-mako.tt
@@ -18,18 +18,11 @@
 "filename": "lge-mako-jwr66v-985845e4.tgz"
 },
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
 }
 ]
 
--- a/b2g/config/nexus-5-l/releng-nexus5.tt
+++ b/b2g/config/nexus-5-l/releng-nexus5.tt
@@ -1,15 +1,7 @@
 [{
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": "True"
-},
-{
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
-"algorithm": "sha512",
-"filename": "gtk3.tar.xz",
-"unpack": true
-}
-]
+}]
--- a/config/check_macroassembler_style.py
+++ b/config/check_macroassembler_style.py
@@ -26,17 +26,17 @@ import difflib
 import os
 import re
 import subprocess
 import sys
 from check_utils import get_all_toplevel_filenames
 
 architecture_independent = set([ 'generic' ])
 all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64', 'mips32' ])
-all_shared_architecture_names = set([ 'x86_shared', 'arm', 'arm64', 'mips32' ])
+all_shared_architecture_names = set([ 'x86_shared', 'mips_shared', 'arm', 'arm64' ])
 
 reBeforeArg = "(?<=[(,\s])"
 reArgType = "(?P<type>[\w\s:*&]+)"
 reArgName = "(?P<name>\s\w+)"
 reArgDefault = "(?P<default>(?:\s=[^,)]+)?)"
 reAfterArg = "(?=[,)])"
 reMatchArg = re.compile(reBeforeArg + reArgType + reArgName + reArgDefault + reAfterArg)
 
new file mode 100644
--- /dev/null
+++ b/dom/base/ChromeNodeList.cpp
@@ -0,0 +1,50 @@
+/* -*- 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/ChromeNodeList.h"
+#include "mozilla/dom/ChromeNodeListBinding.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+already_AddRefed<ChromeNodeList>
+ChromeNodeList::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
+  nsIDocument* root = win ? win->GetExtantDoc() : nullptr;
+  RefPtr<ChromeNodeList> list = new ChromeNodeList(root);
+  return list.forget();
+}
+
+JSObject*
+ChromeNodeList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return ChromeNodeListBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+ChromeNodeList::Append(nsINode& aNode, ErrorResult& aError)
+{
+  if (!aNode.IsContent()) {
+    // nsINodeList deals with nsIContent objects only, so need to
+    // filter out other nodes for now.
+    aError.Throw(NS_ERROR_DOM_TYPE_ERR);
+    return;
+  }
+
+  AppendElement(aNode.AsContent());
+}
+
+void
+ChromeNodeList::Remove(nsINode& aNode, ErrorResult& aError)
+{
+  if (!aNode.IsContent()) {
+    aError.Throw(NS_ERROR_DOM_TYPE_ERR);
+    return;
+  }
+
+  RemoveElement(aNode.AsContent());
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/ChromeNodeList.h
@@ -0,0 +1,35 @@
+/* -*- 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 "nsCOMArray.h"
+#include "nsContentList.h"
+
+namespace mozilla {
+class ErrorResult;
+
+namespace dom {
+class GlobalObject;
+
+class ChromeNodeList final : public nsSimpleContentList
+{
+public:
+  explicit ChromeNodeList(nsINode* aOwner)
+  : nsSimpleContentList(aOwner)
+  {
+  }
+
+  static already_AddRefed<ChromeNodeList>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+  void Append(nsINode& aNode, ErrorResult& aError);
+  void Remove(nsINode& aNode, ErrorResult& aError);
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/base/ScreenOrientation.cpp
+++ b/dom/base/ScreenOrientation.cpp
@@ -11,16 +11,17 @@
 #include "nsScreen.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/Hal.h"
 #include "mozilla/Preferences.h"
 
 #include "mozilla/dom/Promise.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ScreenOrientation,
                                    DOMEventTargetHelper,
                                    mScreen);
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ScreenOrientation)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -149,16 +149,17 @@ EXPORTS.mozilla += [
 ]
 
 EXPORTS.mozilla.dom += [
     'AnonymousContent.h',
     'Attr.h',
     'BarProps.h',
     'BlobSet.h',
     'ChildIterator.h',
+    'ChromeNodeList.h',
     'ChromeUtils.h',
     'Comment.h',
     'Console.h',
     'DirectionalityUtils.h',
     'DocumentFragment.h',
     'DocumentType.h',
     'DOMCursor.h',
     'DOMError.h',
@@ -212,16 +213,17 @@ EXPORTS.mozilla.dom += [
     'WindowOrientationObserver.h',
 ]
 
 UNIFIED_SOURCES += [
     'AnonymousContent.cpp',
     'Attr.cpp',
     'BarProps.cpp',
     'ChildIterator.cpp',
+    'ChromeNodeList.cpp',
     'ChromeUtils.cpp',
     'Comment.cpp',
     'Console.cpp',
     'Crypto.cpp',
     'DirectionalityUtils.cpp',
     'DocumentFragment.cpp',
     'DocumentType.cpp',
     'DOMCursor.cpp',
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7367,36 +7367,94 @@ nsContentUtils::CallOnAllRemoteChildren(
       CallOnAllRemoteChildren(windowMM, aCallback, aArg);
     }
   }
 }
 
 void
 nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
                                                 nsTArray<IPCDataTransfer>& aIPC,
+                                                bool aInSyncMessage,
                                                 mozilla::dom::nsIContentChild* aChild,
                                                 mozilla::dom::nsIContentParent* aParent)
 {
   aIPC.Clear();
   if (aTransferables) {
     uint32_t transferableCount = 0;
     aTransferables->Count(&transferableCount);
     for (uint32_t i = 0; i < transferableCount; ++i) {
       IPCDataTransfer* dt = aIPC.AppendElement();
       nsCOMPtr<nsISupports> genericItem;
       aTransferables->GetElementAt(i, getter_AddRefs(genericItem));
       nsCOMPtr<nsITransferable> transferable(do_QueryInterface(genericItem));
-      TransferableToIPCTransferable(transferable, dt, aChild, aParent);
-    }
-  }
+      TransferableToIPCTransferable(transferable, dt, aInSyncMessage, aChild, aParent);
+    }
+  }
+}
+
+nsresult
+nsContentUtils::SlurpFileToString(nsIFile* aFile, nsACString& aString)
+{
+  aString.Truncate();
+
+  nsCOMPtr<nsIURI> fileURI;
+  nsresult rv = NS_NewFileURI(getter_AddRefs(fileURI), aFile);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIChannel> channel;
+  rv = NS_NewChannel(getter_AddRefs(channel),
+                     fileURI,
+                     nsContentUtils::GetSystemPrincipal(),
+                     nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
+                     nsIContentPolicy::TYPE_OTHER);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIInputStream> stream;
+  rv = channel->Open2(getter_AddRefs(stream));
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = NS_ConsumeStream(stream, UINT32_MAX, aString);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = stream->Close();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+bool
+nsContentUtils::IsFileImage(nsIFile* aFile, nsACString& aType)
+{
+  nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
+  if (!mime) {
+    return false;
+  }
+
+  nsresult rv = mime->GetTypeFromFile(aFile, aType);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+
+  return StringBeginsWith(aType, NS_LITERAL_CSTRING("image/"));
 }
 
 void
 nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
                                               IPCDataTransfer* aIPCDataTransfer,
+                                              bool aInSyncMessage,
                                               mozilla::dom::nsIContentChild* aChild,
                                               mozilla::dom::nsIContentParent* aParent)
 {
   MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
 
   if (aTransferable) {
     nsCOMPtr<nsISupportsArray> flavorList;
     aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
@@ -7460,17 +7518,17 @@ nsContentUtils::TransferableToIPCTransfe
                               imgIContainer::FLAG_SYNC_DECODE);
             if (surface) {
               RefPtr<mozilla::gfx::DataSourceSurface> dataSurface =
                 surface->GetDataSurface();
               size_t length;
               int32_t stride;
               mozilla::UniquePtr<char[]> surfaceData =
                 nsContentUtils::GetSurfaceData(dataSurface, &length, &stride);
-              
+
               IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
               item->flavor() = nsCString(flavorStr);
               item->data() = nsCString(surfaceData.get(), length);
 
               IPCDataTransferImage& imageDetails = item->imageDetails();
               mozilla::gfx::IntSize size = dataSurface->GetSize();
               imageDetails.width() = size.width;
               imageDetails.height() = size.height;
@@ -7480,24 +7538,44 @@ nsContentUtils::TransferableToIPCTransfe
 
             continue;
           }
 
           // Otherwise, handle this as a file.
           nsCOMPtr<BlobImpl> blobImpl;
           nsCOMPtr<nsIFile> file = do_QueryInterface(data);
           if (file) {
+            // If we can send this over as a blob, do so. Otherwise, we're
+            // responding to a sync message and the child can't process the blob
+            // constructor before processing our response, which would crash. In
+            // that case, hope that the caller is nsClipboardProxy::GetData,
+            // called from editor and send over images as raw data.
+            if (aInSyncMessage) {
+              nsAutoCString type;
+              if (IsFileImage(file, type)) {
+                IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
+                item->flavor() = type;
+                SlurpFileToString(file, item->data());
+              }
+
+              continue;
+            }
+
             blobImpl = new BlobImplFile(file, false);
             ErrorResult rv;
             // Ensure that file data is cached no that the content process
             // has this data available to it when passed over:
             blobImpl->GetSize(rv);
             blobImpl->GetLastModified(rv);
             blobImpl->LookupAndCacheIsDirectory();
           } else {
+            if (aInSyncMessage) {
+              // Can't do anything.
+              continue;
+            }
             blobImpl = do_QueryInterface(data);
           }
           if (blobImpl) {
             IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
             item->flavor() = nsCString(flavorStr);
             if (aChild) {
               item->data() =
                 mozilla::dom::BlobChild::GetOrCreate(aChild,
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2403,23 +2403,40 @@ public:
   /*
    * Call the given callback on all remote children of the given top-level
    * window.
    */
   static void CallOnAllRemoteChildren(nsIDOMWindow* aWindow,
                                       CallOnRemoteChildFunction aCallback,
                                       void* aArg);
 
+  /**
+   * Given an nsIFile, attempts to read it into aString.
+   *
+   * Note: Use sparingly! This causes main-thread I/O, which causes jank and all
+   * other bad things.
+   */
+  static nsresult SlurpFileToString(nsIFile* aFile, nsACString& aString);
+
+  /**
+   * Returns true if the mime service thinks this file contains an image.
+   *
+   * The content type is returned in aType.
+   */
+  static bool IsFileImage(nsIFile* aFile, nsACString& aType);
+
   static void TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
                                               nsTArray<mozilla::dom::IPCDataTransfer>& aIPC,
+                                              bool aInSyncMessage,
                                               mozilla::dom::nsIContentChild* aChild,
                                               mozilla::dom::nsIContentParent* aParent);
 
   static void TransferableToIPCTransferable(nsITransferable* aTransferable,
                                             mozilla::dom::IPCDataTransfer* aIPCDataTransfer,
+                                            bool aInSyncMessage,
                                             mozilla::dom::nsIContentChild* aChild,
                                             mozilla::dom::nsIContentParent* aParent);
 
   /*
    * Get the pixel data from the given source surface and return it as a buffer.
    * The length and stride will be assigned from the surface.
    */
   static mozilla::UniquePtr<char[]> GetSurfaceData(mozilla::gfx::DataSourceSurface* aSurface,
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -21,16 +21,17 @@ support-files =
   fileconstructor_file.png
   frame_bug814638.xul
   frame_registerElement_content.html
   registerElement_ep.js
   host_bug814638.xul
   window_nsITextInputProcessor.xul
   title_window.xul
 
+[test_bug120684.xul]
 [test_bug206691.xul]
 [test_bug339494.xul]
 [test_bug357450.xul]
 [test_bug380418.html]
 [test_bug380418.html^headers^]
 [test_bug383430.html]
 [test_bug391728.html]
 [test_bug418986-1.xul]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/chrome/test_bug120684.xul
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=120684
+-->
+<window title="Mozilla Bug 120684"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=120684"
+     target="_blank">Mozilla Bug 120684</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+  /** Test for Bug 120684 **/
+
+  var list = new ChromeNodeList();
+  is(list.length, 0, "Length should be initially 0.");
+
+  ok(list instanceof NodeList, "ChromeNodeList object should be an instance of NodeList.");
+
+  try {
+    list.append(document);
+    ok(false, "should have throw!");
+  } catch(ex) {
+    ok(true, "ChromeNodeList supports only nsIContent objects for now.");
+  }
+
+  try {
+    list.remove(document);
+    ok(false, "should have throw!");
+  } catch(ex) {
+    ok(true, "ChromeNodeList supports only nsIContent objects for now.");
+  }
+  is(list.length, 0, "Length should be 0.");
+
+  list.append(document.documentElement);
+  is(list.length, 1, "Length should be 1.");
+  is(list[0], document.documentElement);
+  is(list[1], undefined);
+
+  // Removing element which isn't in the list shouldn't do anything.
+  list.remove(document.createElement("foo"));
+  is(list.length, 1, "Length should be 1.");
+  is(list[0], document.documentElement);
+
+  list.remove(document.documentElement);
+  is(list.length, 0, "Length should be 0.");
+  is(list[0], undefined);
+
+  var e1 = document.createElement("foo");
+  var e2 = document.createElement("foo");
+  var e3 = document.createElement("foo");
+
+  list.append(e1);
+  list.append(e2);
+  list.append(e3);
+
+  is(list[0], e1);
+  is(list[1], e2);
+  is(list[2], e3);
+  is(list.length, 3);
+
+  list.remove(e2);
+  is(list[0], e1);
+  is(list[1], e3);
+  is(list[2], undefined);
+  is(list.length, 2);
+
+  // A leak test.
+  list.expando = list;
+
+  ]]>
+  </script>
+</window>
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -532,54 +532,29 @@ DefineUnforgeableAttributes(JSContext* c
                             const Prefable<const JSPropertySpec>* props)
 {
   return DefinePrefable(cx, obj, props);
 }
 
 
 // We should use JSFunction objects for interface objects, but we need a custom
 // hasInstance hook because we have new interface objects on prototype chains of
-// old (XPConnect-based) bindings. Because Function.prototype.toString throws if
-// passed a non-Function object we also need to provide our own toString method
-// for interface objects.
-
-static bool
-InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
+// old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
+// reserved slots (e.g. for named constructors).  So we define a custom
+// funToString ObjectOps member for interface objects.
+JSString*
+InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
+                        unsigned /* indent */)
 {
-  JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
-  if (!args.thisv().isObject()) {
-    JS_ReportErrorNumber(cx, js::GetErrorMessage, nullptr,
-                         JSMSG_CANT_CONVERT_TO, "null", "object");
-    return false;
-  }
-
-  JS::Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(thisObj, /* stopAtOuter = */ false));
-  if (!obj) {
-    JS_ReportError(cx, "Permission denied to access object");
-    return false;
-  }
-
-  const js::Class* clasp = js::GetObjectClass(obj);
-  if (!IsDOMIfaceAndProtoClass(clasp)) {
-    JS_ReportError(cx, "toString called on incompatible object");
-    return false;
-  }
+  const js::Class* clasp = js::GetObjectClass(aObject);
+  MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
 
   const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
     DOMIfaceAndProtoJSClass::FromJSClass(clasp);
-  JS::Rooted<JSString*> str(cx,
-                            JS_NewStringCopyZ(cx,
-                                              ifaceAndProtoJSClass->mToString));
-  if (!str) {
-    return false;
-  }
-
-  args.rval().setString(str);
-  return true;
+  return JS_NewStringCopyZ(aCx, ifaceAndProtoJSClass->mToString);
 }
 
 bool
 Constructor(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   const JS::Value& v =
     js::GetFunctionNativeReserved(&args.callee(),
@@ -642,25 +617,16 @@ CreateInterfaceObject(JSContext* cx, JS:
     constructor = CreateConstructor(cx, global, name, constructorNative,
                                     ctorNargs);
   }
   if (!constructor) {
     return nullptr;
   }
 
   if (constructorClass) {
-    // Have to shadow Function.prototype.toString, since that throws
-    // on things that are not js::FunctionClass.
-    JS::Rooted<JSFunction*> toString(cx,
-      JS_DefineFunction(cx, constructor, "toString", InterfaceObjectToString,
-                        0, 0));
-    if (!toString) {
-      return nullptr;
-    }
-
     if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
                            JSPROP_READONLY)) {
       return nullptr;
     }
 
     // Might as well intern, since we're going to need an atomized
     // version of name anyway when we stick our constructor on the
     // global.
@@ -1565,32 +1531,16 @@ XrayResolveOwnProperty(JSContext* cx, JS
   } else if (type == eInterface) {
     if (IdEquals(id, "prototype")) {
       return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count ||
              ResolvePrototypeOrConstructor(cx, wrapper, obj,
                                            nativePropertyHooks->mPrototypeID,
                                            JSPROP_PERMANENT | JSPROP_READONLY,
                                            desc, cacheOnHolder);
     }
-
-    if (IdEquals(id, "toString") && !JS_ObjectIsFunction(cx, obj)) {
-      MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
-
-      JS::Rooted<JSFunction*> toString(cx, JS_NewFunction(cx, InterfaceObjectToString, 0, 0, "toString"));
-      if (!toString) {
-        return false;
-      }
-
-      cacheOnHolder = true;
-
-      FillPropertyDescriptor(desc, wrapper, 0,
-                             JS::ObjectValue(*JS_GetFunctionObject(toString)));
-
-      return JS_WrapPropertyDescriptor(cx, desc);
-    }
   } else {
     MOZ_ASSERT(IsInterfacePrototype(type));
 
     if (IdEquals(id, "constructor")) {
       return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count ||
              ResolvePrototypeOrConstructor(cx, wrapper, obj,
                                            nativePropertyHooks->mConstructorID,
                                            0, desc, cacheOnHolder);
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3354,12 +3354,16 @@ void
 SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
                              UseCounter aUseCounter);
 
 // Warnings
 void
 DeprecationWarning(JSContext* aCx, JSObject* aObject,
                    nsIDocument::DeprecatedOperations aOperation);
 
+// A callback to perform funToString on an interface object
+JSString*
+InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
+                        unsigned /* indent */);
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -448,17 +448,18 @@ class CGDOMJSClass(CGThing):
                       nullptr, /* getProperty */
                       nullptr, /* setProperty */
                       nullptr, /* getOwnPropertyDescriptor */
                       nullptr, /* deleteProperty */
                       nullptr, /* watch */
                       nullptr, /* unwatch */
                       nullptr, /* getElements */
                       nullptr, /* enumerate */
-                      mozilla::dom::ObjectToOuterObjectValue /* thisValue */
+                      mozilla::dom::ObjectToOuterObjectValue, /* thisValue */
+                      nullptr, /* funToString */
                     }
                     """,
                     objectMoved=objectMovedHook)
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
             reservedSlots = slotCount
         if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
             resolveHook = RESOLVE_HOOK_NAME
@@ -725,17 +726,31 @@ class CGInterfaceObjectJSClass(CGThing):
                 nullptr,               /* mayResolve */
                 nullptr,               /* finalize */
                 ${ctorname}, /* call */
                 ${hasInstance}, /* hasInstance */
                 ${ctorname}, /* construct */
                 nullptr,               /* trace */
                 JS_NULL_CLASS_SPEC,
                 JS_NULL_CLASS_EXT,
-                JS_NULL_OBJECT_OPS
+                {
+                  nullptr, /* lookupProperty */
+                  nullptr, /* defineProperty */
+                  nullptr, /* hasProperty */
+                  nullptr, /* getProperty */
+                  nullptr, /* setProperty */
+                  nullptr, /* getOwnPropertyDescriptor */
+                  nullptr, /* deleteProperty */
+                  nullptr, /* watch */
+                  nullptr, /* unwatch */
+                  nullptr, /* getElements */
+                  nullptr, /* enumerate */
+                  nullptr, /* thisObject */
+                  InterfaceObjectToString, /* funToString */
+                }
               },
               eInterface,
               ${hooks},
               "function ${name}() {\\n    [native code]\\n}",
               ${prototypeID},
               ${depth},
               ${protoGetter}
             };
--- a/dom/bindings/test/test_interfaceToString.html
+++ b/dom/bindings/test/test_interfaceToString.html
@@ -26,13 +26,22 @@ try {
     is(eventTargetToString, nativeToString,
        "Stringifying a DOM interface object should return the same string" +
        "as stringifying a native function.");
 }
 catch (e) {
     ok(false, "Stringifying a DOM interface object shouldn't throw.");
 }
 
+try {
+    eventTargetToString = Function.prototype.toString.call(EventTarget);
+    is(eventTargetToString, nativeToString,
+       "Stringifying a DOM interface object via Function.prototype.toString " +
+       "should return the same string as stringifying a native function.");
+}
+catch (e) {
+    ok(false, "Stringifying a DOM interface object shouldn't throw.");
+}
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -344,19 +344,23 @@ TypeUtils::ToInternalRequest(const Cache
   internalRequest->SetCredentialsMode(aIn.credentials());
   internalRequest->SetContentPolicyType(aIn.contentPolicyType());
   internalRequest->SetCacheMode(aIn.requestCache());
   internalRequest->SetRedirectMode(aIn.requestRedirect());
 
   RefPtr<InternalHeaders> internalHeaders =
     ToInternalHeaders(aIn.headers(), aIn.headersGuard());
   ErrorResult result;
-  internalRequest->Headers()->SetGuard(aIn.headersGuard(), result);
+
+  // Be careful to fill the headers before setting the guard in order to
+  // correctly re-create the original headers.
+  internalRequest->Headers()->Fill(*internalHeaders, result);
   MOZ_ASSERT(!result.Failed());
-  internalRequest->Headers()->Fill(*internalHeaders, result);
+
+  internalRequest->Headers()->SetGuard(aIn.headersGuard(), result);
   MOZ_ASSERT(!result.Failed());
 
   nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
 
   internalRequest->SetBody(stream);
 
   return internalRequest.forget();
 }
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -298,24 +298,34 @@ FetchDriver::HttpFetch()
     nsAutoCString method;
     mRequest->GetMethod(method);
     rv = httpChan->SetRequestMethod(method);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Set the same headers.
     nsAutoTArray<InternalHeaders::Entry, 5> headers;
     mRequest->Headers()->GetEntries(headers);
+    bool hasAccept = false;
     for (uint32_t i = 0; i < headers.Length(); ++i) {
+      if (!hasAccept && headers[i].mName.EqualsLiteral("accept")) {
+        hasAccept = true;
+      }
       if (headers[i].mValue.IsEmpty()) {
         httpChan->SetEmptyRequestHeader(headers[i].mName);
       } else {
         httpChan->SetRequestHeader(headers[i].mName, headers[i].mValue, false /* merge */);
       }
     }
 
+    if (!hasAccept) {
+      httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
+                                 NS_LITERAL_CSTRING("*/*"),
+                                 false /* merge */);
+    }
+
     // Step 2. Set the referrer.
     nsAutoString referrer;
     mRequest->GetReferrer(referrer);
     if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
       rv = nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal,
                                                          mDocument,
                                                          httpChan);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/fetch/InternalHeaders.cpp
+++ b/dom/fetch/InternalHeaders.cpp
@@ -146,23 +146,18 @@ void
 InternalHeaders::Clear()
 {
   mList.Clear();
 }
 
 void
 InternalHeaders::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
 {
-  // Rather than re-validate all current headers, just require code to set
-  // this prior to populating the InternalHeaders object.  Allow setting immutable
-  // late, though, as that is pretty much required to have a  useful, immutable
-  // headers object.
-  if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
-    aRv.Throw(NS_ERROR_FAILURE);
-  }
+  // The guard is only checked during ::Set() and ::Append() in the spec.  It
+  // does not require revalidating headers already set.
   mGuard = aGuard;
 }
 
 InternalHeaders::~InternalHeaders()
 {
 }
 
 // static
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1399,21 +1399,21 @@ HTMLMediaElement::CurrentTime() const
 {
   if (MediaStream* stream = GetSrcMediaStream()) {
     if (mSrcStreamPausedCurrentTime >= 0) {
       return mSrcStreamPausedCurrentTime;
     }
     return stream->StreamTimeToSeconds(stream->GetCurrentTime());
   }
 
-  if (mDecoder) {
+  if (mDefaultPlaybackStartPosition == 0.0 && mDecoder) {
     return mDecoder->GetCurrentTime();
   }
 
-  return 0.0;
+  return mDefaultPlaybackStartPosition;
 }
 
 NS_IMETHODIMP HTMLMediaElement::GetCurrentTime(double* aCurrentTime)
 {
   *aCurrentTime = CurrentTime();
   return NS_OK;
 }
 
@@ -1479,49 +1479,40 @@ HTMLMediaElement::Seek(double aTime,
   // play will not be blocked when initiated by a script.
   if (EventStateManager::IsHandlingUserInput() || nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
     mHasUserInteraction = true;
   }
 
   StopSuspendingAfterFirstFrame();
 
   if (mSrcStream) {
-    // do nothing since streams aren't seekable; we effectively clamp to
-    // the current time.
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    // do nothing since media streams have an empty Seekable range.
     return;
   }
 
-  if (!mPlayed) {
-    LOG(LogLevel::Debug, ("HTMLMediaElement::mPlayed not available."));
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-
-  if (mCurrentPlayRangeStart != -1.0) {
+  if (mPlayed && mCurrentPlayRangeStart != -1.0) {
     double rangeEndTime = CurrentTime();
     LOG(LogLevel::Debug, ("%p Adding \'played\' a range : [%f, %f]", this, mCurrentPlayRangeStart, rangeEndTime));
     // Multiple seek without playing, or seek while playing.
     if (mCurrentPlayRangeStart != rangeEndTime) {
       mPlayed->Add(mCurrentPlayRangeStart, rangeEndTime);
     }
     // Reset the current played range start time. We'll re-set it once
     // the seek completes.
     mCurrentPlayRangeStart = -1.0;
   }
 
-  if (!mDecoder) {
-    LOG(LogLevel::Debug, ("%p SetCurrentTime(%f) failed: no decoder", this, aTime));
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
+    mDefaultPlaybackStartPosition = aTime;
     return;
   }
 
-  if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
-    LOG(LogLevel::Debug, ("%p SetCurrentTime(%f) failed: no source", this, aTime));
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+  if (!mDecoder) {
+    // mDecoder must always be set in order to reach this point.
+    NS_ASSERTION(mDecoder, "SetCurrentTime failed: no decoder");
     return;
   }
 
   // Clamp the seek target to inside the seekable ranges.
   RefPtr<dom::TimeRanges> seekable = new dom::TimeRanges(ToSupports(OwnerDoc()));
   media::TimeIntervals seekableIntervals = mDecoder->GetSeekable();
   if (seekableIntervals.IsInvalid()) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
@@ -2109,17 +2100,18 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mDownloadSuspendedByCache(false, "HTMLMediaElement::mDownloadSuspendedByCache"),
     mAudioChannelVolume(1.0),
     mPlayingThroughTheAudioChannel(false),
     mDisableVideo(false),
     mPlayBlockedBecauseHidden(false),
     mMediaStreamTrackListener(nullptr),
     mElementInTreeState(ELEMENT_NOT_INTREE),
     mHasUserInteraction(false),
-    mFirstFrameLoaded(false)
+    mFirstFrameLoaded(false),
+    mDefaultPlaybackStartPosition(0.0)
 {
   if (!gMediaElementLog) {
     gMediaElementLog = PR_NewLogModule("nsMediaElement");
   }
   if (!gMediaElementEventsLog) {
     gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
   }
 
@@ -3435,16 +3427,21 @@ void HTMLMediaElement::MetadataLoaded(co
   } else {
     mWatchManager.ManualNotify(&HTMLMediaElement::UpdateReadyStateInternal);
   }
 
   if (IsVideo() && aInfo->HasVideo()) {
     // We are a video element playing video so update the screen wakelock
     NotifyOwnerDocumentActivityChangedInternal();
   }
+
+  if (mDefaultPlaybackStartPosition > 0) {
+    SetCurrentTime(mDefaultPlaybackStartPosition);
+    mDefaultPlaybackStartPosition = 0.0;
+  }
 }
 
 void HTMLMediaElement::FirstFrameLoaded()
 {
   NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
 
   if (!mFirstFrameLoaded) {
     mFirstFrameLoaded = true;
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -1511,14 +1511,19 @@ private:
   TimeDurationAccumulator mJoinLatency;
 
   // Indicates if user has interacted with the element.
   // Used to block autoplay when disabled.
   bool mHasUserInteraction;
 
   // True if the first frame has been successfully loaded.
   bool mFirstFrameLoaded;
+
+  // Media elements also have a default playback start position, which must
+  // initially be set to zero seconds. This time is used to allow the element to
+  // be seeked even before the media is loaded.
+  double mDefaultPlaybackStartPosition;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLMediaElement_h
--- a/dom/html/MediaDocument.cpp
+++ b/dom/html/MediaDocument.cpp
@@ -54,17 +54,17 @@ MediaDocumentStreamListener::OnStartRequ
   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
 
   mDocument->StartLayout();
 
   if (mNextStream) {
     return mNextStream->OnStartRequest(request, ctxt);
   }
 
-  return NS_BINDING_ABORTED;
+  return NS_ERROR_PARSED_DATA_CACHED;
 }
 
 NS_IMETHODIMP
 MediaDocumentStreamListener::OnStopRequest(nsIRequest* request,
                                            nsISupports *ctxt,
                                            nsresult status)
 {
   nsresult rv = NS_OK;
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -1981,31 +1981,31 @@ private:
     const uint8_t* uncompressed;
     uint32_t uncompressedLength;
     rv = aArguments->GetSharedBlob(0, &uncompressedLength, &uncompressed);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
-    nsAutoArrayPtr<char> compressed(new (fallible) char[compressedLength]);
+    UniqueFreePtr<uint8_t> compressed(
+      static_cast<uint8_t*>(malloc(compressedLength)));
     if (NS_WARN_IF(!compressed)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     snappy::RawCompress(reinterpret_cast<const char*>(uncompressed),
-                        uncompressedLength, compressed.get(),
+                        uncompressedLength,
+                        reinterpret_cast<char*>(compressed.get()),
                         &compressedLength);
 
-    std::pair<const void *, int> data(static_cast<void*>(compressed.get()),
-                                      int(compressedLength));
-
-    // XXX This copies the buffer again... There doesn't appear to be any way to
-    //     preallocate space and write directly to a BlobVariant at the moment.
-    nsCOMPtr<nsIVariant> result = new mozilla::storage::BlobVariant(data);
+    std::pair<uint8_t *, int> data(compressed.release(),
+                                   int(compressedLength));
+
+    nsCOMPtr<nsIVariant> result = new mozilla::storage::AdoptedBlobVariant(data);
 
     result.forget(aResult);
     return NS_OK;
   }
 };
 
 nsresult
 UpgradeSchemaFrom8To9_0(mozIStorageConnection* aConnection)
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2823,17 +2823,17 @@ ContentParent::RecvGetClipboard(nsTArray
     trans->Init(nullptr);
 
     for (uint32_t t = 0; t < aTypes.Length(); t++) {
       trans->AddDataFlavor(aTypes[t].get());
     }
 
     clipboard->GetData(trans, aWhichClipboard);
     nsContentUtils::TransferableToIPCTransferable(trans, aDataTransfer,
-                                                  nullptr, this);
+                                                  true, nullptr, this);
     return true;
 }
 
 bool
 ContentParent::RecvEmptyClipboard(const int32_t& aWhichClipboard)
 {
     nsresult rv;
     nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &rv));
@@ -5267,16 +5267,17 @@ ContentParent::MaybeInvokeDragSession(Ta
       // needed.
       transfer->FillAllExternalData();
       nsCOMPtr<nsILoadContext> lc = aParent ?
                                      aParent->GetLoadContext() : nullptr;
       nsCOMPtr<nsISupportsArray> transferables =
         transfer->GetTransferables(lc);
       nsContentUtils::TransferablesToIPCTransferables(transferables,
                                                       dataTransfers,
+                                                      false,
                                                       nullptr,
                                                       this);
       uint32_t action;
       session->GetDragAction(&action);
       mozilla::unused << SendInvokeDragSession(dataTransfers, action);
     }
   }
 }
--- a/dom/media/mediasource/test/test_SeekNoData_mp4.html
+++ b/dom/media/mediasource/test/test_SeekNoData_mp4.html
@@ -18,23 +18,37 @@ function fuzzyEquals(a, b) {
 }
 
 runWithMSE(function(ms, el) {
   el.controls = true;
   once(ms, 'sourceopen').then(function() {
     ok(true, "Receive a sourceopen event");
     var audiosb = ms.addSourceBuffer("audio/mp4");
     var videosb = ms.addSourceBuffer("video/mp4");
+    el.addEventListener("error", function(e) {
+      ok(false, "should not fire '" + e + "' event");
+    });
+    is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+    try {
+      el.currentTime = 3;
+    } catch (e) {
+      ok(false, "should not throw '" + e + "' exception");
+    }
+    is(el.currentTime, 3, "currentTime is default playback start position");
+    is(el.seeking, false, "seek not started with HAVE_NOTHING");
     fetchAndLoad(audiosb, 'bipbop/bipbop_audio', ['init'], '.mp4')
     .then(fetchAndLoad.bind(null, videosb, 'bipbop/bipbop_video', ['init'], '.mp4'))
     .then(once.bind(null, el, 'loadedmetadata'))
     .then(function() {
       var p = once(el, 'seeking');
       el.play();
       el.currentTime = 5;
+      is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
+      is(el.seeking, true, "seek not started with HAVE_METADATA");
+      is(el.currentTime, 5, "currentTime is seek position");
       return p;
     })
     .then(function() {
        ok(true, "Got seeking event");
        var promises = [];
        promises.push(once(el, 'seeked'));
        promises.push(fetchAndLoad(audiosb, 'bipbop/bipbop_audio', range(5, 9), '.m4s'));
        promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', range(6, 10), '.m4s'));
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -129,28 +129,61 @@ PDMFactory::~PDMFactory()
 
 already_AddRefed<MediaDataDecoder>
 PDMFactory::CreateDecoder(const TrackInfo& aConfig,
                           FlushableTaskQueue* aTaskQueue,
                           MediaDataDecoderCallback* aCallback,
                           layers::LayersBackend aLayersBackend,
                           layers::ImageContainer* aImageContainer)
 {
-  RefPtr<PlatformDecoderModule> current = (mEMEPDM && aConfig.mCrypto.mValid)
-    ? mEMEPDM : GetDecoder(aConfig.mMimeType);
+  bool isEncrypted = mEMEPDM && aConfig.mCrypto.mValid;
+
+  if (isEncrypted) {
+    return CreateDecoderWithPDM(mEMEPDM,
+                                aConfig,
+                                aTaskQueue,
+                                aCallback,
+                                aLayersBackend,
+                                aImageContainer);
+  }
 
-  if (!current) {
-    return nullptr;
+  for (auto& current : mCurrentPDMs) {
+    if (!current->SupportsMimeType(aConfig.mMimeType)) {
+      continue;
+    }
+    RefPtr<MediaDataDecoder> m =
+      CreateDecoderWithPDM(current,
+                           aConfig,
+                           aTaskQueue,
+                           aCallback,
+                           aLayersBackend,
+                           aImageContainer);
+    if (m) {
+      return m.forget();
+    }
   }
+  NS_WARNING("Unable to create a decoder, no platform found.");
+  return nullptr;
+}
+
+already_AddRefed<MediaDataDecoder>
+PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
+                                 const TrackInfo& aConfig,
+                                 FlushableTaskQueue* aTaskQueue,
+                                 MediaDataDecoderCallback* aCallback,
+                                 layers::LayersBackend aLayersBackend,
+                                 layers::ImageContainer* aImageContainer)
+{
+  MOZ_ASSERT(aPDM);
   RefPtr<MediaDataDecoder> m;
 
   if (aConfig.GetAsAudioInfo()) {
-    m = current->CreateAudioDecoder(*aConfig.GetAsAudioInfo(),
-                                    aTaskQueue,
-                                    aCallback);
+    m = aPDM->CreateAudioDecoder(*aConfig.GetAsAudioInfo(),
+                                 aTaskQueue,
+                                 aCallback);
     return m.forget();
   }
 
   if (!aConfig.GetAsVideoInfo()) {
     return nullptr;
   }
 
   MediaDataDecoderCallback* callback = aCallback;
@@ -160,35 +193,35 @@ PDMFactory::CreateDecoder(const TrackInf
     callbackWrapper->SetVideoOutputMinimumInterval(
       TimeDuration::FromMilliseconds(sVideoOutputMinimumInterval_ms));
     callbackWrapper->SetDontDelayInputExhausted(sDontDelayInputExhausted);
     callback = callbackWrapper.get();
   }
 
   if (H264Converter::IsH264(aConfig)) {
     RefPtr<H264Converter> h
-      = new H264Converter(current,
+      = new H264Converter(aPDM,
                           *aConfig.GetAsVideoInfo(),
                           aLayersBackend,
                           aImageContainer,
                           aTaskQueue,
                           callback);
     const nsresult rv = h->GetLastError();
     if (NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_INITIALIZED) {
       // The H264Converter either successfully created the wrapped decoder,
       // or there wasn't enough AVCC data to do so. Otherwise, there was some
       // problem, for example WMF DLLs were missing.
       m = h.forget();
     }
   } else {
-    m = current->CreateVideoDecoder(*aConfig.GetAsVideoInfo(),
-                                    aLayersBackend,
-                                    aImageContainer,
-                                    aTaskQueue,
-                                    callback);
+    m = aPDM->CreateVideoDecoder(*aConfig.GetAsVideoInfo(),
+                                 aLayersBackend,
+                                 aImageContainer,
+                                 aTaskQueue,
+                                 callback);
   }
 
   if (callbackWrapper && m) {
     m = new DecoderFuzzingWrapper(m.forget(), callbackWrapper.forget());
   }
 
   return m.forget();
 }
--- a/dom/media/platforms/PDMFactory.h
+++ b/dom/media/platforms/PDMFactory.h
@@ -48,16 +48,23 @@ public:
 
 private:
   virtual ~PDMFactory();
   void CreatePDMs();
   // Startup the provided PDM and add it to our list if successful.
   bool StartupPDM(PlatformDecoderModule* aPDM);
   // Returns the first PDM in our list supporting the mimetype.
   already_AddRefed<PlatformDecoderModule> GetDecoder(const nsACString& aMimeType);
+  already_AddRefed<MediaDataDecoder>
+  CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
+                       const TrackInfo& aConfig,
+                       FlushableTaskQueue* aTaskQueue,
+                       MediaDataDecoderCallback* aCallback,
+                       layers::LayersBackend aLayersBackend,
+                       layers::ImageContainer* aImageContainer);
 
   // PDM pref caches...
   static bool sUseBlankDecoder;
 #ifdef MOZ_GONK_MEDIACODEC
   static bool sGonkDecoderEnabled;
 #endif
 #ifdef MOZ_WIDGET_ANDROID
   static bool sAndroidMCDecoderPreferred;
--- a/dom/media/platforms/PlatformDecoderModule.h
+++ b/dom/media/platforms/PlatformDecoderModule.h
@@ -209,16 +209,18 @@ public:
   // Decoder needs to decide whether or not hardware accelearation is supported
   // after creating. It doesn't need to call Init() before calling this function.
   virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const { return false; }
 
   // ConfigurationChanged will be called to inform the video or audio decoder
   // that the format of the next input sample is about to change.
   // If video decoder, aConfig will be a VideoInfo object.
   // If audio decoder, aConfig will be a AudioInfo object.
+  // It is not safe to store a reference to this object and the decoder must
+  // make a copy.
   virtual nsresult ConfigurationChanged(const TrackInfo& aConfig)
   {
     return NS_OK;
   }
 };
 
 } // namespace mozilla
 
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -242,32 +242,40 @@ public:
 
     int32_t sampleRate;
     NS_ENSURE_SUCCESS(rv =
         aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"), &sampleRate), rv);
 
     int32_t size;
     NS_ENSURE_SUCCESS(rv = aInfo->Size(&size), rv);
 
-    const int32_t numFrames = (size / numChannels) / 2;
-    AudioDataValue* audio = new AudioDataValue[size];
-    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), size);
-
     int32_t offset;
     NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
 
+#ifdef MOZ_SAMPLE_TYPE_S16
+    int32_t numSamples = size / 2;
+#else
+#error We only support 16-bit integer PCM
+#endif
+
+    const int32_t numFrames = numSamples / numChannels;
+    AudioDataValue* audio = new AudioDataValue[numSamples];
+
+    uint8_t* bufferStart = static_cast<uint8_t*>(aBuffer) + offset;
+    PodCopy(audio, reinterpret_cast<AudioDataValue*>(bufferStart), numSamples);
+
     int64_t presentationTimeUs;
     NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
 
-    RefPtr<AudioData> data = new AudioData(offset, presentationTimeUs,
-                                             aDuration.ToMicroseconds(),
-                                             numFrames,
-                                             audio,
-                                             numChannels,
-                                             sampleRate);
+    RefPtr<AudioData> data = new AudioData(0, presentationTimeUs,
+                                           aDuration.ToMicroseconds(),
+                                           numFrames,
+                                           audio,
+                                           numChannels,
+                                           sampleRate);
     INVOKE_CALLBACK(Output, data);
     return NS_OK;
   }
 };
 
 
 bool AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType)
 {
--- a/dom/media/platforms/wmf/WMFDecoderModule.cpp
+++ b/dom/media/platforms/wmf/WMFDecoderModule.cpp
@@ -63,17 +63,18 @@ SetNumOfDecoderThreads()
 }
 
 /* static */
 void
 WMFDecoderModule::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   sDXVAEnabled = gfxPlatform::GetPlatform()->CanUseHardwareVideoDecoding();
-  sIsIntelDecoderEnabled = Preferences::GetBool("media.webm.intel_decoder.enabled", false);
+  Preferences::AddBoolVarCache(&sIsIntelDecoderEnabled,
+                               "media.webm.intel_decoder.enabled");
   sLowLatencyMFTEnabled = Preferences::GetBool("media.wmf.low-latency.enabled", false);
   SetNumOfDecoderThreads();
 }
 
 /* static */
 int
 WMFDecoderModule::GetNumDecoderThreads()
 {
@@ -134,20 +135,23 @@ WMFDecoderModule::CreateAudioDecoder(con
 }
 
 static bool
 CanCreateMFTDecoder(const GUID& aGuid)
 {
   if (FAILED(wmf::MFStartup())) {
     return false;
   }
-  RefPtr<MFTDecoder> decoder(new MFTDecoder());
-  bool hasH264 = SUCCEEDED(decoder->Create(aGuid));
+  bool hasdecoder = false;
+  {
+    RefPtr<MFTDecoder> decoder(new MFTDecoder());
+    hasdecoder = SUCCEEDED(decoder->Create(aGuid));
+  }
   wmf::MFShutdown();
-  return hasH264;
+  return hasdecoder;
 }
 
 template<const GUID& aGuid>
 static bool
 CanCreateWMFDecoder()
 {
   static Maybe<bool> result;
   if (result.isNothing()) {
@@ -168,17 +172,17 @@ WMFDecoderModule::SupportsMimeType(const
        aMimeType.EqualsLiteral("video/mp4")) &&
       CanCreateWMFDecoder<CLSID_CMSH264DecoderMFT>()) {
     return true;
   }
   if (aMimeType.EqualsLiteral("audio/mpeg") &&
       CanCreateWMFDecoder<CLSID_CMP3DecMediaObject>()) {
     return true;
   }
-  if (sIsIntelDecoderEnabled) {
+  if (sIsIntelDecoderEnabled && sDXVAEnabled) {
     if (aMimeType.EqualsLiteral("video/webm; codecs=vp8") &&
         CanCreateWMFDecoder<CLSID_WebmMfVp8Dec>()) {
       return true;
     }
     if (aMimeType.EqualsLiteral("video/webm; codecs=vp9") &&
         CanCreateWMFDecoder<CLSID_WebmMfVp9Dec>()) {
       return true;
     }
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp
@@ -227,9 +227,32 @@ WMFMediaDataDecoder::Drain()
 
 bool
 WMFMediaDataDecoder::IsHardwareAccelerated(nsACString& aFailureReason) const {
   MOZ_ASSERT(!mIsShutDown);
 
   return mMFTManager && mMFTManager->IsHardwareAccelerated(aFailureReason);
 }
 
+nsresult
+WMFMediaDataDecoder::ConfigurationChanged(const TrackInfo& aConfig)
+{
+  MOZ_ASSERT(mCallback->OnReaderTaskQueue());
+
+  nsCOMPtr<nsIRunnable> runnable =
+    NS_NewRunnableMethodWithArg<UniquePtr<TrackInfo>&&>(
+    this,
+    &WMFMediaDataDecoder::ProcessConfigurationChanged,
+    aConfig.Clone());
+  mTaskQueue->Dispatch(runnable.forget());
+  return NS_OK;
+
+}
+
+void
+WMFMediaDataDecoder::ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig)
+{
+  if (mMFTManager) {
+    mMFTManager->ConfigurationChanged(*aConfig);
+  }
+}
+
 } // namespace mozilla
--- a/dom/media/platforms/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.h
@@ -47,16 +47,18 @@ public:
 
   // Destroys all resources.
   virtual void Shutdown() = 0;
 
   virtual bool IsHardwareAccelerated(nsACString& aFailureReason) const { return false; }
 
   virtual TrackInfo::TrackType GetType() = 0;
 
+  virtual void ConfigurationChanged(const TrackInfo& aConfig) {}
+
 protected:
   // IMFTransform wrapper that performs the decoding.
   RefPtr<MFTDecoder> mDecoder;
 };
 
 // Decodes audio and video using Windows Media Foundation. Samples are decoded
 // using the MFTDecoder created by the MFTManager. This class implements
 // the higher-level logic that drives mapping the MFT to the async
@@ -76,16 +78,18 @@ public:
   nsresult Flush() override;
 
   nsresult Drain() override;
 
   nsresult Shutdown() override;
 
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
 
+  nsresult ConfigurationChanged(const TrackInfo& aConfig) override;
+
 private:
 
   // Called on the task queue. Inserts the sample into the decoder, and
   // extracts output if available.
   void ProcessDecode(MediaRawData* aSample);
 
   // Called on the task queue. Extracts output if available, and delivers
   // it to the reader. Called after ProcessDecode() and ProcessDrain().
@@ -96,16 +100,20 @@ private:
   void ProcessFlush();
 
   // Called on the task queue. Orders the MFT to drain, and then extracts
   // all available output.
   void ProcessDrain();
 
   void ProcessShutdown();
 
+  // Called on the task queue. Tell the MFT that the next Input will have a
+  // different configuration (typically resolution change).
+  void ProcessConfigurationChanged(UniquePtr<TrackInfo>&& aConfig);
+
   RefPtr<FlushableTaskQueue> mTaskQueue;
   MediaDataDecoderCallback* mCallback;
 
   nsAutoPtr<MFTManager> mMFTManager;
 
   // The last offset into the media resource that was passed into Input().
   // This is used to approximate the decoder's position in the media resource.
   int64_t mLastStreamOffset;
--- a/dom/media/platforms/wmf/WMFUtils.cpp
+++ b/dom/media/platforms/wmf/WMFUtils.cpp
@@ -34,36 +34,31 @@ HNsToFrames(int64_t aHNs, uint32_t aRate
   i *= aRate;
   i /= HNS_PER_S;
   NS_ENSURE_TRUE(i.isValid(), E_FAIL);
   *aOutFrames = i.value();
   return S_OK;
 }
 
 HRESULT
-GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
+GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride)
 {
   // Try to get the default stride from the media type.
   HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
   if (SUCCEEDED(hr)) {
     return S_OK;
   }
 
   // Stride attribute not set, calculate it.
   GUID subtype = GUID_NULL;
-  uint32_t width = 0;
-  uint32_t height = 0;
 
   hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-  hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
-  hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride));
+  hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, aWidth, (LONG*)(aOutStride));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   return hr;
 }
 
 int32_t
 MFOffsetToInt32(const MFOffset& aOffset)
 {
--- a/dom/media/platforms/wmf/WMFUtils.h
+++ b/dom/media/platforms/wmf/WMFUtils.h
@@ -32,17 +32,17 @@ inline int64_t
 HNsToUsecs(int64_t hNanoSecs) {
   return hNanoSecs / 10;
 }
 
 HRESULT
 HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames);
 
 HRESULT
-GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride);
+GetDefaultStride(IMFMediaType *aType, uint32_t aWidth, uint32_t* aOutStride);
 
 int32_t
 MFOffsetToInt32(const MFOffset& aOffset);
 
 // Gets the sub-region of the video frame that should be displayed.
 // See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
 HRESULT
 GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion);
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -68,17 +68,19 @@ const CLSID CLSID_WebmMfVp9Dec =
 
 namespace mozilla {
 
 WMFVideoMFTManager::WMFVideoMFTManager(
                             const VideoInfo& aConfig,
                             mozilla::layers::LayersBackend aLayersBackend,
                             mozilla::layers::ImageContainer* aImageContainer,
                             bool aDXVAEnabled)
-  : mImageContainer(aImageContainer)
+  : mVideoInfo(aConfig)
+  , mVideoStride(0)
+  , mImageContainer(aImageContainer)
   , mDXVAEnabled(aDXVAEnabled)
   , mLayersBackend(aLayersBackend)
   // mVideoStride, mVideoWidth, mVideoHeight, mUseHwAccel are initialized in
   // Init().
 {
   MOZ_COUNT_CTOR(WMFVideoMFTManager);
 
   // Need additional checks/params to check vp8/vp9
@@ -247,23 +249,16 @@ WMFVideoMFTManager::InitInternal(bool aF
   }
 
   mDecoder = decoder;
   hr = SetDecoderMediaTypes();
   NS_ENSURE_TRUE(SUCCEEDED(hr), false);
 
   LOG("Video Decoder initialized, Using DXVA: %s", (mUseHwAccel ? "Yes" : "No"));
 
-  // Just in case ConfigureVideoFrameGeometry() does not set these
-  mVideoInfo = VideoInfo();
-  mVideoStride = 0;
-  mVideoWidth = 0;
-  mVideoHeight = 0;
-  mPictureRegion.SetEmpty();
-
   return true;
 }
 
 HRESULT
 WMFVideoMFTManager::SetDecoderMediaTypes()
 {
   // Setup the input/output media types.
   RefPtr<IMFMediaType> inputType;
@@ -367,59 +362,45 @@ WMFVideoMFTManager::ConfigureVideoFrameG
   // we use YV12, as that's easier for us to stick into our rendering
   // pipeline than NV12. NV12 has interleaved UV samples, whereas YV12
   // is a planar format.
   GUID videoFormat;
   hr = mediaType->GetGUID(MF_MT_SUBTYPE, &videoFormat);
   NS_ENSURE_TRUE(videoFormat == MFVideoFormat_NV12 || !mUseHwAccel, E_FAIL);
   NS_ENSURE_TRUE(videoFormat == MFVideoFormat_YV12 || mUseHwAccel, E_FAIL);
 
-  nsIntRect pictureRegion;
-  hr = GetPictureRegion(mediaType, pictureRegion);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
   UINT32 width = 0, height = 0;
   hr = MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-  uint32_t aspectNum = 0, aspectDenom = 0;
-  hr = MFGetAttributeRatio(mediaType,
-                           MF_MT_PIXEL_ASPECT_RATIO,
-                           &aspectNum,
-                           &aspectDenom);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
+  mVideoInfo.mImage.width = width;
+  mVideoInfo.mImage.height = height;
+  nsIntRect pictureRegion = mVideoInfo.mImage;
   // Calculate and validate the picture region and frame dimensions after
   // scaling by the pixel aspect ratio.
   nsIntSize frameSize = nsIntSize(width, height);
-  nsIntSize displaySize = nsIntSize(pictureRegion.width, pictureRegion.height);
-  ScaleDisplayByAspectRatio(displaySize, float(aspectNum) / float(aspectDenom));
+  nsIntSize displaySize = nsIntSize(mVideoInfo.mDisplay.width, mVideoInfo.mDisplay.height);
   if (!IsValidVideoRegion(frameSize, pictureRegion, displaySize)) {
     // Video track's frame sizes will overflow. Ignore the video track.
     return E_FAIL;
   }
 
   if (mDXVA2Manager) {
     hr = mDXVA2Manager->ConfigureForSize(width, height);
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   }
 
   // Success! Save state.
-  mVideoInfo.mDisplay = displaySize;
-  GetDefaultStride(mediaType, &mVideoStride);
-  mVideoWidth = width;
-  mVideoHeight = height;
-  mPictureRegion = pictureRegion;
+  GetDefaultStride(mediaType, width, &mVideoStride);
 
-  LOG("WMFVideoMFTManager frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d) PAR=%d:%d",
+  LOG("WMFVideoMFTManager frame geometry frame=(%u,%u) stride=%u picture=(%d, %d, %d, %d) display=(%d,%d)",
       width, height,
       mVideoStride,
-      mPictureRegion.x, mPictureRegion.y, mPictureRegion.width, mPictureRegion.height,
-      displaySize.width, displaySize.height,
-      aspectNum, aspectDenom);
+      pictureRegion.x, pictureRegion.y, pictureRegion.width, pictureRegion.height,
+      mVideoInfo.mDisplay.width, mVideoInfo.mDisplay.height);
 
   return S_OK;
 }
 
 HRESULT
 WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
                                           int64_t aStreamOffset,
                                           VideoData** aOutVideoData)
@@ -451,35 +432,38 @@ WMFVideoMFTManager::CreateBasicVideoFram
     NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
     stride = mVideoStride;
   }
 
   // YV12, planar format: [YYYY....][VVVV....][UUUU....]
   // i.e., Y, then V, then U.
   VideoData::YCbCrBuffer b;
 
+  uint32_t videoWidth = mVideoInfo.mImage.width;
+  uint32_t videoHeight = mVideoInfo.mImage.height;
+
   // Y (Y') plane
   b.mPlanes[0].mData = data;
   b.mPlanes[0].mStride = stride;
-  b.mPlanes[0].mHeight = mVideoHeight;
-  b.mPlanes[0].mWidth = mVideoWidth;
+  b.mPlanes[0].mHeight = videoHeight;
+  b.mPlanes[0].mWidth = videoWidth;
   b.mPlanes[0].mOffset = 0;
   b.mPlanes[0].mSkip = 0;
 
   // The V and U planes are stored 16-row-aligned, so we need to add padding
   // to the row heights to ensure the Y'CbCr planes are referenced properly.
   uint32_t padding = 0;
-  if (mVideoHeight % 16 != 0) {
-    padding = 16 - (mVideoHeight % 16);
+  if (videoHeight % 16 != 0) {
+    padding = 16 - (videoHeight % 16);
   }
-  uint32_t y_size = stride * (mVideoHeight + padding);
-  uint32_t v_size = stride * (mVideoHeight + padding) / 4;
+  uint32_t y_size = stride * (videoHeight + padding);
+  uint32_t v_size = stride * (videoHeight + padding) / 4;
   uint32_t halfStride = (stride + 1) / 2;
-  uint32_t halfHeight = (mVideoHeight + 1) / 2;
-  uint32_t halfWidth = (mVideoWidth + 1) / 2;
+  uint32_t halfHeight = (videoHeight + 1) / 2;
+  uint32_t halfWidth = (videoWidth + 1) / 2;
 
   // U plane (Cb)
   b.mPlanes[1].mData = data + y_size + v_size;
   b.mPlanes[1].mStride = halfStride;
   b.mPlanes[1].mHeight = halfHeight;
   b.mPlanes[1].mWidth = halfWidth;
   b.mPlanes[1].mOffset = 0;
   b.mPlanes[1].mSkip = 0;
@@ -498,29 +482,29 @@ WMFVideoMFTManager::CreateBasicVideoFram
   NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
 
   RefPtr<layers::PlanarYCbCrImage> image =
     new IMFYCbCrImage(buffer, twoDBuffer);
 
   VideoData::SetVideoDataToImage(image,
                                  mVideoInfo,
                                  b,
-                                 mPictureRegion,
+                                 mVideoInfo.mImage,
                                  false);
 
   RefPtr<VideoData> v =
     VideoData::CreateFromImage(mVideoInfo,
                                mImageContainer,
                                aStreamOffset,
                                pts.ToMicroseconds(),
                                duration.ToMicroseconds(),
                                image.forget(),
                                false,
                                -1,
-                               mPictureRegion);
+                               mVideoInfo.mImage);
 
   v.forget(aOutVideoData);
   return S_OK;
 }
 
 HRESULT
 WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
                                         int64_t aStreamOffset,
@@ -531,17 +515,17 @@ WMFVideoMFTManager::CreateD3DVideoFrame(
   NS_ENSURE_TRUE(mDXVA2Manager, E_ABORT);
   NS_ENSURE_TRUE(mUseHwAccel, E_ABORT);
 
   *aOutVideoData = nullptr;
   HRESULT hr;
 
   RefPtr<Image> image;
   hr = mDXVA2Manager->CopyToImage(aSample,
-                                  mPictureRegion,
+                                  mVideoInfo.mImage,
                                   mImageContainer,
                                   getter_AddRefs(image));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   NS_ENSURE_TRUE(image, E_FAIL);
 
   media::TimeUnit pts = GetSampleTime(aSample);
   NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
   media::TimeUnit duration = GetSampleDuration(aSample);
@@ -549,17 +533,17 @@ WMFVideoMFTManager::CreateD3DVideoFrame(
   RefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo,
                                                      mImageContainer,
                                                      aStreamOffset,
                                                      pts.ToMicroseconds(),
                                                      duration.ToMicroseconds(),
                                                      image.forget(),
                                                      false,
                                                      -1,
-                                                     mPictureRegion);
+                                                     mVideoInfo.mImage);
 
   NS_ENSURE_TRUE(v, E_FAIL);
   v.forget(aOutVideoData);
 
   return S_OK;
 }
 
 // Blocks until decoded sample is produced by the deoder.
@@ -627,9 +611,16 @@ WMFVideoMFTManager::Shutdown()
 
 bool
 WMFVideoMFTManager::IsHardwareAccelerated(nsACString& aFailureReason) const
 {
   aFailureReason = mDXVAFailureReason;
   return mDecoder && mUseHwAccel;
 }
 
+void
+WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig)
+{
+  MOZ_ASSERT(aConfig.GetAsVideoInfo());
+  mVideoInfo = *aConfig.GetAsVideoInfo();
+}
+
 } // namespace mozilla
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.h
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h
@@ -34,16 +34,18 @@ public:
   void Shutdown() override;
 
   bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
 
   TrackInfo::TrackType GetType() override {
     return TrackInfo::kVideoTrack;
   }
 
+  void ConfigurationChanged(const TrackInfo& aConfig) override;
+
 private:
 
   bool InitializeDXVA(bool aForceD3D9);
 
   bool InitInternal(bool aForceD3D9);
 
   HRESULT ConfigureVideoFrameGeometry();
 
@@ -57,19 +59,16 @@ private:
 
   HRESULT SetDecoderMediaTypes();
 
   bool CanUseDXVA(IMFMediaType* aType);
 
   // Video frame geometry.
   VideoInfo mVideoInfo;
   uint32_t mVideoStride;
-  uint32_t mVideoWidth;
-  uint32_t mVideoHeight;
-  nsIntRect mPictureRegion;
 
   RefPtr<layers::ImageContainer> mImageContainer;
   nsAutoPtr<DXVA2Manager> mDXVA2Manager;
 
   RefPtr<IMFSample> mLastInput;
   float mLastDuration;
 
   bool mDXVAEnabled;
--- a/dom/media/platforms/wrappers/H264Converter.cpp
+++ b/dom/media/platforms/wrappers/H264Converter.cpp
@@ -17,16 +17,17 @@ namespace mozilla
 
 H264Converter::H264Converter(PlatformDecoderModule* aPDM,
                              const VideoInfo& aConfig,
                              layers::LayersBackend aLayersBackend,
                              layers::ImageContainer* aImageContainer,
                              FlushableTaskQueue* aVideoTaskQueue,
                              MediaDataDecoderCallback* aCallback)
   : mPDM(aPDM)
+  , mOriginalConfig(aConfig)
   , mCurrentConfig(aConfig)
   , mLayersBackend(aLayersBackend)
   , mImageContainer(aImageContainer)
   , mVideoTaskQueue(aVideoTaskQueue)
   , mCallback(aCallback)
   , mDecoder(nullptr)
   , mNeedAVCC(aPDM->DecoderNeedsConversion(aConfig) == PlatformDecoderModule::kNeedAVCC)
   , mLastError(NS_OK)
@@ -48,24 +49,20 @@ H264Converter::Init()
   // We haven't been able to initialize a decoder due to a missing SPS/PPS.
   return MediaDataDecoder::InitPromise::CreateAndResolve(
            TrackType::kVideoTrack, __func__);
 }
 
 nsresult
 H264Converter::Input(MediaRawData* aSample)
 {
-  if (!mNeedAVCC) {
-    if (!mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
-      return NS_ERROR_FAILURE;
-    }
-  } else {
-    if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
-      return NS_ERROR_FAILURE;
-    }
+  if (!mp4_demuxer::AnnexB::ConvertSampleToAVCC(aSample)) {
+    // We need AVCC content to be able to later parse the SPS.
+    // This is a no-op if the data is already AVCC.
+    return NS_ERROR_FAILURE;
   }
 
   if (mInitPromiseRequest.Exists()) {
     mMediaRawSamples.AppendElement(aSample);
     return NS_OK;
   }
 
   nsresult rv;
@@ -79,16 +76,21 @@ H264Converter::Input(MediaRawData* aSamp
       // Ignore for the time being, the MediaRawData will be dropped.
       return NS_OK;
     }
   } else {
     rv = CheckForSPSChange(aSample);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (!mNeedAVCC &&
+      !mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample)) {
+    return NS_ERROR_FAILURE;
+  }
+
   aSample->mExtraData = mCurrentConfig.mExtraData;
 
   return mDecoder->Input(aSample);
 }
 
 nsresult
 H264Converter::Flush()
 {
@@ -133,17 +135,17 @@ nsresult
 H264Converter::CreateDecoder()
 {
   if (mNeedAVCC && !mp4_demuxer::AnnexB::HasSPS(mCurrentConfig.mExtraData)) {
     // nothing found yet, will try again later
     return NS_ERROR_NOT_INITIALIZED;
   }
   UpdateConfigFromExtraData(mCurrentConfig.mExtraData);
 
-  mDecoder = mPDM->CreateVideoDecoder(mCurrentConfig,
+  mDecoder = mPDM->CreateVideoDecoder(mNeedAVCC ? mCurrentConfig : mOriginalConfig,
                                       mLayersBackend,
                                       mImageContainer,
                                       mVideoTaskQueue,
                                       mCallback);
   if (!mDecoder) {
     mLastError = NS_ERROR_FAILURE;
     return NS_ERROR_FAILURE;
   }
--- a/dom/media/platforms/wrappers/H264Converter.h
+++ b/dom/media/platforms/wrappers/H264Converter.h
@@ -48,16 +48,17 @@ private:
   nsresult CreateDecoderAndInit(MediaRawData* aSample);
   nsresult CheckForSPSChange(MediaRawData* aSample);
   void UpdateConfigFromExtraData(MediaByteBuffer* aExtraData);
 
   void OnDecoderInitDone(const TrackType aTrackType);
   void OnDecoderInitFailed(MediaDataDecoder::DecoderFailureReason aReason);
 
   RefPtr<PlatformDecoderModule> mPDM;
+  const VideoInfo& mOriginalConfig;
   VideoInfo mCurrentConfig;
   layers::LayersBackend mLayersBackend;
   RefPtr<layers::ImageContainer> mImageContainer;
   RefPtr<FlushableTaskQueue> mVideoTaskQueue;
   nsTArray<RefPtr<MediaRawData>> mMediaRawSamples;
   MediaDataDecoderCallback* mCallback;
   RefPtr<MediaDataDecoder> mDecoder;
   MozPromiseRequestHolder<InitPromise> mInitPromiseRequest;
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -763,16 +763,17 @@ skip-if = (toolkit == 'android' && proce
 [test_replay_metadata.html]
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
 [test_reset_events_async.html]
 [test_reset_src.html]
 [test_video_dimensions.html]
 tags=capturestream
 [test_resume.html]
 skip-if = true # bug 1021673
+[test_seek_nosrc.html]
 [test_seek_out_of_range.html]
 skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
 [test_seek-1.html]
 skip-if = android_version == '10' # bug 1059116
 [test_seek-2.html]
 [test_seek-3.html]
 [test_seek-4.html]
 [test_seek-5.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_seek_nosrc.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Media test: seek tests</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var SEEK_TIME = 3.5;
+var seekStarted = false;
+var seekCompleted = false;
+var metadata = false;
+
+var v = document.createElement('video');
+document.body.appendChild(v);
+SimpleTest.registerCleanupFunction(function () {
+  v.remove();
+});
+
+try {
+  v.currentTime = SEEK_TIME;
+} catch (e) {
+  ok(false, "should not fire '" + e + "' event");
+}
+is(v.readyState, v.HAVE_NOTHING, "readyState is HAVE_NOTHING");
+ok(!v.seeking, "can't be seeking prior src defined");
+is(v.currentTime, SEEK_TIME, "currentTime is default playback start position");
+once(v, "seeking", function() {
+  seekStarted = true;
+});
+once(v, "seeked", function() {
+  seekCompleted = true;
+});
+once(v, "loadedmetadata", function() {
+  metadata = true;
+  ok(v.seeking, "element is seeking once readyState is HAVE_METADATA");
+});
+once(v, "ended", function() {
+  ok(seekStarted, "seek should have started");
+  ok(seekCompleted, "seek should have completed");
+  ok(metadata, "loadedmetadata fired");
+  ok(v.currentTime >= SEEK_TIME, "currentTime should be after seek time");
+  SimpleTest.finish();
+});
+
+v.src = "seek.webm";
+v.play();
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/webaudio/AudioNode.cpp
+++ b/dom/media/webaudio/AudioNode.cpp
@@ -172,35 +172,35 @@ AudioNode::DisconnectFromGraph()
     // It doesn't matter which one we remove, since we're going to remove all
     // entries for this node anyway.
     output->RemoveInputNode(inputIndex);
   }
 
   DestroyMediaStream();
 }
 
-void
+AudioNode*
 AudioNode::Connect(AudioNode& aDestination, uint32_t aOutput,
                    uint32_t aInput, ErrorResult& aRv)
 {
   if (aOutput >= NumberOfOutputs() ||
       aInput >= aDestination.NumberOfInputs()) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
-    return;
+    return nullptr;
   }
 
   if (Context() != aDestination.Context()) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-    return;
+    return nullptr;
   }
 
   if (FindIndexOfNodeWithPorts(aDestination.mInputNodes, this, aInput, aOutput) !=
       nsTArray<AudioNode::InputNode>::NoIndex) {
     // connection already exists.
-    return;
+    return &aDestination;
   }
 
   // The MediaStreamGraph will handle cycle detection. We don't need to do it
   // here.
 
   mOutputNodes.AppendElement(&aDestination);
   InputNode* input = aDestination.mInputNodes.AppendElement();
   input->mInputNode = this;
@@ -215,16 +215,18 @@ AudioNode::Connect(AudioNode& aDestinati
       AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK,
                         static_cast<uint16_t>(aInput),
                         static_cast<uint16_t>(aOutput));
   }
   aDestination.NotifyInputsChanged();
 
   // This connection may have connected a panner and a source.
   Context()->UpdatePannerSource();
+
+  return &aDestination;
 }
 
 void
 AudioNode::Connect(AudioParam& aDestination, uint32_t aOutput,
                    ErrorResult& aRv)
 {
   if (aOutput >= NumberOfOutputs()) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
--- a/dom/media/webaudio/AudioNode.h
+++ b/dom/media/webaudio/AudioNode.h
@@ -84,18 +84,18 @@ public:
     return mContext;
   }
 
   AudioContext* Context() const
   {
     return mContext;
   }
 
-  virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
-                       uint32_t aInput, ErrorResult& aRv);
+  virtual AudioNode* Connect(AudioNode& aDestination, uint32_t aOutput,
+                             uint32_t aInput, ErrorResult& aRv);
 
   virtual void Connect(AudioParam& aDestination, uint32_t aOutput,
                        ErrorResult& aRv);
 
   virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv);
 
   // Called after input nodes have been explicitly added or removed through
   // the Connect() or Disconnect() methods.
--- a/dom/media/webaudio/ScriptProcessorNode.h
+++ b/dom/media/webaudio/ScriptProcessorNode.h
@@ -28,23 +28,24 @@ public:
 
   IMPL_EVENT_HANDLER(audioprocess)
 
   virtual void EventListenerAdded(nsIAtom* aType) override;
   virtual void EventListenerRemoved(nsIAtom* aType) override;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
-  virtual void Connect(AudioNode& aDestination, uint32_t aOutput,
-                       uint32_t aInput, ErrorResult& aRv) override
+  virtual AudioNode* Connect(AudioNode& aDestination, uint32_t aOutput,
+                             uint32_t aInput, ErrorResult& aRv) override
   {
-    AudioNode::Connect(aDestination, aOutput, aInput, aRv);
+    AudioNode* node = AudioNode::Connect(aDestination, aOutput, aInput, aRv);
     if (!aRv.Failed()) {
       UpdateConnectedStatus();
     }
+    return node;
   }
 
   virtual void Connect(AudioParam& aDestination, uint32_t aOutput,
                        ErrorResult& aRv) override
   {
     AudioNode::Connect(aDestination, aOutput, aRv);
     if (!aRv.Failed()) {
       UpdateConnectedStatus();
--- a/dom/webidl/AudioNode.webidl
+++ b/dom/webidl/AudioNode.webidl
@@ -19,17 +19,17 @@ enum ChannelCountMode {
 enum ChannelInterpretation {
     "speakers",
     "discrete"
 };
 
 interface AudioNode : EventTarget {
 
     [Throws]
-    void connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
+    AudioNode connect(AudioNode destination, optional unsigned long output = 0, optional unsigned long input = 0);
     [Throws]
     void connect(AudioParam destination, optional unsigned long output = 0);
     [Throws]
     void disconnect(optional unsigned long output = 0);
 
     readonly attribute AudioContext context;
     readonly attribute unsigned long numberOfInputs;
     readonly attribute unsigned long numberOfOutputs;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/ChromeNodeList.webidl
@@ -0,0 +1,13 @@
+/* -*- 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/.
+ */
+
+[ChromeOnly, Constructor]
+interface ChromeNodeList : NodeList {
+  [Throws]
+  void append(Node aNode);
+  [Throws]
+  void remove(Node aNode);
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -70,16 +70,17 @@ WEBIDL_FILES = [
     'CanvasCaptureMediaStream.webidl',
     'CanvasRenderingContext2D.webidl',
     'CaretPosition.webidl',
     'CDATASection.webidl',
     'ChannelMergerNode.webidl',
     'ChannelSplitterNode.webidl',
     'CharacterData.webidl',
     'ChildNode.webidl',
+    'ChromeNodeList.webidl',
     'ChromeNotifications.webidl',
     'ChromeUtils.webidl',
     'Client.webidl',
     'Clients.webidl',
     'ClipboardEvent.webidl',
     'CommandEvent.webidl',
     'Comment.webidl',
     'CompositionEvent.webidl',
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -54,19 +54,19 @@ CancelChannelRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsresult rv = mChannel->Cancel(mStatus);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 FetchEvent::FetchEvent(EventTarget* aOwner)
-: ExtendableEvent(aOwner)
-, mIsReload(false)
-, mWaitToRespond(false)
+  : ExtendableEvent(aOwner)
+  , mIsReload(false)
+  , mWaitToRespond(false)
 {
 }
 
 FetchEvent::~FetchEvent()
 {
 }
 
 void
@@ -431,42 +431,34 @@ RespondWithHandler::CancelRequest(nsresu
 void
 FetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv)
 {
   if (EventPhase() == nsIDOMEvent::NONE || mWaitToRespond) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  // 4.5.3.2 If the respond-with entered flag is set, then:
-  // Throw an "InvalidStateError" exception.
-  // Here we use |mPromise != nullptr| as respond-with enter flag
-  if (mPromise) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  mPromise = &aArg;
-
   RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
   StopImmediatePropagation();
   mWaitToRespond = true;
   RefPtr<RespondWithHandler> handler =
     new RespondWithHandler(mChannel, mRequest->Mode(), ir->IsClientRequest(),
                            ir->IsNavigationRequest(), mScriptSpec);
   aArg.AppendNativeHandler(handler);
+
+  WaitUntil(aArg, aRv);
 }
 
 NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent)
 NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent)
 NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, ExtendableEvent,
-                                   mRequest, mPromise)
+NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, ExtendableEvent, mRequest)
 
 ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
   : Event(aOwner, nullptr, nullptr)
 {
 }
 
 void
 ExtendableEvent::WaitUntil(Promise& aPromise, ErrorResult& aRv)
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -98,17 +98,16 @@ public:
   }
 };
 
 class FetchEvent final : public ExtendableEvent
 {
   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
   RefPtr<Request> mRequest;
   nsCString mScriptSpec;
-  RefPtr<Promise> mPromise;
   bool mIsReload;
   bool mWaitToRespond;
 protected:
   explicit FetchEvent(EventTarget* aOwner);
   ~FetchEvent();
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
@@ -146,23 +145,16 @@ public:
   {
     return mIsReload;
   }
 
   void
   RespondWith(Promise& aArg, ErrorResult& aRv);
 
   already_AddRefed<Promise>
-  GetPromise() const
-  {
-    RefPtr<Promise> p = mPromise;
-    return p.forget();
-  }
-
-  already_AddRefed<Promise>
   ForwardTo(const nsAString& aUrl);
 
   already_AddRefed<Promise>
   Default();
 };
 
 #ifndef MOZ_SIMPLEPUSH
 
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1170,21 +1170,21 @@ private:
         runnable = new CancelChannelRunnable(mInterceptedChannel, NS_ERROR_INTERCEPTION_CANCELED);
       } else {
         runnable = new ResumeRequest(mInterceptedChannel);
       }
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
     }
 
-    RefPtr<Promise> respondWithPromise = event->GetPromise();
-    if (respondWithPromise) {
+    RefPtr<Promise> waitUntilPromise = event->GetPromise();
+    if (waitUntilPromise) {
       RefPtr<KeepAliveHandler> keepAliveHandler =
         new KeepAliveHandler(mKeepAliveToken);
-      respondWithPromise->AppendNativeHandler(keepAliveHandler);
+      waitUntilPromise->AppendNativeHandler(keepAliveHandler);
     }
 
     // 9.8.22 If request is a non-subresource request, then: Invoke Soft Update algorithm
     if (internalReq->IsNavigationRequest()) {
       nsCOMPtr<nsIRunnable> runnable= new SoftUpdateRequest(mRegistration);
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable.forget())));
     }
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ae6a8a6b88403959c75efce931b0bf4293efc956
GIT binary patch
literal 87
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=oTrOph(&MmkMjpU%%3$Q@ydZf
kW_Mm0(}F7pCT1xxd^;`67yW*X5Ktw9r>mdKI;Vst0D!m{_W%F@
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fe391dc8a2d797360651fe8cf77161a3fc891194
GIT binary patch
literal 123
zc%17D@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEPM$7~ArY-_&utWBP~c%$*z@jL
z8rOSWjTbX5i}z1sXJLKaupmKJKx7SbQ&Xu!zy>}Ju4{~r2dxw|BEXUllDQ?<M0xZq
S5i$mv#^CAd=d#Wzp$PyI1tgjP
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache-maxage/index.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<script>
+var width, url, width2, url2;
+function maybeReport() {
+  if (width !== undefined && url !== undefined &&
+      width2 !== undefined && url2 !== undefined) {
+    window.parent.postMessage({status: "result",
+                               width: width,
+                               width2: width2,
+                               url: url,
+                               url2: url2}, "*");
+  }
+}
+onload = function() {
+  width = document.querySelector("img").width;
+  width2 = document.querySelector("img").width;
+  maybeReport();
+};
+navigator.serviceWorker.onmessage = function(event) {
+  if (event.data.suffix == "2") {
+    url2 = event.data.url;
+  } else {
+    url = event.data.url;
+  }
+  maybeReport();
+};
+</script>
+<img src="image.png">
+<img src="image2.png">
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache-maxage/maxage_test.js
@@ -0,0 +1,41 @@
+function synthesizeImage(suffix) {
+  // Serve image-20px for the first page, and image-40px for the second page.
+  return clients.matchAll().then(clients => {
+    var url = "image-20px.png";
+    clients.forEach(client => {
+      if (client.url.indexOf("?new") > 0) {
+        url = "image-40px.png";
+      }
+      client.postMessage({suffix: suffix, url: url});
+    });
+    return fetch(url);
+  }).then(response => {
+    return response.arrayBuffer();
+  }).then(ab => {
+    var headers;
+    if (suffix == "") {
+      headers = {
+        "Content-Type": "image/png",
+        "Date": "Tue, 1 Jan 1990 01:02:03 GMT",
+        "Cache-Control": "max-age=1",
+      };
+    } else {
+      headers = {
+        "Content-Type": "image/png",
+        "Cache-Control": "no-cache",
+      };
+    }
+    return new Response(ab, {
+      status: 200,
+      headers: headers,
+    });
+  });
+}
+
+self.addEventListener("fetch", function(event) {
+  if (event.request.url.indexOf("image.png") >= 0) {
+    event.respondWith(synthesizeImage(""));
+  } else if (event.request.url.indexOf("image2.png") >= 0) {
+    event.respondWith(synthesizeImage("2"));
+  }
+});
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache-maxage/register.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script>
+  function ok(v, msg) {
+    window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
+  }
+
+  function done(reg) {
+    ok(reg.active, "The active worker should be available.");
+    window.parent.postMessage({status: "registrationdone"}, "*");
+  }
+
+  navigator.serviceWorker.ready.then(done);
+  navigator.serviceWorker.register("maxage_test.js", {scope: "."});
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/imagecache-maxage/unregister.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script>
+  navigator.serviceWorker.getRegistration(".").then(function(registration) {
+    registration.unregister().then(function(success) {
+      if (success) {
+        window.parent.postMessage({status: "unregistrationdone"}, "*");
+      }
+    }, function(e) {
+      dump("Unregistering the SW failed with " + e + "\n");
+    });
+  });
+</script>
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -54,16 +54,22 @@ support-files =
   fetch/https/index.html
   fetch/https/register.html
   fetch/https/unregister.html
   fetch/https/https_test.js
   fetch/https/clonedresponse/index.html
   fetch/https/clonedresponse/register.html
   fetch/https/clonedresponse/unregister.html
   fetch/https/clonedresponse/https_test.js
+  fetch/imagecache-maxage/index.html
+  fetch/imagecache-maxage/image-20px.png
+  fetch/imagecache-maxage/image-40px.png
+  fetch/imagecache-maxage/maxage_test.js
+  fetch/imagecache-maxage/register.html
+  fetch/imagecache-maxage/unregister.html
   fetch/interrupt.sjs
   fetch/origin/index.sjs
   fetch/origin/index-to-https.sjs
   fetch/origin/realindex.html
   fetch/origin/realindex.html^headers^
   fetch/origin/register.html
   fetch/origin/unregister.html
   fetch/origin/origin_test.js
@@ -277,8 +283,9 @@ skip-if = toolkit == "android" || toolki
 [test_unresolved_fetch_interception.html]
 [test_hsts_upgrade_intercept.html]
 skip-if = e10s # Bug 1214305
 [test_csp_upgrade-insecure_intercept.html]
 skip-if = e10s # Bug 1214305
 [test_serviceworker_header.html]
 [test_openWindow.html]
 skip-if = toolkit == "android" || toolkit == "gonk" || e10s
+[test_imagecache_max_age.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_imagecache_max_age.html
@@ -0,0 +1,75 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test that the image cache respects a synthesized image's Cache headers</title>
+  <script type="text/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">
+<iframe></iframe>
+</div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  var iframe;
+  var framesLoaded = 0;
+  function runTest() {
+    iframe = document.querySelector("iframe");
+    iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/register.html";
+    window.onmessage = function(e) {
+      if (e.data.status == "ok") {
+        ok(e.data.result, e.data.message);
+      } else if (e.data.status == "registrationdone") {
+        iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/index.html";
+      } else if (e.data.status == "result") {
+        switch (++framesLoaded) {
+        case 1:
+          is(e.data.url, "image-20px.png", "Correct url expected");
+          is(e.data.url2, "image-20px.png", "Correct url expected");
+          is(e.data.width, 20, "Correct width expected");
+          is(e.data.width2, 20, "Correct width expected");
+          // Wait for 100ms so that the image gets expired.
+          setTimeout(function() {
+            iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/index.html?new"
+          }, 100);
+          break;
+        case 2:
+          is(e.data.url, "image-40px.png", "Correct url expected");
+          is(e.data.url2, "image-40px.png", "Correct url expected");
+          // TODO: Uncomment this check when bug 1217571 gets fixed.
+          // Currently because of bug 1217571, the QI in imgCacheValidator::OnStartRequest()
+          // to nsICachingChannel fails, which causes the check below to fail in non-e10s.
+          //is(e.data.width, 40, "Correct width expected");
+          //is(e.data.width2, 40, "Correct width expected");
+          iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/imagecache-maxage/unregister.html";
+          break;
+        default:
+          ok(false, "This should never happen");
+        }
+      } else if (e.data.status == "unregistrationdone") {
+        window.onmessage = null;
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  SimpleTest.requestFlakyTimeout("This test needs to simulate the passing of time");
+  SimpleTest.waitForExplicitFinish();
+  onload = function() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+      ["dom.serviceWorkers.enabled", true],
+      ["dom.serviceWorkers.testing.enabled", true],
+      ["dom.serviceWorkers.interception.enabled", true],
+    ]}, runTest);
+  };
+</script>
+</pre>
+</body>
+</html>
--- a/dom/xbl/test/test_bug389322.xhtml
+++ b/dom/xbl/test/test_bug389322.xhtml
@@ -111,16 +111,16 @@ function report(testName, success) {
     var success = true;
   }
   catch (e) { success = false; }
   report("HTML script tags with explicit version", success)
 ]]></script>
 <script type="text/javascript"><![CDATA[
   try {
     eval("let x = 1;");
-    var success = false;
+    var success = true;
   }
-  catch (e) { success = true; }
-  is(success, true, "JS 1.7 should not work in versionless HTML script tags");
+  catch (e) { success = false; }
+  is(success, true, "let should work in versionless HTML script tags");
 ]]></script>
 </pre>
 </body>
 </html>
--- a/editor/libeditor/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/nsHTMLDataTransfer.cpp
@@ -1016,73 +1016,62 @@ nsHTMLEditor::ParseCFHTML(nsCString & aC
 nsresult nsHTMLEditor::InsertObject(const char* aType, nsISupports* aObject, bool aIsSafe,
                                     nsIDOMDocument *aSourceDoc,
                                     nsIDOMNode *aDestinationNode,
                                     int32_t aDestOffset,
                                     bool aDoDeleteSelection)
 {
   nsresult rv;
 
-  const char* type = aType;
+  nsAutoCString type(aType);
 
   // Check to see if we can insert an image file
   bool insertAsImage = false;
-  nsCOMPtr<nsIURI> fileURI;
-  if (0 == nsCRT::strcmp(type, kFileMime))
+  nsCOMPtr<nsIFile> fileObj;
+  if (type.EqualsLiteral(kFileMime))
   {
-    nsCOMPtr<nsIFile> fileObj = do_QueryInterface(aObject);
+    fileObj = do_QueryInterface(aObject);
     if (fileObj)
     {
-      rv = NS_NewFileURI(getter_AddRefs(fileURI), fileObj);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      nsCOMPtr<nsIMIMEService> mime = do_GetService("@mozilla.org/mime;1");
-      NS_ENSURE_TRUE(mime, NS_ERROR_FAILURE);
-      nsAutoCString contentType;
-      rv = mime->GetTypeFromFile(fileObj, contentType);
-      NS_ENSURE_SUCCESS(rv, rv);
-
       // Accept any image type fed to us
-      if (StringBeginsWith(contentType, NS_LITERAL_CSTRING("image/"))) {
+      if (nsContentUtils::IsFileImage(fileObj, type))
+      {
         insertAsImage = true;
-        type = contentType.get();
+      }
+      else
+      {
+        // Reset type.
+        type.AssignLiteral(kFileMime);
       }
     }
   }
 
-  if (0 == nsCRT::strcmp(type, kJPEGImageMime) ||
-      0 == nsCRT::strcmp(type, kJPGImageMime) ||
-      0 == nsCRT::strcmp(type, kPNGImageMime) ||
-      0 == nsCRT::strcmp(type, kGIFImageMime) ||
+  if (type.EqualsLiteral(kJPEGImageMime) ||
+      type.EqualsLiteral(kJPGImageMime) ||
+      type.EqualsLiteral(kPNGImageMime) ||
+      type.EqualsLiteral(kGIFImageMime) ||
       insertAsImage)
   {
-    nsCOMPtr<nsIInputStream> imageStream;
-    if (insertAsImage) {
-      NS_ASSERTION(fileURI, "The file URI should be retrieved earlier");
-
-      nsCOMPtr<nsIChannel> channel;
-      rv = NS_NewChannel(getter_AddRefs(channel),
-                         fileURI,
-                         nsContentUtils::GetSystemPrincipal(),
-                         nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
-                         nsIContentPolicy::TYPE_OTHER);
+    nsCString imageData;
+    if (insertAsImage)
+    {
+      rv = nsContentUtils::SlurpFileToString(fileObj, imageData);
       NS_ENSURE_SUCCESS(rv, rv);
-      rv = channel->Open2(getter_AddRefs(imageStream));
-      NS_ENSURE_SUCCESS(rv, rv);
-    } else {
-      imageStream = do_QueryInterface(aObject);
+    }
+    else
+    {
+      nsCOMPtr<nsIInputStream> imageStream = do_QueryInterface(aObject);
       NS_ENSURE_TRUE(imageStream, NS_ERROR_FAILURE);
-    }
 
-    nsCString imageData;
-    rv = NS_ConsumeStream(imageStream, UINT32_MAX, imageData);
-    NS_ENSURE_SUCCESS(rv, rv);
+      rv = NS_ConsumeStream(imageStream, UINT32_MAX, imageData);
+      NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = imageStream->Close();
-    NS_ENSURE_SUCCESS(rv, rv);
+      rv = imageStream->Close();
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
 
     nsAutoCString data64;
     rv = Base64Encode(imageData, data64);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsAutoString stuffToPaste;
     stuffToPaste.AssignLiteral("<IMG src=\"data:");
     AppendUTF8toUTF16(type, stuffToPaste);
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1611,17 +1611,19 @@ public:
 
   static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); }
 
   /**
    * Returns the current area of the layer (in layer-space coordinates)
    * marked as needed to be recomposited.
    */
   const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; }
-  const void SetInvalidRegion(const nsIntRegion& aRect) { mInvalidRegion = aRect; }
+  const void AddInvalidRegion(const nsIntRegion& aRegion) {
+    mInvalidRegion.Or(mInvalidRegion, aRegion);
+  }
 
   /**
    * Mark the entirety of the layer's visible region as being invalid.
    */
   void SetInvalidRectToVisibleRegion() { mInvalidRegion = GetVisibleRegion(); }
 
   /**
    * Adds to the current invalid rect.
--- a/gfx/layers/RotatedBuffer.cpp
+++ b/gfx/layers/RotatedBuffer.cpp
@@ -301,19 +301,22 @@ RotatedContentBuffer::BorrowDrawTargetFo
                                                  -quadrantRect.y));
 
   return mLoanedDrawTarget;
 }
 
 void
 BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
 {
+  MOZ_ASSERT(mLoanedDrawTarget);
   MOZ_ASSERT(aReturned == mLoanedDrawTarget);
-  mLoanedDrawTarget->SetTransform(mLoanedTransform);
-  mLoanedDrawTarget = nullptr;
+  if (mLoanedDrawTarget) {
+    mLoanedDrawTarget->SetTransform(mLoanedTransform);
+    mLoanedDrawTarget = nullptr;
+  }
   aReturned = nullptr;
 }
 
 gfxContentType
 RotatedContentBuffer::BufferContentType()
 {
   if (mBufferProvider || mDTBuffer) {
     SurfaceFormat format;
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -143,16 +143,17 @@ void
 LayerManagerComposite::Destroy()
 {
   if (!mDestroyed) {
     mCompositor->GetWidget()->CleanupWindowEffects();
     if (mRoot) {
       RootLayer()->Destroy();
     }
     mRoot = nullptr;
+    mClonedLayerTreeProperties = nullptr;
     mDestroyed = true;
   }
 }
 
 void
 LayerManagerComposite::UpdateRenderBounds(const IntRect& aRect)
 {
   mRenderBounds = aRect;
@@ -170,18 +171,16 @@ LayerManagerComposite::BeginTransaction(
 {
   mInTransaction = true;
   
   if (!mCompositor->Ready()) {
     return;
   }
   
   mIsCompositorReady = true;
-
-  mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
 }
 
 void
 LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget, const IntRect& aRect)
 {
   mInTransaction = true;
   
   if (!mCompositor->Ready()) {
@@ -277,64 +276,97 @@ LayerManagerComposite::EndTransaction(co
     return;
   }
 
   // Set composition timestamp here because we need it in
   // ComputeEffectiveTransforms (so the correct video frame size is picked) and
   // also to compute invalid regions properly.
   mCompositor->SetCompositionTime(aTimeStamp);
 
-  if (mRoot && mClonedLayerTreeProperties) {
-    MOZ_ASSERT(!mTarget);
-    nsIntRegion invalid =
-      mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);
-    mClonedLayerTreeProperties = nullptr;
-
-    mInvalidRegion.Or(mInvalidRegion, invalid);
-  } else if (!mTarget) {
-    mInvalidRegion.Or(mInvalidRegion, mRenderBounds);
-  }
-
-  if (mInvalidRegion.IsEmpty() && !mTarget) {
-    // Composition requested, but nothing has changed. Don't do any work.
-    return;
-  }
-
-  // We don't want our debug overlay to cause more frames to happen
-  // so we will invalidate after we've decided if something changed.
-  InvalidateDebugOverlay(mRenderBounds);
-
- if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
+  if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     MOZ_ASSERT(!aTimeStamp.IsNull());
-    // The results of our drawing always go directly into a pixel buffer,
-    // so we don't need to pass any global transform here.
-    mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
-
-    nsIntRegion opaque;
-    ApplyOcclusionCulling(mRoot, opaque);
-
-    Render();
-#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
-    RenderToPresentationSurface();
-#endif
-    mGeometryChanged = false;
+    UpdateAndRender();
   } else {
-    // Modified layer tree
+    // Modified the layer tree.
     mGeometryChanged = true;
   }
 
   mCompositor->ClearTargetContext();
   mTarget = nullptr;
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   Log();
   MOZ_LAYERS_LOG(("]----- EndTransaction"));
 #endif
 }
 
+void
+LayerManagerComposite::UpdateAndRender()
+{
+  nsIntRegion invalid;
+
+  if (mClonedLayerTreeProperties) {
+    // We need to compute layer tree differences even if we're not going to
+    // immediately use the resulting damage area, since ComputeDifferences
+    // is also responsible for invalidates intermediate surfaces in
+    // ContainerLayers.
+    nsIntRegion changed = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged);
+
+    if (mTarget) {
+      // Since we're composing to an external target, we're not going to use
+      // the damage region from layers changes - we want to composite
+      // everything in the target bounds. Instead we accumulate the layers
+      // damage region for the next window composite.
+      mInvalidRegion.Or(mInvalidRegion, changed);
+    } else {
+      invalid = Move(changed);
+    }
+  }
+
+  if (mTarget) {
+    invalid.Or(invalid, mTargetBounds);
+  } else {
+    // If we didn't have a previous layer tree, invalidate the entire render
+    // area.
+    if (!mClonedLayerTreeProperties) {
+      invalid.Or(invalid, mRenderBounds);
+    }
+
+    // Add any additional invalid rects from the window manager or previous
+    // damage computed during ComposeToTarget().
+    invalid.Or(invalid, mInvalidRegion);
+    mInvalidRegion.SetEmpty();
+  }
+
+  // Update cached layer tree information.
+  mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
+
+  if (invalid.IsEmpty()) {
+    // Composition requested, but nothing has changed. Don't do any work.
+    return;
+  }
+
+  // We don't want our debug overlay to cause more frames to happen
+  // so we will invalidate after we've decided if something changed.
+  InvalidateDebugOverlay(mRenderBounds);
+
+  // The results of our drawing always go directly into a pixel buffer,
+  // so we don't need to pass any global transform here.
+  mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
+
+  nsIntRegion opaque;
+  ApplyOcclusionCulling(mRoot, opaque);
+
+  Render(invalid);
+#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
+  RenderToPresentationSurface();
+#endif
+  mGeometryChanged = false;
+}
+
 already_AddRefed<DrawTarget>
 LayerManagerComposite::CreateOptimalMaskDrawTarget(const IntSize &aSize)
 {
   NS_RUNTIMEABORT("Should only be called on the drawing side");
   return nullptr;
 }
 
 already_AddRefed<PaintedLayer>
@@ -636,17 +668,17 @@ LayerManagerComposite::PopGroupForLayerE
   effectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX] = new EffectColorMatrix(effectMatrix);
 
   gfx::Rect clipRectF(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
   mCompositor->DrawQuad(Rect(Point(0, 0), Size(mTwoPassTmpTarget->GetSize())), clipRectF, effectChain, 1.,
                         Matrix4x4());
 }
 
 void
-LayerManagerComposite::Render()
+LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
 {
   PROFILER_LABEL("LayerManagerComposite", "Render",
     js::ProfileEntry::Category::GRAPHICS);
 
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
@@ -696,55 +728,44 @@ LayerManagerComposite::Render()
     LayerScope::SetHWComposed();
     if (mFPS) {
       double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
       if (gfxPrefs::LayersDrawFPS()) {
         printf_stderr("HWComposer: FPS is %g\n", fps);
       }
     }
     mCompositor->EndFrameForExternalComposition(Matrix());
-    // Reset the invalid region as compositing is done
-    mInvalidRegion.SetEmpty();
     mLastFrameMissedHWC = false;
     return;
   } else if (!mTarget && !haveLayerEffects) {
     mLastFrameMissedHWC = !!composer2D;
   }
 
   {
     PROFILER_LABEL("LayerManagerComposite", "PreRender",
       js::ProfileEntry::Category::GRAPHICS);
 
     if (!mCompositor->GetWidget()->PreRender(this)) {
       return;
     }
   }
 
-  nsIntRegion invalid;
-  if (mTarget) {
-    invalid = mTargetBounds;
-  } else {
-    invalid = mInvalidRegion;
-    // Reset the invalid region now that we've begun compositing.
-    mInvalidRegion.SetEmpty();
-  }
-
   ParentLayerIntRect clipRect;
   Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height);
   Rect actualBounds;
 
   CompositorBench(mCompositor, bounds);
 
   if (mRoot->GetClipRect()) {
     clipRect = *mRoot->GetClipRect();
     Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
-    mCompositor->BeginFrame(invalid, &rect, bounds, nullptr, &actualBounds);
+    mCompositor->BeginFrame(aInvalidRegion, &rect, bounds, nullptr, &actualBounds);
   } else {
     gfx::Rect rect;
-    mCompositor->BeginFrame(invalid, nullptr, bounds, &rect, &actualBounds);
+    mCompositor->BeginFrame(aInvalidRegion, nullptr, bounds, &rect, &actualBounds);
     clipRect = ParentLayerIntRect(rect.x, rect.y, rect.width, rect.height);
   }
 
   if (actualBounds.IsEmpty()) {
     mCompositor->GetWidget()->PostRender(this);
     return;
   }
 
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -293,19 +293,24 @@ private:
    * accumulated transform of intermediate surfaces beneath aLayer.
    */
   static void ComputeRenderIntegrityInternal(Layer* aLayer,
                                              nsIntRegion& aScreenRegion,
                                              nsIntRegion& aLowPrecisionScreenRegion,
                                              const gfx::Matrix4x4& aTransform);
 
   /**
+   * Update the invalid region and render it.
+   */
+  void UpdateAndRender();
+
+  /**
    * Render the current layer tree to the active target.
    */
-  void Render();
+  void Render(const nsIntRegion& aInvalidRegion);
 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
   void RenderToPresentationSurface();
 #endif
 
   /**
    * We need to know our invalid region before we're ready to render.
    */
   void InvalidateDebugOverlay(const gfx::IntRect& aBounds);
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -340,20 +340,23 @@ LayerTransactionParent::RecvUpdate(Infal
       layer->SetMixBlendMode((gfx::CompositionOp)common.mixBlendMode());
       layer->SetForceIsolatedGroup(common.forceIsolatedGroup());
       if (PLayerParent* maskLayer = common.maskLayerParent()) {
         layer->SetMaskLayer(cast(maskLayer)->AsLayer());
       } else {
         layer->SetMaskLayer(nullptr);
       }
       layer->SetAnimations(common.animations());
-      layer->SetInvalidRegion(common.invalidRegion());
       layer->SetFrameMetrics(common.metrics());
       layer->SetDisplayListLog(common.displayListLog().get());
 
+      // The updated invalid region is added to the existing one, since we can
+      // update multiple times before the next composite.
+      layer->AddInvalidRegion(common.invalidRegion());
+
       nsTArray<RefPtr<Layer>> maskLayers;
       for (size_t i = 0; i < common.ancestorMaskLayersParent().Length(); i++) {
         Layer* maskLayer = cast(common.ancestorMaskLayersParent().ElementAt(i))->AsLayer();
         maskLayers.AppendElement(maskLayer);
       }
       layer->SetAncestorMaskLayers(maskLayers);
 
       typedef SpecificLayerAttributes Specific;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -289,16 +289,17 @@ private:
   DECL_GFX_PREF(Once, "image.multithreaded_decoding.limit",    ImageMTDecodingLimit, int32_t, -1);
   DECL_GFX_PREF(Live, "image.single-color-optimization.enabled", ImageSingleColorOptimizationEnabled, bool, true);
 
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabled, bool, false);
+  DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled",     LayersAMDSwitchableGfxEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled",         AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
   DECL_GFX_PREF(Live, "layers.bench.enabled",                  LayersBenchEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.bufferrotation.enabled",         BufferRotationEnabled, bool, true);
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
   // If MOZ_GFX_OPTIMIZE_MOBILE is defined, we force component alpha off
   // and ignore the preference.
   DECL_GFX_PREF(Skip, "layers.componentalpha.enabled",         ComponentAlphaEnabled, bool, false);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1853,36 +1853,49 @@ bool DoesD3D11TextureSharingWorkInternal
 
   if (GetModuleHandleW(L"atidxx32.dll")) {
     nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
     if (gfxInfo) {
       nsString vendorID, vendorID2;
       gfxInfo->GetAdapterVendorID(vendorID);
       gfxInfo->GetAdapterVendorID2(vendorID2);
       if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) {
-        gfxCriticalError(CriticalLog::DefaultOptions(false)) << "Unexpected Intel/AMD dual-GPU setup";
-        return false;
+        if (!gfxPrefs::LayersAMDSwitchableGfxEnabled()) {
+          return false;
+        }
+        gfxCriticalError(CriticalLog::DefaultOptions(false)) << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU";
       }
     }
   }
 
   RefPtr<ID3D11Texture2D> texture;
   D3D11_TEXTURE2D_DESC desc;
-  desc.Width = 32;
-  desc.Height = 32;
+  const int texture_size = 32;
+  desc.Width = texture_size;
+  desc.Height = texture_size;
   desc.MipLevels = 1;
   desc.ArraySize = 1;
   desc.Format = format;
   desc.SampleDesc.Count = 1;
   desc.SampleDesc.Quality = 0;
   desc.Usage = D3D11_USAGE_DEFAULT;
   desc.CPUAccessFlags = 0;
   desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
   desc.BindFlags = bindflags;
-  if (FAILED(device->CreateTexture2D(&desc, NULL, getter_AddRefs(texture)))) {
+
+  uint32_t color[texture_size * texture_size];
+  for (size_t i = 0; i < sizeof(color)/sizeof(color[0]); i++) {
+    color[i] = 0xff00ffff;
+  }
+  // We're going to check that sharing actually works with this format
+  D3D11_SUBRESOURCE_DATA data;
+  data.pSysMem = color;
+  data.SysMemPitch = texture_size * 4;
+  data.SysMemSlicePitch = 0;
+  if (FAILED(device->CreateTexture2D(&desc, &data, getter_AddRefs(texture)))) {
     return false;
   }
 
   HANDLE shareHandle;
   RefPtr<IDXGIResource> otherResource;
   if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource),
                                      getter_AddRefs(otherResource))))
   {
@@ -1903,16 +1916,60 @@ bool DoesD3D11TextureSharingWorkInternal
   }
 
   if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D),
                                             getter_AddRefs(sharedTexture))))
   {
     return false;
   }
 
+  // create a staging texture for readback
+  RefPtr<ID3D11Texture2D> cpuTexture;
+  desc.Usage = D3D11_USAGE_STAGING;
+  desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+  desc.MiscFlags = 0;
+  desc.BindFlags = 0;
+  if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(cpuTexture)))) {
+    return false;
+  }
+
+  RefPtr<IDXGIKeyedMutex> sharedMutex;
+  RefPtr<ID3D11DeviceContext> deviceContext;
+  sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sharedMutex));
+  device->GetImmediateContext(getter_AddRefs(deviceContext));
+  if (FAILED(sharedMutex->AcquireSync(0, 30*1000))) {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout";
+    // only wait for 30 seconds
+    return false;
+  }
+
+  // Copy to the cpu texture so that we can readback
+  deviceContext->CopyResource(cpuTexture, sharedTexture);
+
+  D3D11_MAPPED_SUBRESOURCE mapped;
+  int resultColor = 0;
+  if (SUCCEEDED(deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) {
+    // read the texture
+    resultColor = *(int*)mapped.pData;
+    deviceContext->Unmap(cpuTexture, 0);
+  } else {
+    gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed";
+    return false;
+  }
+
+  sharedMutex->ReleaseSync(0);
+
+  // check that the color we put in is the color we get out
+  if (resultColor != color[0]) {
+    // Shared surfaces seem to be broken on dual AMD & Intel HW when using the
+    // AMD GPU
+    gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch";
+    return false;
+  }
+
   RefPtr<ID3D11ShaderResourceView> sharedView;
 
   // This if(FAILED()) is the one that actually fails on systems affected by bug 1083071.
   if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, getter_AddRefs(sharedView)))) {
     gfxCriticalNote << "CreateShaderResourceView failed for format" << format;
     return false;
   }
 
rename from image/BMPFileHeaders.h
rename to image/BMPHeaders.h
--- a/image/BMPFileHeaders.h
+++ b/image/BMPHeaders.h
@@ -1,84 +1,38 @@
 /* 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_image_BMPFileHeaders_h
-#define mozilla_image_BMPFileHeaders_h
+#ifndef mozilla_image_BMPHeaders_h
+#define mozilla_image_BMPHeaders_h
 
 #include <stddef.h>
 #include <stdint.h>
 
 namespace mozilla {
 namespace image {
 namespace bmp {
 
-// This length is stored in the |bihsize| field of bmp::FileHeader.
+// The length of the file header as defined in the BMP spec.
+static const size_t FILE_HEADER_LENGTH = 14;
+
+// This lengths of the info header for the different BMP versions.
 struct InfoHeaderLength {
   enum {
     WIN_V2 = 12,
     WIN_V3 = 40,
     WIN_V4 = 108,
     WIN_V5 = 124,
 
     // OS2_V1 is omitted; it's the same as WIN_V2.
     OS2_V2_MIN = 16,    // Minimum allowed value for OS2v2.
     OS2_V2_MAX = 64,    // Maximum allowed value for OS2v2.
+
+    WIN_ICO = WIN_V3,
   };
 };
 
-struct FileHeader {
-  char signature[2];   // String "BM".
-  uint32_t filesize;   // File size; unreliable in practice.
-  int32_t reserved;    // Zero.
-  uint32_t dataoffset; // Offset to raster data.
-
-  // The length of the file header as defined in the BMP spec.
-  static const size_t LENGTH = 14;
-};
-
-struct XYZ {
-  int32_t x, y, z;
-};
-
-struct XYZTriple {
-  XYZ r, g, b;
-};
-
-struct V5InfoHeader {
-  uint32_t bihsize;          // Header size
-  int32_t width;             // Uint16 in OS/2 BMPs
-  int32_t height;            // Uint16 in OS/2 BMPs
-  uint16_t planes;           // =1
-  uint16_t bpp;              // Bits per pixel.
-  // The rest of the header is not available in WIN_V2/OS2_V1 BMP Files
-  uint32_t compression;      // See Compression for valid values
-  uint32_t image_size;       // (compressed) image size. Can be 0 if
-                             // compression==0
-  uint32_t xppm;             // Pixels per meter, horizontal
-  uint32_t yppm;             // Pixels per meter, vertical
-  uint32_t colors;           // Used Colors
-  uint32_t important_colors; // Number of important colors. 0=all
-  uint32_t red_mask;         // Bits used for red component
-  uint32_t green_mask;       // Bits used for green component
-  uint32_t blue_mask;        // Bits used for blue component
-  uint32_t alpha_mask;       // Bits used for alpha component
-  uint32_t color_space;      // 0x73524742=LCS_sRGB ...
-  // These members are unused unless color_space == LCS_CALIBRATED_RGB
-  XYZTriple white_point;     // Logical white point
-  uint32_t gamma_red;        // Red gamma component
-  uint32_t gamma_green;      // Green gamma component
-  uint32_t gamma_blue;       // Blue gamma component
-  uint32_t intent;           // Rendering intent
-  // These members are unused unless color_space == LCS_PROFILE_*
-  uint32_t profile_offset;   // Offset to profile data in bytes
-  uint32_t profile_size;     // Size of profile data in bytes
-  uint32_t reserved;         // =0
-
-  static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742;
-};
-
 } // namespace bmp
 } // namespace image
 } // namespace mozilla
 
-#endif // mozilla_image_BMPFileHeaders_h
+#endif // mozilla_image_BMPHeaders_h
--- a/image/Downscaler.cpp
+++ b/image/Downscaler.cpp
@@ -101,35 +101,35 @@ Downscaler::BeginFrame(const nsIntSize& 
 
   skia::resize::ComputeFilters(resizeMethod,
                                mOriginalSize.height, mTargetSize.height,
                                0, mTargetSize.height,
                                mYFilter.get());
 
   // Allocate the buffer, which contains scanlines of the original image.
   // pad by 15 to handle overreads by the simd code
-  mRowBuffer = MakeUnique<uint8_t[]>(mOriginalSize.width * sizeof(uint32_t) + 15);
+  mRowBuffer.reset(new (fallible) uint8_t[mOriginalSize.width * sizeof(uint32_t) + 15]);
   if (MOZ_UNLIKELY(!mRowBuffer)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // Allocate the window, which contains horizontally downscaled scanlines. (We
   // can store scanlines which are already downscale because our downscaling
   // filter is separable.)
   mWindowCapacity = mYFilter->max_filter();
-  mWindow = MakeUnique<uint8_t*[]>(mWindowCapacity);
+  mWindow.reset(new (fallible) uint8_t*[mWindowCapacity]);
   if (MOZ_UNLIKELY(!mWindow)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   bool anyAllocationFailed = false;
   // pad by 15 to handle overreads by the simd code
   const int rowSize = mTargetSize.width * sizeof(uint32_t) + 15;
   for (int32_t i = 0; i < mWindowCapacity; ++i) {
-    mWindow[i] = new uint8_t[rowSize];
+    mWindow[i] = new (fallible) uint8_t[rowSize];
     anyAllocationFailed = anyAllocationFailed || mWindow[i] == nullptr;
   }
 
   if (MOZ_UNLIKELY(anyAllocationFailed)) {
     // We intentionally iterate through the entire array even if an allocation
     // fails, to ensure that all the pointers in it are either valid or nullptr.
     // That in turn ensures that ReleaseWindow() can clean up correctly.
     return NS_ERROR_OUT_OF_MEMORY;
--- a/image/SourceBuffer.h
+++ b/image/SourceBuffer.h
@@ -268,63 +268,61 @@ private:
   class Chunk
   {
   public:
     explicit Chunk(size_t aCapacity)
       : mCapacity(aCapacity)
       , mLength(0)
     {
       MOZ_ASSERT(aCapacity > 0, "Creating zero-capacity chunk");
-      mData = new (fallible) char[mCapacity];
+      mData.reset(new (fallible) char[mCapacity]);
     }
 
-    ~Chunk() { delete[] mData; }
-
     Chunk(Chunk&& aOther)
       : mCapacity(aOther.mCapacity)
       , mLength(aOther.mLength)
-      , mData(aOther.mData)
+      , mData(Move(aOther.mData))
     {
       aOther.mCapacity = aOther.mLength = 0;
       aOther.mData = nullptr;
     }
 
     Chunk& operator=(Chunk&& aOther)
     {
       mCapacity = aOther.mCapacity;
       mLength = aOther.mLength;
-      mData = aOther.mData;
+      mData = Move(aOther.mData);
       aOther.mCapacity = aOther.mLength = 0;
       aOther.mData = nullptr;
       return *this;
     }
 
     bool AllocationFailed() const { return !mData; }
     size_t Capacity() const { return mCapacity; }
     size_t Length() const { return mLength; }
 
     char* Data() const
     {
       MOZ_ASSERT(mData, "Allocation failed but nobody checked for it");
-      return mData;
+      return mData.get();
     }
 
     void AddLength(size_t aAdditionalLength)
     {
       MOZ_ASSERT(mLength + aAdditionalLength <= mCapacity);
       mLength += aAdditionalLength;
     }
 
   private:
     Chunk(const Chunk&) = delete;
     Chunk& operator=(const Chunk&) = delete;
 
     size_t mCapacity;
     size_t mLength;
-    char* mData;
+    UniquePtr<char[]> mData;
   };
 
   nsresult AppendChunk(Maybe<Chunk>&& aChunk);
   Maybe<Chunk> CreateChunk(size_t aCapacity, bool aRoundUp = true);
   nsresult Compact();
   static size_t RoundedUpCapacity(size_t aCapacity);
   size_t FibonacciCapacityWithMinimum(size_t aMinCapacity);
 
--- a/image/decoders/icon/win/nsIconChannel.cpp
+++ b/image/decoders/icon/win/nsIconChannel.cpp
@@ -570,21 +570,21 @@ nsIconChannel::MakeInputStream(nsIInputS
           (colorTableSize = GetColorTableSize(&colorHeader)) >= 0 &&
           (maskTableSize  = GetColorTableSize(&maskHeader))  >= 0) {
         uint32_t iconSize = sizeof(ICONFILEHEADER) +
                             sizeof(ICONENTRY) +
                             sizeof(BITMAPINFOHEADER) +
                             colorHeader.biSizeImage +
                             maskHeader.biSizeImage;
 
-        char* buffer = new char[iconSize];
+        UniquePtr<char[]> buffer = MakeUnique<char[]>(iconSize);
         if (!buffer) {
           rv = NS_ERROR_OUT_OF_MEMORY;
         } else {
-          char* whereTo = buffer;
+          char* whereTo = buffer.get();
           int howMuch;
 
           // the data starts with an icon file header
           ICONFILEHEADER iconHeader;
           iconHeader.ifhReserved = 0;
           iconHeader.ifhType = 1;
           iconHeader.ifhCount = 1;
           howMuch = sizeof(ICONFILEHEADER);
@@ -635,27 +635,26 @@ nsIconChannel::MakeInputStream(nsIInputS
               // Now, create a pipe and stuff our data into it
               nsCOMPtr<nsIInputStream> inStream;
               nsCOMPtr<nsIOutputStream> outStream;
               rv = NS_NewPipe(getter_AddRefs(inStream),
                               getter_AddRefs(outStream),
                               iconSize, iconSize, aNonBlocking);
               if (NS_SUCCEEDED(rv)) {
                 uint32_t written;
-                rv = outStream->Write(buffer, iconSize, &written);
+                rv = outStream->Write(buffer.get(), iconSize, &written);
                 if (NS_SUCCEEDED(rv)) {
                   NS_ADDREF(*_retval = inStream);
                 }
               }
 
             } // if we got bitmap bits
             delete maskInfo;
           } // if we got mask bits
           delete colorInfo;
-          delete [] buffer;
         } // if we allocated the buffer
       } // if we got mask size
 
       DeleteDC(hDC);
       DeleteObject(iconInfo.hbmColor);
       DeleteObject(iconInfo.hbmMask);
     } // if we got icon info
     DestroyIcon(hIcon);
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -20,38 +20,38 @@
 //
 // WINDOWS VERSIONS OF THE BMP FORMAT
 // ----------------------------------
 // WinBMPv1.
 // - This version is no longer used and can be ignored.
 //
 // WinBMPv2.
 // - First is a 14 byte file header that includes: the magic number ("BM"),
-//   file size, and offset to the pixel data (|dataoffset|).
+//   file size, and offset to the pixel data (|mDataOffset|).
 // - Next is a 12 byte info header which includes: the info header size
-//   (bihsize), width, height, number of color planes, and bits-per-pixel
-//   (|bpp|) which must be 1, 4, 8 or 24.
-// - Next is the semi-optional color table, which has length 2^|bpp| and has 3
-//   bytes per value (BGR). The color table is required if |bpp| is 1, 4, or 8.
+//   (mBIHSize), width, height, number of color planes, and bits-per-pixel
+//   (|mBpp|) which must be 1, 4, 8 or 24.
+// - Next is the semi-optional color table, which has length 2^|mBpp| and has 3
+//   bytes per value (BGR). The color table is required if |mBpp| is 1, 4, or 8.
 // - Next is an optional gap.
-// - Next is the pixel data, which is pointed to by |dataoffset|.
+// - Next is the pixel data, which is pointed to by |mDataOffset|.
 //
 // WinBMPv3. This is the most widely used version.
 // - It changed the info header to 40 bytes by taking the WinBMPv2 info
 //   header, enlargening its width and height fields, and adding more fields
-//   including: a compression type (|compression|) and number of colors
-//   (|colors|).
+//   including: a compression type (|mCompression|) and number of colors
+//   (|mNumColors|).
 // - The semi-optional color table is now 4 bytes per value (BGR0), and its
-//   length is |colors|, or 2^|bpp| if |colors| is zero.
-// - |compression| can be RGB (i.e. no compression), RLE4 (if bpp==4) or RLE8
-//   (if bpp==8) values.
+//   length is |mNumColors|, or 2^|mBpp| if |mNumColors| is zero.
+// - |mCompression| can be RGB (i.e. no compression), RLE4 (if |mBpp|==4) or
+//   RLE8 (if |mBpp|==8) values.
 //
 // WinBMPv3-NT. A variant of WinBMPv3.
 // - It did not change the info header layout from WinBMPv3.
-// - |bpp| can now be 16 or 32, in which case |compression| can be RGB or the
+// - |mBpp| can now be 16 or 32, in which case |mCompression| can be RGB or the
 //   new BITFIELDS value; in the latter case an additional 12 bytes of color
 //   bitfields follow the info header.
 //
 // WinBMPv4.
 // - It extended the info header to 108 bytes, including the 12 bytes of color
 //   mask data from WinBMPv3-NT, plus alpha mask data, and also color-space and
 //   gamma correction fields.
 //
@@ -132,30 +132,31 @@ using namespace bmp;
 static void
 SetPixel(uint32_t*& aDecoded, uint8_t aRed, uint8_t aGreen,
          uint8_t aBlue, uint8_t aAlpha = 0xFF)
 {
   *aDecoded++ = gfxPackedPixel(aAlpha, aRed, aGreen, aBlue);
 }
 
 static void
-SetPixel(uint32_t*& aDecoded, uint8_t idx, bmp::ColorTableEntry* aColors)
+SetPixel(uint32_t*& aDecoded, uint8_t idx,
+         const UniquePtr<ColorTableEntry[]>& aColors)
 {
   SetPixel(aDecoded,
            aColors[idx].mRed, aColors[idx].mGreen, aColors[idx].mBlue);
 }
 
 /// Sets two (or one if aCount = 1) pixels
 /// @param aDecoded where the data is stored. Will be moved 4 resp 8 bytes
 /// depending on whether one or two pixels are written.
 /// @param aData The values for the two pixels
 /// @param aCount Current count. Is decremented by one or two.
 static void
 Set4BitPixel(uint32_t*& aDecoded, uint8_t aData, uint32_t& aCount,
-             bmp::ColorTableEntry* aColors)
+             const UniquePtr<ColorTableEntry[]>& aColors)
 {
   uint8_t idx = aData >> 4;
   SetPixel(aDecoded, idx, aColors);
   if (--aCount > 0) {
     idx = aData & 0xF;
     SetPixel(aDecoded, idx, aColors);
     --aCount;
   }
@@ -166,93 +167,86 @@ GetBMPLog()
 {
   static PRLogModuleInfo* sBMPLog;
   if (!sBMPLog) {
     sBMPLog = PR_NewLogModule("BMPDecoder");
   }
   return sBMPLog;
 }
 
-nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
+// The length of the mBIHSize field in the info header.
+static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
+
+nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength)
   : Decoder(aImage)
-  , mLexer(Transition::To(State::FILE_HEADER, FileHeader::LENGTH))
+  , mLexer(Transition::To(aState, aLength))
   , mIsWithinICO(false)
   , mMayHaveTransparency(false)
   , mDoesHaveTransparency(false)
   , mNumColors(0)
   , mColors(nullptr)
   , mBytesPerColor(0)
   , mPreGapLength(0)
   , mCurrentRow(0)
   , mCurrentPos(0)
   , mAbsoluteModeNumPixels(0)
 {
-  memset(&mBFH, 0, sizeof(mBFH));
-  memset(&mBIH, 0, sizeof(mBIH));
+}
+
+// Constructor for normal BMP files.
+nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
+  : nsBMPDecoder(aImage, State::FILE_HEADER, FILE_HEADER_LENGTH)
+{
+}
+
+// Constructor used for WinBMPv3-ICO files, which lack a file header.
+nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset)
+  : nsBMPDecoder(aImage, State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH)
+{
+  SetIsWithinICO();
+
+  // Even though the file header isn't present in this case, the dataOffset
+  // field is set as if it is, and so we must increment mPreGapLength
+  // accordingly.
+  mPreGapLength += FILE_HEADER_LENGTH;
+
+  // This is the one piece of data we normally get from a BMP file header, so
+  // it must be provided via an argument.
+  mH.mDataOffset = aDataOffset;
 }
 
 nsBMPDecoder::~nsBMPDecoder()
 {
-  delete[] mColors;
-}
-
-// Obtains the bits per pixel from the internal BIH header.
-int32_t
-nsBMPDecoder::GetBitsPerPixel() const
-{
-  return mBIH.bpp;
-}
-
-// Obtains the width from the internal BIH header.
-int32_t
-nsBMPDecoder::GetWidth() const
-{
-  return mBIH.width;
-}
-
-// Obtains the absolute value of the height from the internal BIH header.
-// If it's positive the bitmap is stored bottom to top, otherwise top to bottom.
-int32_t
-nsBMPDecoder::GetHeight() const
-{
-  return abs(mBIH.height);
-}
-
-// Obtains the internal output image buffer.
-uint32_t*
-nsBMPDecoder::GetImageData()
-{
-  return reinterpret_cast<uint32_t*>(mImageData);
 }
 
 // Obtains the size of the compressed image resource.
 int32_t
 nsBMPDecoder::GetCompressedImageSize() const
 {
-  // In the RGB case image_size might not be set, so compute it manually.
+  // In the RGB case mImageSize might not be set, so compute it manually.
   MOZ_ASSERT(mPixelRowSize != 0);
-  return mBIH.compression == Compression::RGB
-       ? mPixelRowSize * GetHeight()
-       : mBIH.image_size;
+  return mH.mCompression == Compression::RGB
+       ? mPixelRowSize * AbsoluteHeight()
+       : mH.mImageSize;
 }
 
 void
 nsBMPDecoder::FinishInternal()
 {
   // We shouldn't be called in error cases.
   MOZ_ASSERT(!HasError(), "Can't call FinishInternal on error!");
 
   // We should never make multiple frames.
   MOZ_ASSERT(GetFrameCount() <= 1, "Multiple BMP frames?");
 
   // Send notifications if appropriate.
   if (!IsMetadataDecode() && HasSize()) {
 
     // Invalidate.
-    nsIntRect r(0, 0, mBIH.width, GetHeight());
+    nsIntRect r(0, 0, mH.mWidth, AbsoluteHeight());
     PostInvalidation(r);
 
     if (mDoesHaveTransparency) {
       MOZ_ASSERT(mMayHaveTransparency);
       PostFrameStop(Opacity::SOME_TRANSPARENCY);
     } else {
       PostFrameStop(Opacity::OPAQUE);
     }
@@ -395,37 +389,37 @@ BitFields::IsR8G8B8() const
 
 uint32_t*
 nsBMPDecoder::RowBuffer()
 {
   if (mDownscaler) {
     return reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer()) + mCurrentPos;
   }
 
-  // Convert from row (1..height) to absolute line (0..height-1).
-  int32_t line = (mBIH.height < 0)
-               ? -mBIH.height - mCurrentRow
+  // Convert from row (1..mHeight) to absolute line (0..mHeight-1).
+  int32_t line = (mH.mHeight < 0)
+               ? -mH.mHeight - mCurrentRow
                : mCurrentRow - 1;
-  int32_t offset = line * mBIH.width + mCurrentPos;
+  int32_t offset = line * mH.mWidth + mCurrentPos;
   return reinterpret_cast<uint32_t*>(mImageData) + offset;
 }
 
 void
 nsBMPDecoder::FinishRow()
 {
   if (mDownscaler) {
     mDownscaler->CommitRow();
 
     if (mDownscaler->HasInvalidation()) {
       DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
       PostInvalidation(invalidRect.mOriginalSizeRect,
                        Some(invalidRect.mTargetSizeRect));
     }
   } else {
-    PostInvalidation(IntRect(0, mCurrentRow, mBIH.width, 1));
+    PostInvalidation(IntRect(0, mCurrentRow, mH.mWidth, 1));
   }
   mCurrentRow--;
 }
 
 void
 nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
@@ -461,165 +455,153 @@ nsBMPDecoder::WriteInternal(const char* 
     return;
   }
 
   MOZ_ASSERT(*terminalState == State::SUCCESS);
 
   return;
 }
 
-// The length of the bihsize field in the info header.
-static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
-
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength)
 {
   mPreGapLength += aLength;
 
-  mBFH.signature[0] = aData[0];
-  mBFH.signature[1] = aData[1];
-  bool signatureOk = mBFH.signature[0] == 'B' && mBFH.signature[1] == 'M';
+  bool signatureOk = aData[0] == 'B' && aData[1] == 'M';
   if (!signatureOk) {
     PostDataError();
     return Transition::Terminate(State::FAILURE);
   }
 
-  // Nb: this field is unreliable. In Windows BMPs it's the file size, but in
-  // OS/2 BMPs it's sometimes the size of the file and info headers. It doesn't
-  // matter because we don't consult it.
-  mBFH.filesize = LittleEndian::readUint32(aData + 2);
+  // We ignore the filesize (aData + 2) and reserved (aData + 6) fields.
 
-  mBFH.reserved = 0;
-
-  mBFH.dataoffset = LittleEndian::readUint32(aData + 10);
+  mH.mDataOffset = LittleEndian::readUint32(aData + 10);
 
   return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
 }
 
-// We read the info header in two steps: (a) read the bihsize field to
+// We read the info header in two steps: (a) read the mBIHSize field to
 // determine how long the header is; (b) read the rest of the header.
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::ReadInfoHeaderSize(const char* aData, size_t aLength)
 {
   mPreGapLength += aLength;
 
-  mBIH.bihsize = LittleEndian::readUint32(aData);
+  mH.mBIHSize = LittleEndian::readUint32(aData);
 
-  bool bihsizeOk = mBIH.bihsize == InfoHeaderLength::WIN_V2 ||
-                   mBIH.bihsize == InfoHeaderLength::WIN_V3 ||
-                   mBIH.bihsize == InfoHeaderLength::WIN_V4 ||
-                   mBIH.bihsize == InfoHeaderLength::WIN_V5 ||
-                   (mBIH.bihsize >= InfoHeaderLength::OS2_V2_MIN &&
-                    mBIH.bihsize <= InfoHeaderLength::OS2_V2_MAX);
-  if (!bihsizeOk) {
+  bool bihSizeOk = mH.mBIHSize == InfoHeaderLength::WIN_V2 ||
+                   mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
+                   mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
+                   mH.mBIHSize == InfoHeaderLength::WIN_V5 ||
+                   (mH.mBIHSize >= InfoHeaderLength::OS2_V2_MIN &&
+                    mH.mBIHSize <= InfoHeaderLength::OS2_V2_MAX);
+  if (!bihSizeOk) {
     PostDataError();
     return Transition::Terminate(State::FAILURE);
   }
   // ICO BMPs must have a WinVMPv3 header. nsICODecoder should have already
   // terminated decoding if this isn't the case.
-  MOZ_ASSERT_IF(mIsWithinICO, mBIH.bihsize == InfoHeaderLength::WIN_V3);
+  MOZ_ASSERT_IF(mIsWithinICO, mH.mBIHSize == InfoHeaderLength::WIN_V3);
 
   return Transition::To(State::INFO_HEADER_REST,
-                        mBIH.bihsize - BIHSIZE_FIELD_LENGTH);
+                        mH.mBIHSize - BIHSIZE_FIELD_LENGTH);
 }
 
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
 {
   mPreGapLength += aLength;
 
-  // |width| and |height| may be signed (Windows) or unsigned (OS/2). We just
+  // |mWidth| and |mHeight| may be signed (Windows) or unsigned (OS/2). We just
   // read as unsigned because in practice that's good enough.
-  if (mBIH.bihsize == InfoHeaderLength::WIN_V2) {
-    mBIH.width       = LittleEndian::readUint16(aData + 0);
-    mBIH.height      = LittleEndian::readUint16(aData + 2);
-    mBIH.planes      = LittleEndian::readUint16(aData + 4);
-    mBIH.bpp         = LittleEndian::readUint16(aData + 6);
+  if (mH.mBIHSize == InfoHeaderLength::WIN_V2) {
+    mH.mWidth  = LittleEndian::readUint16(aData + 0);
+    mH.mHeight = LittleEndian::readUint16(aData + 2);
+    // We ignore the planes (aData + 4) field; it should always be 1.
+    mH.mBpp    = LittleEndian::readUint16(aData + 6);
   } else {
-    mBIH.width       = LittleEndian::readUint32(aData + 0);
-    mBIH.height      = LittleEndian::readUint32(aData + 4);
-    mBIH.planes      = LittleEndian::readUint16(aData + 8);
-    mBIH.bpp         = LittleEndian::readUint16(aData + 10);
+    mH.mWidth  = LittleEndian::readUint32(aData + 0);
+    mH.mHeight = LittleEndian::readUint32(aData + 4);
+    // We ignore the planes (aData + 4) field; it should always be 1.
+    mH.mBpp    = LittleEndian::readUint16(aData + 10);
 
     // For OS2-BMPv2 the info header may be as little as 16 bytes, so be
     // careful for these fields.
-    mBIH.compression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
-    mBIH.image_size  = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
-    mBIH.xppm        = aLength >= 24 ? LittleEndian::readUint32(aData + 20) : 0;
-    mBIH.yppm        = aLength >= 28 ? LittleEndian::readUint32(aData + 24) : 0;
-    mBIH.colors      = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
-    mBIH.important_colors
-                     = aLength >= 36 ? LittleEndian::readUint32(aData + 32) : 0;
+    mH.mCompression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
+    mH.mImageSize   = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
+    // We ignore the xppm (aData + 20) and yppm (aData + 24) fields.
+    mH.mNumColors   = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
+    // We ignore the important_colors (aData + 36) field.
 
     // For WinBMPv4, WinBMPv5 and (possibly) OS2-BMPv2 there are additional
     // fields in the info header which we ignore, with the possible exception
     // of the color bitfields (see below).
   }
 
   // Run with NSPR_LOG_MODULES=BMPDecoder:4 set to see this output.
   MOZ_LOG(GetBMPLog(), LogLevel::Debug,
           ("BMP: bihsize=%u, %d x %d, bpp=%u, compression=%u, colors=%u\n",
-          mBIH.bihsize, mBIH.width, mBIH.height, uint32_t(mBIH.bpp),
-          mBIH.compression, mBIH.colors));
+          mH.mBIHSize, mH.mWidth, mH.mHeight, uint32_t(mH.mBpp),
+          mH.mCompression, mH.mNumColors));
 
   // BMPs with negative width are invalid. Also, reject extremely wide images
   // to keep the math sane. And reject INT_MIN as a height because you can't
   // get its absolute value (because -INT_MIN is one more than INT_MAX).
   const int32_t k64KWidth = 0x0000FFFF;
-  bool sizeOk = 0 <= mBIH.width && mBIH.width <= k64KWidth &&
-                mBIH.height != INT_MIN;
+  bool sizeOk = 0 <= mH.mWidth && mH.mWidth <= k64KWidth &&
+                mH.mHeight != INT_MIN;
   if (!sizeOk) {
     PostDataError();
     return Transition::Terminate(State::FAILURE);
   }
 
-  // Check bpp and compression.
+  // Check mBpp and mCompression.
   bool bppCompressionOk =
-    (mBIH.compression == Compression::RGB &&
-      (mBIH.bpp ==  1 || mBIH.bpp ==  4 || mBIH.bpp ==  8 ||
-       mBIH.bpp == 16 || mBIH.bpp == 24 || mBIH.bpp == 32)) ||
-    (mBIH.compression == Compression::RLE8 && mBIH.bpp == 8) ||
-    (mBIH.compression == Compression::RLE4 && mBIH.bpp == 4) ||
-    (mBIH.compression == Compression::BITFIELDS &&
-      (mBIH.bpp == 16 || mBIH.bpp == 32));
+    (mH.mCompression == Compression::RGB &&
+      (mH.mBpp ==  1 || mH.mBpp ==  4 || mH.mBpp ==  8 ||
+       mH.mBpp == 16 || mH.mBpp == 24 || mH.mBpp == 32)) ||
+    (mH.mCompression == Compression::RLE8 && mH.mBpp == 8) ||
+    (mH.mCompression == Compression::RLE4 && mH.mBpp == 4) ||
+    (mH.mCompression == Compression::BITFIELDS &&
+      (mH.mBpp == 16 || mH.mBpp == 32));
   if (!bppCompressionOk) {
     PostDataError();
     return Transition::Terminate(State::FAILURE);
   }
 
   // Post our size to the superclass.
-  uint32_t realHeight = GetHeight();
-  PostSize(mBIH.width, realHeight);
-  mCurrentRow = realHeight;
+  uint32_t absHeight = AbsoluteHeight();
+  PostSize(mH.mWidth, absHeight);
+  mCurrentRow = absHeight;
 
   // Round it up to the nearest byte count, then pad to 4-byte boundary.
   // Compute this even for a metadate decode because GetCompressedImageSize()
   // relies on it.
-  mPixelRowSize = (mBIH.bpp * mBIH.width + 7) / 8;
+  mPixelRowSize = (mH.mBpp * mH.mWidth + 7) / 8;
   uint32_t surplus = mPixelRowSize % 4;
   if (surplus != 0) {
     mPixelRowSize += 4 - surplus;
   }
 
   size_t bitFieldsLengthStillToRead = 0;
-  if (mBIH.compression == Compression::BITFIELDS) {
+  if (mH.mCompression == Compression::BITFIELDS) {
     // Need to read bitfields.
-    if (mBIH.bihsize >= InfoHeaderLength::WIN_V4) {
+    if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) {
       // Bitfields are present in the info header, so we can read them
       // immediately.
       mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
     } else {
       // Bitfields are present after the info header, so we will read them in
       // ReadBitfields().
       bitFieldsLengthStillToRead = BitFields::LENGTH;
     }
-  } else if (mBIH.bpp == 16) {
+  } else if (mH.mBpp == 16) {
     // No bitfields specified; use the default 5-5-5 values.
     mBitFields.SetR5G5B5();
-  } else if (mBIH.bpp == 32) {
+  } else if (mH.mBpp == 32) {
     // No bitfields specified; use the default 8-8-8 values.
     mBitFields.SetR8G8B8();
   }
 
   return Transition::To(State::BITFIELDS, bitFieldsLengthStillToRead);
 }
 
 void
@@ -642,45 +624,45 @@ nsBMPDecoder::ReadBitfields(const char* 
   // in ReadInfoHeader().
   if (aLength != 0) {
     mBitFields.ReadFromHeader(aData, /* aReadAlpha = */ false);
   }
 
   // Note that RLE-encoded BMPs might be transparent because the 'delta' mode
   // can skip pixels and cause implicit transparency.
   mMayHaveTransparency =
-    (mBIH.compression == Compression::RGB && mIsWithinICO && mBIH.bpp == 32) ||
-    mBIH.compression == Compression::RLE8 ||
-    mBIH.compression == Compression::RLE4 ||
-    (mBIH.compression == Compression::BITFIELDS &&
+    (mH.mCompression == Compression::RGB && mIsWithinICO && mH.mBpp == 32) ||
+    mH.mCompression == Compression::RLE8 ||
+    mH.mCompression == Compression::RLE4 ||
+    (mH.mCompression == Compression::BITFIELDS &&
      mBitFields.mAlpha.IsPresent());
   if (mMayHaveTransparency) {
     PostHasTransparency();
   }
 
   // We've now read all the headers. If we're doing a metadata decode, we're
   // done.
   if (IsMetadataDecode()) {
     return Transition::Terminate(State::SUCCESS);
   }
 
   // Set up the color table, if present; it'll be filled in by ReadColorTable().
-  if (mBIH.bpp <= 8) {
-    mNumColors = 1 << mBIH.bpp;
-    if (0 < mBIH.colors && mBIH.colors < mNumColors) {
-      mNumColors = mBIH.colors;
+  if (mH.mBpp <= 8) {
+    mNumColors = 1 << mH.mBpp;
+    if (0 < mH.mNumColors && mH.mNumColors < mNumColors) {
+      mNumColors = mH.mNumColors;
     }
 
     // Always allocate and zero 256 entries, even though mNumColors might be
     // smaller, because the file might erroneously index past mNumColors.
-    mColors = new ColorTableEntry[256];
-    memset(mColors, 0, 256 * sizeof(ColorTableEntry));
+    mColors = MakeUnique<ColorTableEntry[]>(256);
+    memset(mColors.get(), 0, 256 * sizeof(ColorTableEntry));
 
     // OS/2 Bitmaps have no padding byte.
-    mBytesPerColor = (mBIH.bihsize == InfoHeaderLength::WIN_V2) ? 3 : 4;
+    mBytesPerColor = (mH.mBIHSize == InfoHeaderLength::WIN_V2) ? 3 : 4;
   }
 
   MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
   IntSize targetSize = mDownscaler ? mDownscaler->TargetSize() : GetSize();
   nsresult rv = AllocateFrame(/* aFrameNum = */ 0, targetSize,
                               IntRect(IntPoint(), targetSize),
                               SurfaceFormat::B8G8R8A8);
   if (NS_FAILED(rv)) {
@@ -713,49 +695,49 @@ nsBMPDecoder::ReadColorTable(const char*
     // The format is BGR or BGR0.
     mColors[i].mBlue  = uint8_t(aData[0]);
     mColors[i].mGreen = uint8_t(aData[1]);
     mColors[i].mRed   = uint8_t(aData[2]);
     aData += mBytesPerColor;
   }
 
   // We know how many bytes we've read so far (mPreGapLength) and we know the
-  // offset of the pixel data (mBFH.dataoffset), so we can determine the length
+  // offset of the pixel data (mH.mDataOffset), so we can determine the length
   // of the gap (possibly zero) between the color table and the pixel data.
   //
-  // If the gap is negative the file must be malformed (e.g. mBFH.dataoffset
+  // If the gap is negative the file must be malformed (e.g. mH.mDataOffset
   // points into the middle of the color palette instead of past the end) and
   // we give up.
-  if (mPreGapLength > mBFH.dataoffset) {
+  if (mPreGapLength > mH.mDataOffset) {
     PostDataError();
     return Transition::Terminate(State::FAILURE);
   }
-  uint32_t gapLength = mBFH.dataoffset - mPreGapLength;
+  uint32_t gapLength = mH.mDataOffset - mPreGapLength;
   return Transition::To(State::GAP, gapLength);
 }
 
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::SkipGap()
 {
-  bool hasRLE = mBIH.compression == Compression::RLE8 ||
-                mBIH.compression == Compression::RLE4;
+  bool hasRLE = mH.mCompression == Compression::RLE8 ||
+                mH.mCompression == Compression::RLE4;
   return hasRLE
        ? Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH)
        : Transition::To(State::PIXEL_ROW, mPixelRowSize);
 }
 
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::ReadPixelRow(const char* aData)
 {
   MOZ_ASSERT(mCurrentPos == 0);
 
   const uint8_t* src = reinterpret_cast<const uint8_t*>(aData);
   uint32_t* dst = RowBuffer();
-  uint32_t lpos = mBIH.width;
-  switch (mBIH.bpp) {
+  uint32_t lpos = mH.mWidth;
+  switch (mH.mBpp) {
     case 1:
       while (lpos > 0) {
         int8_t bit;
         uint8_t idx;
         for (bit = 7; bit >= 0 && lpos > 0; bit--) {
           idx = (*src >> bit) & 1;
           SetPixel(dst, idx, mColors);
           --lpos;
@@ -812,18 +794,18 @@ nsBMPDecoder::ReadPixelRow(const char* a
       while (lpos > 0) {
         SetPixel(dst, src[2], src[1], src[0]);
         --lpos;
         src += 3;
       }
       break;
 
     case 32:
-      if (mBIH.compression == Compression::RGB && mIsWithinICO &&
-          mBIH.bpp == 32) {
+      if (mH.mCompression == Compression::RGB && mIsWithinICO &&
+          mH.mBpp == 32) {
         // This is a special case only used for 32bpp WinBMPv3-ICO files, which
         // could be in either 0RGB or ARGB format.
         while (lpos > 0) {
           // If src[3] is zero, we can't tell at this point if the image is
           // 0RGB or ARGB. So we just use 0 value as-is. If the image is 0RGB
           // then mDoesHaveTransparency will be false at the end, we'll treat
           // the image as opaque, and the 0 alpha values will be ignored. If
           // the image is ARGB then mDoesHaveTransparency will be true at the
@@ -889,21 +871,21 @@ nsBMPDecoder::ReadRLESegment(const char*
 
   if (byte1 != RLE::ESCAPE) {
     // Encoded mode consists of two bytes: byte1 specifies the number of
     // consecutive pixels to be drawn using the color index contained in
     // byte2.
     //
     // Work around bitmaps that specify too many pixels.
     uint32_t pixelsNeeded =
-      std::min<uint32_t>(mBIH.width - mCurrentPos, byte1);
+      std::min<uint32_t>(mH.mWidth - mCurrentPos, byte1);
     if (pixelsNeeded) {
       uint32_t* dst = RowBuffer();
       mCurrentPos += pixelsNeeded;
-      if (mBIH.compression == Compression::RLE8) {
+      if (mH.mCompression == Compression::RLE8) {
         do {
           SetPixel(dst, byte2, mColors);
           pixelsNeeded --;
         } while (pixelsNeeded);
       } else {
         do {
           Set4BitPixel(dst, byte2, pixelsNeeded, mColors);
         } while (pixelsNeeded);
@@ -929,17 +911,17 @@ nsBMPDecoder::ReadRLESegment(const char*
   }
 
   // Absolute mode. |byte2| gives the number of pixels. The length depends on
   // whether it's 4-bit or 8-bit RLE. Also, the length must be even (and zero
   // padding is used to achieve this when necessary).
   MOZ_ASSERT(mAbsoluteModeNumPixels == 0);
   mAbsoluteModeNumPixels = byte2;
   uint32_t length = byte2;
-  if (mBIH.compression == Compression::RLE4) {
+  if (mH.mCompression == Compression::RLE4) {
     length = (length + 1) / 2;    // halve, rounding up
   }
   if (length & 1) {
     length++;
   }
   return Transition::To(State::RLE_ABSOLUTE, length);
 }
 
@@ -954,18 +936,18 @@ nsBMPDecoder::ReadRLEDelta(const char* a
   if (mDownscaler) {
     // Clear the skipped pixels. (This clears to the end of the row,
     // which is perfect if there's a Y delta and harmless if not).
     mDownscaler->ClearRow(/* aStartingAtCol = */ mCurrentPos);
   }
 
   // Handle the XDelta.
   mCurrentPos += uint8_t(aData[0]);
-  if (mCurrentPos > mBIH.width) {
-    mCurrentPos = mBIH.width;
+  if (mCurrentPos > mH.mWidth) {
+    mCurrentPos = mH.mWidth;
   }
 
   // Handle the Y Delta.
   int32_t yDelta = std::min<int32_t>(uint8_t(aData[1]), mCurrentRow);
   mCurrentRow -= yDelta;
 
   if (mDownscaler && yDelta > 0) {
     // Commit the current row (the first of the skipped rows).
@@ -984,28 +966,28 @@ nsBMPDecoder::ReadRLEDelta(const char* a
 }
 
 LexerTransition<nsBMPDecoder::State>
 nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength)
 {
   uint32_t n = mAbsoluteModeNumPixels;
   mAbsoluteModeNumPixels = 0;
 
-  if (mCurrentPos + n > uint32_t(mBIH.width)) {
+  if (mCurrentPos + n > uint32_t(mH.mWidth)) {
     // Bad data. Stop decoding; at least part of the image may have been
     // decoded.
     return Transition::Terminate(State::SUCCESS);
   }
 
   // In absolute mode, n represents the number of pixels that follow, each of
   // which contains the color index of a single pixel.
   uint32_t* dst = RowBuffer();
   uint32_t iSrc = 0;
   uint32_t* oldPos = dst;
-  if (mBIH.compression == Compression::RLE8) {
+  if (mH.mCompression == Compression::RLE8) {
     while (n > 0) {
       SetPixel(dst, aData[iSrc], mColors);
       n--;
       iSrc++;
     }
   } else {
     while (n > 0) {
       Set4BitPixel(dst, aData[iSrc], n, mColors);
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -2,26 +2,53 @@
 /* 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_image_decoders_nsBMPDecoder_h
 #define mozilla_image_decoders_nsBMPDecoder_h
 
-#include "BMPFileHeaders.h"
+#include "BMPHeaders.h"
 #include "Decoder.h"
 #include "gfxColor.h"
 #include "StreamingLexer.h"
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace image {
 
 namespace bmp {
 
+/// This struct contains the fields from the file header and info header that
+/// we use during decoding. (Excluding bitfields fields, which are kept in
+/// BitFields.)
+struct Header {
+  uint32_t mDataOffset;     // Offset to raster data.
+  uint32_t mBIHSize;        // Header size.
+  int32_t  mWidth;          // Image width.
+  int32_t  mHeight;         // Image height.
+  uint16_t mBpp;            // Bits per pixel.
+  uint32_t mCompression;    // See struct Compression for valid values.
+  uint32_t mImageSize;      // (compressed) image size. Can be 0 if
+                            // mCompression==0.
+  uint32_t mNumColors;      // Used colors.
+
+  Header()
+   : mDataOffset(0)
+   , mBIHSize(0)
+   , mWidth(0)
+   , mHeight(0)
+   , mBpp(0)
+   , mCompression(0)
+   , mImageSize(0)
+   , mNumColors(0)
+  {}
+};
+
 /// An entry in the color table.
 struct ColorTableEntry {
   uint8_t mRed;
   uint8_t mGreen;
   uint8_t mBlue;
 };
 
 /// All the color-related bitfields for 16bpp and 32bpp images. We use this
@@ -93,33 +120,27 @@ class RasterImage;
 
 /// Decoder for BMP-Files, as used by Windows and OS/2.
 
 class nsBMPDecoder : public Decoder
 {
 public:
   ~nsBMPDecoder();
 
-  /// Obtains the bits per pixel from the internal BIH header.
-  int32_t GetBitsPerPixel() const;
-
-  /// Obtains the width from the internal BIH header.
-  int32_t GetWidth() const;
+  /// Obtains the internal output image buffer.
+  uint32_t* GetImageData() { return reinterpret_cast<uint32_t*>(mImageData); }
 
-  /// Obtains the abs-value of the height from the internal BIH header.
-  int32_t GetHeight() const;
-
-  /// Obtains the internal output image buffer.
-  uint32_t* GetImageData();
+  /// Obtains the length of the internal output image buffer.
   size_t GetImageDataLength() const { return mImageDataLength; }
 
   /// Obtains the size of the compressed image resource.
   int32_t GetCompressedImageSize() const;
 
-  /// Mark this BMP as being within an ICO file.
+  /// Mark this BMP as being within an ICO file. Only used for testing purposes
+  /// because the ICO-specific constructor does this marking automatically.
   void SetIsWithinICO() { mIsWithinICO = true; }
 
   /// Did the BMP file have alpha data of any kind? (Only use this after the
   /// bitmap has been fully decoded.)
   bool HasTransparency() const { return mDoesHaveTransparency; }
 
   /// Force transparency from outside. (Used by the ICO decoder.)
   void SetHasTransparency()
@@ -131,71 +152,79 @@ public:
   virtual void WriteInternal(const char* aBuffer,
                              uint32_t aCount) override;
   virtual void FinishInternal() override;
 
 private:
   friend class DecoderFactory;
   friend class nsICODecoder;
 
-  // Decoders should only be instantiated via DecoderFactory.
-  // XXX(seth): nsICODecoder is temporarily an exception to this rule.
-  explicit nsBMPDecoder(RasterImage* aImage);
-
-  uint32_t* RowBuffer();
-
-  void FinishRow();
-
   enum class State {
     FILE_HEADER,
     INFO_HEADER_SIZE,
     INFO_HEADER_REST,
     BITFIELDS,
     COLOR_TABLE,
     GAP,
     PIXEL_ROW,
     RLE_SEGMENT,
     RLE_DELTA,
     RLE_ABSOLUTE,
     SUCCESS,
     FAILURE
   };
 
+  // This is the constructor used by DecoderFactory.
+  explicit nsBMPDecoder(RasterImage* aImage);
+
+  // This is the constructor used by nsICODecoder.
+  // XXX(seth): nsICODecoder is temporarily an exception to the rule that
+  //            decoders should only be instantiated via DecoderFactory.
+  nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);
+
+  // Helper constructor called by the other two.
+  nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength);
+
+  int32_t AbsoluteHeight() const { return abs(mH.mHeight); }
+
+  uint32_t* RowBuffer();
+
+  void FinishRow();
+
   LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
   LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
   LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
   LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
   LexerTransition<State> ReadColorTable(const char* aData, size_t aLength);
   LexerTransition<State> SkipGap();
   LexerTransition<State> ReadPixelRow(const char* aData);
   LexerTransition<State> ReadRLESegment(const char* aData);
   LexerTransition<State> ReadRLEDelta(const char* aData);
   LexerTransition<State> ReadRLEAbsolute(const char* aData, size_t aLength);
 
   StreamingLexer<State> mLexer;
 
-  bmp::FileHeader mBFH;
-  bmp::V5InfoHeader mBIH;
+  bmp::Header mH;
 
   // If the BMP is within an ICO file our treatment of it differs slightly.
   bool mIsWithinICO;
 
   bmp::BitFields mBitFields;
 
   // Might the image have transparency? Determined from the headers during
   // metadata decode. (Does not guarantee the image actually has transparency.)
   bool mMayHaveTransparency;
 
   // Does the image have transparency? Determined during full decoding, so only
   // use this after that has been completed.
   bool mDoesHaveTransparency;
 
   uint32_t mNumColors;      // The number of used colors, i.e. the number of
                             // entries in mColors, if it's present.
-  bmp::ColorTableEntry* mColors; // The color table, if it's present.
+  UniquePtr<bmp::ColorTableEntry[]> mColors; // The color table, if it's present.
   uint32_t mBytesPerColor;  // 3 or 4, depending on the format
 
   // The number of bytes prior to the optional gap that have been read. This
   // is used to find the start of the pixel data.
   uint32_t mPreGapLength;
 
   uint32_t mPixelRowSize;   // The number of bytes per pixel row.
 
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -16,17 +16,17 @@
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace image {
 
 // Constants.
 static const uint32_t ICOHEADERSIZE = 6;
-static const uint32_t BITMAPINFOSIZE = 40;
+static const uint32_t BITMAPINFOSIZE = bmp::InfoHeaderLength::WIN_ICO;
 
 // ----------------------------------------
 // Actual Data Processing
 // ----------------------------------------
 
 uint32_t
 nsICODecoder::CalcAlphaRowSize()
 {
@@ -105,63 +105,26 @@ nsICODecoder::GetFinalStateFromContained
   mDecodeAborted = mContainedDecoder->WasAborted();
   mProgress |= mContainedDecoder->TakeProgress();
   mInvalidRect.UnionRect(mInvalidRect, mContainedDecoder->TakeInvalidRect());
   mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
 
   MOZ_ASSERT(HasError() || !mCurrentFrame || mCurrentFrame->IsImageComplete());
 }
 
-// Returns a buffer filled with the bitmap file header in little endian:
-// Signature 2 bytes 'BM'
-// FileSize      4 bytes File size in bytes
-// reserved      4 bytes unused (=0)
-// DataOffset    4 bytes File offset to Raster Data
-// Returns true if successful
-bool
-nsICODecoder::FillBitmapFileHeaderBuffer(int8_t* bfh)
-{
-  memset(bfh, 0, 14);
-  bfh[0] = 'B';
-  bfh[1] = 'M';
-  int32_t dataOffset = 0;
-  int32_t fileSize = 0;
-  dataOffset = bmp::FileHeader::LENGTH + BITMAPINFOSIZE;
-
-  // The color table is present only if BPP is <= 8
-  if (mDirEntry.mBitCount <= 8) {
-    uint16_t numColors = GetNumColors();
-    if (numColors == (uint16_t)-1) {
-      return false;
-    }
-    dataOffset += 4 * numColors;
-    fileSize = dataOffset + GetRealWidth() * GetRealHeight();
-  } else {
-    fileSize = dataOffset + (mDirEntry.mBitCount * GetRealWidth() *
-                             GetRealHeight()) / 8;
-  }
-
-  NativeEndian::swapToLittleEndianInPlace(&fileSize, 1);
-  memcpy(bfh + 2, &fileSize, sizeof(fileSize));
-  NativeEndian::swapToLittleEndianInPlace(&dataOffset, 1);
-  memcpy(bfh + 10, &dataOffset, sizeof(dataOffset));
-  return true;
-}
-
 // A BMP inside of an ICO has *2 height because of the AND mask
 // that follows the actual bitmap.  The BMP shouldn't know about
 // this difference though.
 bool
 nsICODecoder::FixBitmapHeight(int8_t* bih)
 {
-  // Get the height from the BMP file information header
-  int32_t height;
-  memcpy(&height, bih + 8, sizeof(height));
-  NativeEndian::swapFromLittleEndianInPlace(&height, 1);
-  // BMPs can be stored inverted by having a negative height
+  // Get the height from the BMP file information header.
+  int32_t height = LittleEndian::readInt32(bih + 8);
+
+  // BMPs can be stored inverted by having a negative height.
   height = abs(height);
 
   // The bitmap height is by definition * 2 what it should be to account for
   // the 'AND mask'. It is * 2 even if the `AND mask` is not present.
   height /= 2;
 
   if (height > 256) {
     return false;
@@ -171,78 +134,53 @@ nsICODecoder::FixBitmapHeight(int8_t* bi
   // the ICO height.  So fix the ICO height.
   if (height == 256) {
     mDirEntry.mHeight = 0;
   } else {
     mDirEntry.mHeight = (int8_t)height;
   }
 
   // Fix the BMP height in the BIH so that the BMP decoder can work properly
-  NativeEndian::swapToLittleEndianInPlace(&height, 1);
-  memcpy(bih + 8, &height, sizeof(height));
+  LittleEndian::writeInt32(bih + 8, height);
   return true;
 }
 
 // We should always trust the contained resource for the width
 // information over our own information.
 bool
 nsICODecoder::FixBitmapWidth(int8_t* bih)
 {
-  // Get the width from the BMP file information header
-  int32_t width;
-  memcpy(&width, bih + 4, sizeof(width));
-  NativeEndian::swapFromLittleEndianInPlace(&width, 1);
+  // Get the width from the BMP file information header.
+  int32_t width = LittleEndian::readInt32(bih + 4);
+
   if (width > 256) {
     return false;
   }
 
-  // We should always trust the width  from the bitmap itself instead of
+  // We should always trust the width from the bitmap itself instead of
   // the ICO width.
   if (width == 256) {
     mDirEntry.mWidth = 0;
   } else {
     mDirEntry.mWidth = (int8_t)width;
   }
   return true;
 }
 
-// The BMP information header's bits per pixel should be trusted
-// more than what we have.  Usually the ICO's BPP is set to 0.
-int32_t
-nsICODecoder::ReadBPP(const char* aBIH)
-{
-  const int8_t* bih = reinterpret_cast<const int8_t*>(aBIH);
-  int32_t bitsPerPixel;
-  memcpy(&bitsPerPixel, bih + 14, sizeof(bitsPerPixel));
-  NativeEndian::swapFromLittleEndianInPlace(&bitsPerPixel, 1);
-  return bitsPerPixel;
-}
-
-int32_t
-nsICODecoder::ReadBIHSize(const char* aBIH)
-{
-  const int8_t* bih = reinterpret_cast<const int8_t*>(aBIH);
-  int32_t headerSize;
-  memcpy(&headerSize, bih, sizeof(headerSize));
-  NativeEndian::swapFromLittleEndianInPlace(&headerSize, 1);
-  return headerSize;
-}
-
 LexerTransition<ICOState>
 nsICODecoder::ReadHeader(const char* aData)
 {
   // If the third byte is 1, this is an icon. If 2, a cursor.
   if ((aData[2] != 1) && (aData[2] != 2)) {
     return Transition::Terminate(ICOState::FAILURE);
   }
   mIsCursor = (aData[2] == 2);
 
   // The fifth and sixth bytes specify the number of resources in the file.
-  mNumIcons =
-    LittleEndian::readUint16(reinterpret_cast<const uint16_t*>(aData + 4));
+  mNumIcons = LittleEndian::readUint16(aData + 4);
   if (mNumIcons == 0) {
     return Transition::Terminate(ICOState::SUCCESS); // Nothing to do.
   }
 
   // Downscale-during-decode can end up decoding different resources in the ICO
   // file depending on the target size. Since the resources are not necessarily
   // scaled versions of the same image, some may be transparent and some may not
   // be. We could be precise about transparency if we decoded the metadata of
@@ -266,29 +204,24 @@ nsICODecoder::FirstResourceOffset() cons
 
 LexerTransition<ICOState>
 nsICODecoder::ReadDirEntry(const char* aData)
 {
   mCurrIcon++;
 
   // Read the directory entry.
   IconDirEntry e;
-  memset(&e, 0, sizeof(e));
-  memcpy(&e.mWidth, aData, sizeof(e.mWidth));
-  memcpy(&e.mHeight, aData + 1, sizeof(e.mHeight));
-  memcpy(&e.mColorCount, aData + 2, sizeof(e.mColorCount));
-  memcpy(&e.mReserved, aData + 3, sizeof(e.mReserved));
-  memcpy(&e.mPlanes, aData + 4, sizeof(e.mPlanes));
-  e.mPlanes = LittleEndian::readUint16(&e.mPlanes);
-  memcpy(&e.mBitCount, aData + 6, sizeof(e.mBitCount));
-  e.mBitCount = LittleEndian::readUint16(&e.mBitCount);
-  memcpy(&e.mBytesInRes, aData + 8, sizeof(e.mBytesInRes));
-  e.mBytesInRes = LittleEndian::readUint32(&e.mBytesInRes);
-  memcpy(&e.mImageOffset, aData + 12, sizeof(e.mImageOffset));
-  e.mImageOffset = LittleEndian::readUint32(&e.mImageOffset);
+  e.mWidth       = aData[0];
+  e.mHeight      = aData[1];
+  e.mColorCount  = aData[2];
+  e.mReserved    = aData[3];
+  e.mPlanes      = LittleEndian::readUint16(aData + 4);
+  e.mBitCount    = LittleEndian::readUint16(aData + 6);
+  e.mBytesInRes  = LittleEndian::readUint32(aData + 8);
+  e.mImageOffset = LittleEndian::readUint32(aData + 12);
 
   // Determine if this is the biggest resource we've seen so far. We always use
   // the biggest resource for the intrinsic size, and if we're not downscaling,
   // we select it as the best resource as well.
   IntSize entrySize(GetRealWidth(e), GetRealHeight(e));
   if (e.mBitCount >= mBiggestResourceColorDepth &&
       entrySize.width * entrySize.height >=
         mBiggestResourceSize.width * mBiggestResourceSize.height) {
@@ -384,31 +317,18 @@ nsICODecoder::SniffResource(const char* 
     }
 
     // Read in the rest of the PNG unbuffered.
     size_t toRead = mDirEntry.mBytesInRes - PNGSIGNATURESIZE;
     return Transition::ToUnbuffered(ICOState::FINISHED_RESOURCE,
                                     ICOState::READ_PNG,
                                     toRead);
   } else {
-    // Create a BMP decoder which will do most of the work for us; the exception
-    // is the AND mask, which isn't present in standalone BMPs.
-    nsBMPDecoder* bmpDecoder = new nsBMPDecoder(mImage);
-    mContainedDecoder = bmpDecoder;
-    bmpDecoder->SetIsWithinICO();
-    mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
-    mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
-    mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
-    if (mDownscaler) {
-      mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
-    }
-    mContainedDecoder->Init();
-
     // Make sure we have a sane size for the bitmap information header.
-    int32_t bihSize = ReadBIHSize(aData);
+    int32_t bihSize = LittleEndian::readUint32(aData);
     if (bihSize != static_cast<int32_t>(BITMAPINFOSIZE)) {
       return Transition::Terminate(ICOState::FAILURE);
     }
 
     // Buffer the first part of the bitmap information header.
     memcpy(mBIHraw, aData, PNGSIGNATURESIZE);
 
     // Read in the rest of the bitmap information header.
@@ -434,32 +354,45 @@ nsICODecoder::ReadPNG(const char* aData,
 }
 
 LexerTransition<ICOState>
 nsICODecoder::ReadBIH(const char* aData)
 {
   // Buffer the rest of the bitmap information header.
   memcpy(mBIHraw + PNGSIGNATURESIZE, aData, BITMAPINFOSIZE - PNGSIGNATURESIZE);
 
-  // Extracting the BPP from the BIH header; it should be trusted over the one
-  // we have from the ICO header.
-  mBPP = ReadBPP(mBIHraw);
+  // Extract the BPP from the BIH header; it should be trusted over the one
+  // we have from the ICO header which is usually set to 0.
+  mBPP = LittleEndian::readUint16(mBIHraw + 14);
 
   // The ICO format when containing a BMP does not include the 14 byte
-  // bitmap file header. To use the code of the BMP decoder we need to
-  // generate this header ourselves and feed it to the BMP decoder.
-  int8_t bfhBuffer[BMPFILEHEADERSIZE];
-  if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
-    return Transition::Terminate(ICOState::FAILURE);
+  // bitmap file header. So we create the BMP decoder via the constructor that
+  // tells it to skip this, and pass in the required data (dataOffset) that
+  // would have been present in the header.
+  uint32_t dataOffset = bmp::FILE_HEADER_LENGTH + BITMAPINFOSIZE;
+  if (mDirEntry.mBitCount <= 8) {
+    // The color table is present only if BPP is <= 8.
+    uint16_t numColors = GetNumColors();
+    if (numColors == (uint16_t)-1) {
+      return Transition::Terminate(ICOState::FAILURE);
+    }
+    dataOffset += 4 * numColors;
   }
 
-  if (!WriteToContainedDecoder(reinterpret_cast<const char*>(bfhBuffer),
-                               sizeof(bfhBuffer))) {
-    return Transition::Terminate(ICOState::FAILURE);
+  // Create a BMP decoder which will do most of the work for us; the exception
+  // is the AND mask, which isn't present in standalone BMPs.
+  RefPtr<nsBMPDecoder> bmpDecoder = new nsBMPDecoder(mImage, dataOffset);
+  mContainedDecoder = bmpDecoder;
+  mContainedDecoder->SetMetadataDecode(IsMetadataDecode());
+  mContainedDecoder->SetDecoderFlags(GetDecoderFlags());
+  mContainedDecoder->SetSurfaceFlags(GetSurfaceFlags());
+  if (mDownscaler) {
+    mContainedDecoder->SetTargetSize(mDownscaler->TargetSize());
   }
+  mContainedDecoder->Init();
 
   // Fix the ICO height from the BIH. It needs to be halved so our BMP decoder
   // will understand, because the BMP decoder doesn't expect the alpha mask that
   // follows the BMP data in an ICO.
   if (!FixBitmapHeight(reinterpret_cast<int8_t*>(mBIHraw))) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
@@ -468,24 +401,16 @@ nsICODecoder::ReadBIH(const char* aData)
     return Transition::Terminate(ICOState::FAILURE);
   }
 
   // Write out the BMP's bitmap info header.
   if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw))) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
-  // Sometimes the ICO BPP header field is not filled out so we should trust the
-  // contained resource over our own information.
-  // XXX(seth): Is this ever different than the value we obtained from
-  // ReadBPP() above?
-  RefPtr<nsBMPDecoder> bmpDecoder =
-    static_cast<nsBMPDecoder*>(mContainedDecoder.get());
-  mBPP = bmpDecoder->GetBitsPerPixel();
-
   // Check to make sure we have valid color settings.
   uint16_t numColors = GetNumColors();
   if (numColors == uint16_t(-1)) {
     return Transition::Terminate(ICOState::FAILURE);
   }
 
   // Do we have an AND mask on this BMP? If so, we need to read it after we read
   // the BMP data itself.
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -82,30 +82,24 @@ private:
 
   // Writes to the contained decoder and sets the appropriate errors
   // Returns true if there are no errors.
   bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount);
 
   // Gets decoder state from the contained decoder so it's visible externally.
   void GetFinalStateFromContainedDecoder();
 
-  // Creates a bitmap file header buffer, returns true if successful
-  bool FillBitmapFileHeaderBuffer(int8_t* bfh);
   // Fixes the ICO height to match that of the BIH.
   // and also fixes the BIH height to be /2 of what it was.
   // See definition for explanation.
   // Returns false if invalid information is contained within.
   bool FixBitmapHeight(int8_t* bih);
   // Fixes the ICO width to match that of the BIH.
   // Returns false if invalid information is contained within.
   bool FixBitmapWidth(int8_t* bih);
-  // Extract bitmap info header size count from BMP information header
-  int32_t ReadBIHSize(const char* aBIH);
-  // Extract bit count from BMP information header
-  int32_t ReadBPP(const char* aBIH);
   // Calculates the row size in bytes for the AND mask table
   uint32_t CalcAlphaRowSize();
   // Obtains the number of colors from the BPP, mBPP must be filled in
   uint16_t GetNumColors();
 
   LexerTransition<ICOState> ReadHeader(const char* aData);
   LexerTransition<ICOState> ReadDirEntry(const char* aData);
   LexerTransition<ICOState> SniffResource(const char* aData);
@@ -115,17 +109,17 @@ private:
   LexerTransition<ICOState> PrepareForMask();
   LexerTransition<ICOState> ReadMaskRow(const char* aData);
   LexerTransition<ICOState> FinishMask();
   LexerTransition<ICOState> FinishResource();
 
   StreamingLexer<ICOState, 32> mLexer; // The lexer.
   RefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
   UniquePtr<uint8_t[]> mMaskBuffer;    // A temporary buffer for the alpha mask.
-  char mBIHraw[40];                    // The bitmap information header.
+  char mBIHraw[bmp::InfoHeaderLength::WIN_ICO]; // The bitmap information header.
   IconDirEntry mDirEntry;              // The dir entry for the selected resource.
   IntSize mBiggestResourceSize;        // Used to select the intrinsic size.
   IntSize mBiggestResourceHotSpot;     // Used to select the intrinsic size.
   uint16_t mBiggestResourceColorDepth; // Used to select the intrinsic size.
   int32_t mBestResourceDelta;          // Used to select the best resource.
   uint16_t mBestResourceColorDepth;    // Used to select the best resource.
   uint16_t mNumIcons; // Stores the number of icons in the ICO file.
   uint16_t mCurrIcon; // Stores the current dir entry index we are processing.
--- a/image/encoders/bmp/nsBMPEncoder.cpp
+++ b/image/encoders/bmp/nsBMPEncoder.cpp
@@ -482,19 +482,19 @@ void
 nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
                              uint32_t aHeight)
 {
   memset(&mBMPFileHeader, 0, sizeof(mBMPFileHeader));
   mBMPFileHeader.signature[0] = 'B';
   mBMPFileHeader.signature[1] = 'M';
 
   if (aVersion == VERSION_3) {
-    mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V3;
+    mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V3;
   } else { // aVersion == 5
-    mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V5;
+    mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V5;
   }
 
   // The color table is present only if BPP is <= 8
   if (aBPP <= 8) {
     uint32_t numColors = 1 << aBPP;
     mBMPFileHeader.dataoffset += 4 * numColors;
     mBMPFileHeader.filesize = mBMPFileHeader.dataoffset + aWidth * aHeight;
   } else {
--- a/image/encoders/bmp/nsBMPEncoder.h
+++ b/image/encoders/bmp/nsBMPEncoder.h
@@ -6,28 +6,84 @@
 #ifndef mozilla_image_encoders_bmp_nsBMPEncoder_h
 #define mozilla_image_encoders_bmp_nsBMPEncoder_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/UniquePtr.h"
 
 #include "imgIEncoder.h"
-#include "BMPFileHeaders.h"
+#include "BMPHeaders.h"
 
 #include "nsCOMPtr.h"
 
 #define NS_BMPENCODER_CID \
 { /* 13a5320c-4c91-4FA4-bd16-b081a3ba8c0b */         \
      0x13a5320c,                                     \
      0x4c91,                                         \
      0x4fa4,                                         \
     {0xbd, 0x16, 0xb0, 0x81, 0xa3, 0Xba, 0x8c, 0x0b} \
 }
 
+namespace mozilla {
+namespace image {
+namespace bmp {
+
+struct FileHeader {
+  char signature[2];   // String "BM".
+  uint32_t filesize;   // File size.
+  int32_t reserved;    // Zero.
+  uint32_t dataoffset; // Offset to raster data.
+};
+
+struct XYZ {
+  int32_t x, y, z;
+};
+
+struct XYZTriple {
+  XYZ r, g, b;
+};
+
+struct V5InfoHeader {
+  uint32_t bihsize;          // Header size
+  int32_t width;             // Uint16 in OS/2 BMPs
+  int32_t height;            // Uint16 in OS/2 BMPs
+  uint16_t planes;           // =1
+  uint16_t bpp;              // Bits per pixel.
+  uint32_t compression;      // See Compression for valid values
+  uint32_t image_size;       // (compressed) image size. Can be 0 if
+                             // compression==0
+  uint32_t xppm;             // Pixels per meter, horizontal
+  uint32_t yppm;             // Pixels per meter, vertical
+  uint32_t colors;           // Used Colors
+  uint32_t important_colors; // Number of important colors. 0=all
+  // The rest of the header is not available in WIN_V3 BMP Files
+  uint32_t red_mask;         // Bits used for red component
+  uint32_t green_mask;       // Bits used for green component
+  uint32_t blue_mask;        // Bits used for blue component
+  uint32_t alpha_mask;       // Bits used for alpha component
+  uint32_t color_space;      // 0x73524742=LCS_sRGB ...
+  // These members are unused unless color_space == LCS_CALIBRATED_RGB
+  XYZTriple white_point;     // Logical white point
+  uint32_t gamma_red;        // Red gamma component
+  uint32_t gamma_green;      // Green gamma component
+  uint32_t gamma_blue;       // Blue gamma component
+  uint32_t intent;           // Rendering intent
+  // These members are unused unless color_space == LCS_PROFILE_*
+  uint32_t profile_offset;   // Offset to profile data in bytes
+  uint32_t profile_size;     // Size of profile data in bytes
+  uint32_t reserved;         // =0
+
+  static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742;
+};
+
+} // namespace bmp
+} // namespace image
+} // namespace mozilla
+
 // Provides BMP encoding functionality. Use InitFromData() to do the
 // encoding. See that function definition for encoding options.
 
 class nsBMPEncoder final : public imgIEncoder
 {
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
--- a/image/encoders/ico/nsICOEncoder.cpp
+++ b/image/encoders/ico/nsICOEncoder.cpp
@@ -157,36 +157,36 @@ nsICOEncoder::AddImageFrame(const uint8_
     mImageBufferStart = static_cast<uint8_t*>(malloc(mImageBufferSize));
     if (!mImageBufferStart) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     mImageBufferCurr = mImageBufferStart;
 
     // Icon files that wrap a BMP file must not include the BITMAPFILEHEADER
     // section at the beginning of the encoded BMP data, so we must skip over
-    // bmp::FileHeader::LENGTH bytes when adding the BMP content to the icon
+    // bmp::FILE_HEADER_LENGTH bytes when adding the BMP content to the icon
     // file.
     mICODirEntry.mBytesInRes =
-      BMPImageBufferSize - bmp::FileHeader::LENGTH + andMaskSize;
+      BMPImageBufferSize - bmp::FILE_HEADER_LENGTH + andMaskSize;
 
     // Encode the icon headers
     EncodeFileHeader();
     EncodeInfoHeader();
 
     char* imageBuffer;
     rv = mContainedEncoder->GetImageBuffer(&imageBuffer);
     NS_ENSURE_SUCCESS(rv, rv);
-    memcpy(mImageBufferCurr, imageBuffer + bmp::FileHeader::LENGTH,
-           BMPImageBufferSize - bmp::FileHeader::LENGTH);
+    memcpy(mImageBufferCurr, imageBuffer + bmp::FILE_HEADER_LENGTH,
+           BMPImageBufferSize - bmp::FILE_HEADER_LENGTH);
     // We need to fix the BMP height to be *2 for the AND mask
     uint32_t fixedHeight = GetRealHeight() * 2;
     NativeEndian::swapToLittleEndianInPlace(&fixedHeight, 1);
     // The height is stored at an offset of 8 from the DIB header
     memcpy(mImageBufferCurr + 8, &fixedHeight, sizeof(fixedHeight));
-    mImageBufferCurr += BMPImageBufferSize - bmp::FileHeader::LENGTH;
+    mImageBufferCurr += BMPImageBufferSize - bmp::FILE_HEADER_LENGTH;
 
     // Calculate rowsize in DWORD's
     uint32_t rowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up
     int32_t currentLine = GetRealHeight();
 
     // Write out the AND mask
     while (currentLine > 0) {
       currentLine--;
--- a/image/encoders/jpeg/nsJPEGEncoder.cpp
+++ b/image/encoders/jpeg/nsJPEGEncoder.cpp
@@ -157,29 +157,29 @@ nsJPEGEncoder::InitFromData(const uint8_
 
   // feed it the rows
   if (aInputFormat == INPUT_FORMAT_RGB) {
     while (cinfo.next_scanline < cinfo.image_height) {
       const uint8_t* row = &aData[cinfo.next_scanline * aStride];
       jpeg_write_scanlines(&cinfo, const_cast<uint8_t**>(&row), 1);
     }
   } else if (aInputFormat == INPUT_FORMAT_RGBA) {
-    uint8_t* row = new uint8_t[aWidth * 3];
+    UniquePtr<uint8_t[]> rowptr = MakeUnique<uint8_t[]>(aWidth * 3);
+    uint8_t* row = rowptr.get();
     while (cinfo.next_scanline < cinfo.image_height) {
       ConvertRGBARow(&aData[cinfo.next_scanline * aStride], row, aWidth);
       jpeg_write_scanlines(&cinfo, &row, 1);
     }
-    delete[] row;
   } else if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
-    uint8_t* row = new uint8_t[aWidth * 3];
+    UniquePtr<uint8_t[]> rowptr = MakeUnique<uint8_t[]>(aWidth * 3);
+    uint8_t* row = rowptr.get();
     while (cinfo.next_scanline < cinfo.image_height) {
       ConvertHostARGBRow(&aData[cinfo.next_scanline * aStride], row, aWidth);
       jpeg_write_scanlines(&cinfo, &row, 1);
     }
-    delete[] row;
   }
 
   jpeg_finish_compress(&cinfo);
   jpeg_destroy_compress(&cinfo);
 
   mFinished = true;
   NotifyListener();
 
--- a/image/encoders/png/nsPNGEncoder.cpp
+++ b/image/encoders/png/nsPNGEncoder.cpp
@@ -282,32 +282,28 @@ nsPNGEncoder::AddImageFrame(const uint8_
   png_set_filter(mPNG, PNG_FILTER_TYPE_BASE, PNG_FILTER_VALUE_NONE);
 #endif
 
   // write each row: if we add more input formats, we may want to
   // generalize the conversions
   if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
     // PNG requires RGBA with post-multiplied alpha, so we need to
     // convert
-    uint8_t* row = new uint8_t[aWidth * 4];
+    UniquePtr<uint8_t[]> row = MakeUnique<uint8_t[]>(aWidth * 4);
     for (uint32_t y = 0; y < aHeight; y++) {
-      ConvertHostARGBRow(&aData[y * aStride], row, aWidth, useTransparency);
-      png_write_row(mPNG, row);
+      ConvertHostARGBRow(&aData[y * aStride], row.get(), aWidth, useTransparency);
+      png_write_row(mPNG, row.get());
     }
-    delete[] row;
-
   } else if (aInputFormat == INPUT_FORMAT_RGBA && !useTransparency) {
     // RBGA, but we need to strip the alpha
-    uint8_t* row = new uint8_t[aWidth * 4];
+    UniquePtr<uint8_t[]> row = MakeUnique<uint8_t[]>(aWidth * 4);
     for (uint32_t y = 0; y < aHeight; y++) {
-      StripAlpha(&aData[y * aStride], row, aWidth);
-      png_write_row(mPNG, row);
+      StripAlpha(&aData[y * aStride], row.get(), aWidth);
+      png_write_row(mPNG, row.get());
     }
-    delete[] row;
-
   } else if (aInputFormat == INPUT_FORMAT_RGB ||
              aInputFormat == INPUT_FORMAT_RGBA) {
     // simple RBG(A), no conversion needed
     for (uint32_t y = 0; y < aHeight; y++) {
       png_write_row(mPNG, (uint8_t*)&aData[y * aStride]);
     }
 
   } else {
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -319,16 +319,24 @@ typedef bool
 /**
  * The old-style JSClass.enumerate op should define all lazy properties not
  * yet reflected in obj.
  */
 typedef bool
 (* JSEnumerateOp)(JSContext* cx, JS::HandleObject obj);
 
 /**
+ * The type of ObjectOps::funToString.  This callback allows an object to
+ * provide a custom string to use when Function.prototype.toString is invoked on
+ * that object.  A null return value means OOM.
+ */
+typedef JSString*
+(* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent);
+
+/**
  * Resolve a lazy property named by id in obj by defining it directly in obj.
  * Lazy properties are those reflected from some peer native property space
  * (e.g., the DOM attributes for a given node reflected as obj) on demand.
  *
  * JS looks for a property in an object, and if not found, tries to resolve
  * the given id. *resolvedp should be set to true iff the property was
  * was defined on |obj|.
  */
@@ -645,32 +653,33 @@ struct ObjectOps
     SetPropertyOp       setProperty;
     GetOwnPropertyOp    getOwnPropertyDescriptor;
     DeletePropertyOp    deleteProperty;
     WatchOp             watch;
     UnwatchOp           unwatch;
     GetElementsOp       getElements;
     JSNewEnumerateOp    enumerate;
     ThisValueOp         thisValue;
+    JSFunToStringOp     funToString;
 };
 
 #define JS_NULL_OBJECT_OPS                                                    \
     {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,  \
      nullptr, nullptr, nullptr, nullptr}
 
 } // namespace js
 
 // Classes, objects, and properties.
 
 typedef void (*JSClassInternal)();
 
 struct JSClass {
     JS_CLASS_MEMBERS(JSFinalizeOp);
 
-    void*               reserved[25];
+    void*               reserved[26];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  // objects have private slot
 #define JSCLASS_DELAY_METADATA_CALLBACK (1<<1)  // class's initialization code
                                                 // will call
                                                 // SetNewObjectMetadata itself
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  // private is (nsISupports*)
 #define JSCLASS_IS_DOMJSCLASS           (1<<4)  // objects are DOM
--- a/js/src/asmjs/AsmJSFrameIterator.cpp
+++ b/js/src/asmjs/AsmJSFrameIterator.cpp
@@ -131,17 +131,17 @@ static const unsigned PushedRetAddr = 4;
 static const unsigned PushedFP = 16;
 static const unsigned StoredFP = 20;
 static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_ARM64)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PushedFP = 0;
 static const unsigned StoredFP = 0;
 static const unsigned PostStorePrePopFP = 0;
-#elif defined(JS_CODEGEN_MIPS32)
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
 static const unsigned PushedRetAddr = 8;
 static const unsigned PushedFP = 24;
 static const unsigned StoredFP = 28;
 static const unsigned PostStorePrePopFP = 4;
 #elif defined(JS_CODEGEN_NONE)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PostStorePrePopFP = 0;
@@ -152,17 +152,17 @@ static const unsigned StoredFP = 1;
 # error "Unknown architecture!"
 #endif
 
 static void
 PushRetAddr(MacroAssembler& masm)
 {
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
-#elif defined(JS_CODEGEN_MIPS32)
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     masm.push(ra);
 #else
     // The x86/x64 call instruction pushes the return address.
 #endif
 }
 
 // Generate a prologue that maintains AsmJSActivation::fp as the virtual frame
 // pointer so that AsmJSProfilingFrameIterator can walk the stack at any pc in
@@ -216,17 +216,18 @@ GenerateProfilingPrologue(MacroAssembler
 }
 
 // Generate the inverse of GenerateProfilingPrologue.
 static void
 GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, AsmJSExit::Reason reason,
                           Label* profilingReturn)
 {
     Register scratch = ABIArgGenerator::NonReturn_VolatileReg0;
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
+    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     Register scratch2 = ABIArgGenerator::NonReturn_VolatileReg1;
 #endif
 
     if (framePushed)
         masm.addToStackPtr(Imm32(framePushed));
 
     masm.loadAsmJSActivation(scratch);
 
@@ -240,17 +241,18 @@ GenerateProfilingEpilogue(MacroAssembler
 #if defined(JS_CODEGEN_ARM)
         AutoForbidPools afp(&masm, /* number of instructions in scope = */ 4);
 #endif
 
         // sp protects the stack from clobber via asynchronous signal handlers
         // and the async interrupt exit. Since activation.fp can be read at any
         // time and still points to the current frame, be careful to only update
         // sp after activation.fp has been repointed to the caller's frame.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
+    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
         masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
         masm.storePtr(scratch2, Address(scratch, AsmJSActivation::offsetOfFP()));
         DebugOnly<uint32_t> prePop = masm.currentOffset();
         masm.addToStackPtr(Imm32(sizeof(void *)));
         MOZ_ASSERT_IF(!masm.oom(), PostStorePrePopFP == masm.currentOffset() - prePop);
 #else
         masm.pop(Address(scratch, AsmJSActivation::offsetOfFP()));
         MOZ_ASSERT(PostStorePrePopFP == 0);
@@ -339,16 +341,23 @@ js::GenerateAsmJSFunctionEpilogue(MacroA
         masm.twoByteNop();
 #elif defined(JS_CODEGEN_ARM)
         masm.nop();
 #elif defined(JS_CODEGEN_MIPS32)
         masm.nop();
         masm.nop();
         masm.nop();
         masm.nop();
+#elif defined(JS_CODEGEN_MIPS64)
+        masm.nop();
+        masm.nop();
+        masm.nop();
+        masm.nop();
+        masm.nop();
+        masm.nop();
 #endif
     }
 
     // Normal epilogue:
     masm.addToStackPtr(Imm32(framePushed + AsmJSFrameBytesAfterReturnAddress));
     masm.ret();
     masm.setFramePushed(0);
 
@@ -561,17 +570,17 @@ AsmJSProfilingFrameIterator::AsmJSProfil
         // innermost call. To avoid this problem, we use the static structure of
         // the code in the prologue and epilogue to do the Right Thing.
         uint32_t offsetInModule = (uint8_t*)state.pc - module_->codeBase();
         MOZ_ASSERT(offsetInModule < module_->codeBytes());
         MOZ_ASSERT(offsetInModule >= codeRange->begin());
         MOZ_ASSERT(offsetInModule < codeRange->end());
         uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
         void** sp = (void**)state.sp;
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
         if (offsetInCodeRange < PushedRetAddr) {
             // First instruction of the ARM/MIPS function; the return address is
             // still in lr and fp still holds the caller's fp.
             callerPC_ = state.lr;
             callerFP_ = fp;
             AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp - 2);
         } else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) {
             // Second-to-last instruction of the ARM/MIPS function; fp points to
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -379,16 +379,27 @@ AsmJSModule::finish(ExclusiveContext* cx
     for (size_t i = 0; i < masm.numLongJumps(); i++) {
         RelativeLink link(RelativeLink::InstructionImmediate);
         link.patchAtOffset = masm.longJump(i);
         InstImm* inst = (InstImm*)(code_ + masm.longJump(i));
         link.targetOffset = Assembler::ExtractLuiOriValue(inst, inst->next()) - (uint32_t)code_;
         if (!staticLinkData_.relativeLinks.append(link))
             return false;
     }
+#elif defined(JS_CODEGEN_MIPS64)
+    // On MIPS64 we need to update all the long jumps because they contain an
+    // absolute adress.
+    for (size_t i = 0; i < masm.numLongJumps(); i++) {
+        RelativeLink link(RelativeLink::InstructionImmediate);
+        link.patchAtOffset = masm.longJump(i);
+        InstImm* inst = (InstImm*)(code_ + masm.longJump(i));
+        link.targetOffset = Assembler::ExtractLoad64Value(inst) - (uint64_t)code_;
+        if (!staticLinkData_.relativeLinks.append(link))
+            return false;
+    }
 #endif
 
 #if defined(JS_CODEGEN_X64)
     // Global data accesses on x64 use rip-relative addressing and thus do
     // not need patching after deserialization.
     for (size_t i = 0; i < masm.numAsmJSGlobalAccesses(); i++) {
         AsmJSGlobalAccess a = masm.asmJSGlobalAccess(i);
         masm.patchAsmJSGlobalAccess(a.patchAt, code_, globalData(), a.globalDataOffset);
@@ -821,17 +832,17 @@ AsmJSModule::initHeap(Handle<ArrayBuffer
     // CodeGeneratorX64::visitAsmJS{Load,Store,CompareExchange,Exchange,AtomicBinop}Heap)
     uint32_t heapLength = heap->byteLength();
     for (size_t i = 0; i < heapAccesses_.length(); i++) {
         const jit::AsmJSHeapAccess& access = heapAccesses_[i];
         // See comment above for x86 codegen.
         if (access.hasLengthCheck())
             X86Encoding::AddInt32(access.patchLengthAt(code_), heapLength);
     }
-#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     uint32_t heapLength = heap->byteLength();
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         jit::Assembler::UpdateBoundsCheck(heapLength,
                                           (jit::Instruction*)(heapAccesses_[i].insnOffset() + code_));
     }
 #endif
 }
 
@@ -1734,16 +1745,19 @@ AsmJSModule::setProfilingEnabled(bool en
         void* callee = calleeOffset.getDest(callerInsn);
 #elif defined(JS_CODEGEN_ARM64)
         MOZ_CRASH();
         void* callee = nullptr;
         (void)callerRetAddr;
 #elif defined(JS_CODEGEN_MIPS32)
         Instruction* instr = (Instruction*)(callerRetAddr - 4 * sizeof(uint32_t));
         void* callee = (void*)Assembler::ExtractLuiOriValue(instr, instr->next());
+#elif defined(JS_CODEGEN_MIPS64)
+        Instruction* instr = (Instruction*)(callerRetAddr - 6 * sizeof(uint32_t));
+        void* callee = (void*)Assembler::ExtractLoad64Value(instr);
 #elif defined(JS_CODEGEN_NONE)
         MOZ_CRASH();
         void* callee = nullptr;
 #else
 # error "Missing architecture"
 #endif
 
         const CodeRange* codeRange = lookupCodeRange(callee);
@@ -1762,16 +1776,19 @@ AsmJSModule::setProfilingEnabled(bool en
         new (caller) InstBLImm(BOffImm(newCallee - caller), Assembler::Always);
 #elif defined(JS_CODEGEN_ARM64)
         (void)newCallee;
         MOZ_CRASH();
 #elif defined(JS_CODEGEN_MIPS32)
         Assembler::WriteLuiOriInstructions(instr, instr->next(),
                                            ScratchRegister, (uint32_t)newCallee);
         instr[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
+#elif defined(JS_CODEGEN_MIPS64)
+        Assembler::WriteLoad64Instructions(instr, ScratchRegister, (uint64_t)newCallee);
+        instr[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
 #elif defined(JS_CODEGEN_NONE)
         MOZ_CRASH();
 #else
 # error "Missing architecture"
 #endif
     }
 
     // Update all the addresses in the function-pointer tables to point to the
@@ -1836,16 +1853,28 @@ AsmJSModule::setProfilingEnabled(bool en
             Assembler::WriteLuiOriInstructions(instr, instr->next(),
                                                ScratchRegister, (uint32_t)profilingEpilogue);
             instr[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr);
         } else {
             instr[0].makeNop();
             instr[1].makeNop();
             instr[2].makeNop();
         }
+#elif defined(JS_CODEGEN_MIPS64)
+        Instruction* instr = (Instruction*)jump;
+        if (enabled) {
+            Assembler::WriteLoad64Instructions(instr, ScratchRegister, (uint64_t)profilingEpilogue);
+            instr[4] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr);
+        } else {
+            instr[0].makeNop();
+            instr[1].makeNop();
+            instr[2].makeNop();
+            instr[3].makeNop();
+            instr[4].makeNop();
+        }
 #elif defined(JS_CODEGEN_NONE)
         MOZ_CRASH();
 #else
 # error "Missing architecture"
 #endif
     }
 
     // Replace all calls to builtins with calls to profiling thunks that push a
@@ -1876,16 +1905,17 @@ AsmJSModule::setProfilingEnabled(bool en
 static bool
 GetCPUID(uint32_t* cpuId)
 {
     enum Arch {
         X86 = 0x1,
         X64 = 0x2,
         ARM = 0x3,
         MIPS = 0x4,
+        MIPS64 = 0x5,
         ARCH_BITS = 3
     };
 
 #if defined(JS_CODEGEN_X86)
     MOZ_ASSERT(uint32_t(CPUInfo::GetSSEVersion()) <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = X86 | (uint32_t(CPUInfo::GetSSEVersion()) << ARCH_BITS);
     return true;
 #elif defined(JS_CODEGEN_X64)
@@ -1895,16 +1925,20 @@ GetCPUID(uint32_t* cpuId)
 #elif defined(JS_CODEGEN_ARM)
     MOZ_ASSERT(GetARMFlags() <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = ARM | (GetARMFlags() << ARCH_BITS);
     return true;
 #elif defined(JS_CODEGEN_MIPS32)
     MOZ_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
     *cpuId = MIPS | (GetMIPSFlags() << ARCH_BITS);
     return true;
+#elif defined(JS_CODEGEN_MIPS64)
+    MOZ_ASSERT(GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
+    *cpuId = MIPS64 | (GetMIPSFlags() << ARCH_BITS);
+    return true;
 #else
     return false;
 #endif
 }
 
 class MachineId
 {
     uint32_t cpuId_;
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -741,35 +741,35 @@ class AsmJSModule
             InstructionImmediate
         };
 
         RelativeLink()
         { }
 
         explicit RelativeLink(Kind kind)
         {
-#if defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
             kind_ = kind;
 #elif defined(JS_CODEGEN_ARM)
             // On ARM, CodeLabels are only used to label raw pointers, so in
             // all cases on ARM, a RelativePatch means patching a raw pointer.
             MOZ_ASSERT(kind == CodeLabel || kind == RawPointer);
 #endif
             // On X64 and X86, all RelativePatch-es are patched as raw pointers.
         }
 
         bool isRawPointerPatch() {
-#if defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
             return kind_ == RawPointer;
 #else
             return true;
 #endif
         }
 
-#ifdef JS_CODEGEN_MIPS32
+#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
         Kind kind_;
 #endif
         uint32_t patchAtOffset;
         uint32_t targetOffset;
     };
 
     typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector;
 
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -7050,37 +7050,37 @@ GenerateEntry(ModuleValidator& m, unsign
 
     Label begin;
     masm.haltingAlign(CodeAlignment);
     masm.bind(&begin);
 
     // Save the return address if it wasn't already saved by the call insn.
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
-#elif defined(JS_CODEGEN_MIPS32)
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     masm.push(ra);
 #elif defined(JS_CODEGEN_X86)
     static const unsigned EntryFrameSize = sizeof(void*);
 #endif
 
     // Save all caller non-volatile registers before we clobber them here and in
     // the asm.js callee (which does not preserve non-volatile registers).
     masm.setFramePushed(0);
     masm.PushRegsInMask(NonVolatileRegs);
     MOZ_ASSERT(masm.framePushed() == FramePushedAfterSave);
 
-    // ARM and MIPS have a globally-pinned GlobalReg (x64 uses RIP-relative
+    // ARM and MIPS/MIPS64 have a globally-pinned GlobalReg (x64 uses RIP-relative
     // addressing, x86 uses immediates in effective addresses). For the
     // AsmJSGlobalRegBias addition, see Assembler-(mips,arm).h.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     masm.movePtr(IntArgReg1, GlobalReg);
     masm.addPtr(Imm32(AsmJSGlobalRegBias), GlobalReg);
 #endif
 
-    // ARM, MIPS and x64 have a globally-pinned HeapReg (x86 uses immediates in
+    // ARM, MIPS/MIPS64 and x64 have a globally-pinned HeapReg (x86 uses immediates in
     // effective addresses). Loading the heap register depends on the global
     // register already having been loaded.
     masm.loadAsmJSHeapRegisterFromGlobalData();
 
     // Put the 'argv' argument into a non-argument/return register so that we
     // can use 'argv' while we fill in the arguments for the asm.js callee.
     // Also, save 'argv' on the stack so that we can recover it after the call.
     // Use a second non-argument/return register as temporary scratch.
@@ -7379,17 +7379,17 @@ GenerateFFIInterpExit(ModuleValidator& m
     masm.loadAsmJSHeapRegisterFromGlobalData();
     GenerateCheckForHeapDetachment(m, ABIArgGenerator::NonReturn_VolatileReg0);
 
     Label profilingReturn;
     GenerateAsmJSExitEpilogue(masm, framePushed, AsmJSExit::SlowFFI, &profilingReturn);
     return !masm.oom() && m.finishGeneratingInterpExit(exitIndex, &begin, &profilingReturn);
 }
 
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
 static const unsigned MaybeSavedGlobalReg = sizeof(void*);
 #else
 static const unsigned MaybeSavedGlobalReg = 0;
 #endif
 
 static bool
 GenerateFFIIonExit(ModuleValidator& m, const Signature& sig, unsigned exitIndex,
                    Label* throwLabel)
@@ -7423,17 +7423,17 @@ GenerateFFIIonExit(ModuleValidator& m, c
     Register scratch = ABIArgGenerator::NonArgReturnReg1;  // repeatedly clobbered
 
     // 2.1. Get ExitDatum
     unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
 #if defined(JS_CODEGEN_X64)
     m.masm().append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
 #elif defined(JS_CODEGEN_X86)
     m.masm().append(AsmJSGlobalAccess(masm.movlWithPatch(Imm32(0), callee), globalDataOffset));
-#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
+#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     masm.computeEffectiveAddress(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), callee);
 #endif
 
     // 2.2. Get callee
     masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
 
     // 2.3. Save callee
     masm.storePtr(callee, Address(masm.getStackPointer(), argOffset));
@@ -7459,17 +7459,17 @@ GenerateFFIIonExit(ModuleValidator& m, c
     MOZ_ASSERT(argOffset == ionFrameBytes);
 
     // 6. Jit code will clobber all registers, even non-volatiles. GlobalReg and
     //    HeapReg are removed from the general register set for asm.js code, so
     //    these will not have been saved by the caller like all other registers,
     //    so they must be explicitly preserved. Only save GlobalReg since
     //    HeapReg must be reloaded (from global data) after the call since the
     //    heap may change during the FFI call.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
     masm.storePtr(GlobalReg, Address(masm.getStackPointer(), ionFrameBytes));
 #endif
 
     {
         // Enable Activation.
         //
         // This sequence requires four registers, and needs to preserve the 'callee'
@@ -7575,17 +7575,17 @@ GenerateFFIIonExit(ModuleValidator& m, c
         masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext));
 
         //   rt->jitActivation = prevJitActivation_;
         masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitActivation()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfJitActivation));
     }
 
     // Reload the global register since Ion code can clobber any register.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
     masm.loadPtr(Address(masm.getStackPointer(), ionFrameBytes), GlobalReg);
 #endif
 
     // As explained above, the frame was aligned for Ion such that
     //   (sp + sizeof(void*)) % JitStackAlignment == 0
     // But now we possibly want to call one of several different C++ functions,
     // so subtract the sizeof(void*) so that sp is aligned for an ABI call.
@@ -7890,17 +7890,17 @@ GenerateAsyncInterruptExit(ModuleValidat
 
     // Restore the StackPointer to its position before the call.
     masm.moveToStackPtr(ABIArgGenerator::NonVolatileReg);
 
     // Restore the machine state to before the interrupt.
     masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
     masm.popFlags();              // after this, nothing that sets conditions
     masm.ret();                   // pop resumePC into PC
-#elif defined(JS_CODEGEN_MIPS32)
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     // Reserve space to store resumePC.
     masm.subFromStackPtr(Imm32(sizeof(intptr_t)));
     // set to zero so we can use masm.framePushed() below.
     masm.setFramePushed(0);
     // When this platform supports SIMD extensions, we'll need to push high lanes
     // of SIMD registers as well.
     JS_STATIC_ASSERT(!SupportsSimd);
     // save all registers,except sp. After this stack is alligned.
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -271,24 +271,36 @@ class LifoAlloc
 
     MOZ_ALWAYS_INLINE
     void* alloc(size_t n) {
         JS_OOM_POSSIBLY_FAIL();
         return allocImpl(n);
     }
 
     MOZ_ALWAYS_INLINE
-    void* allocInfallible(size_t n) {
+    void* allocInfallibleOrAssert(size_t n) {
+        void* result = allocImpl(n);
+        MOZ_RELEASE_ASSERT(result, "[OOM] Is it really infallible?");
+        return result;
+    }
+
+    MOZ_ALWAYS_INLINE
+    void* allocInfallibleOrCrash(size_t n) {
         AutoEnterOOMUnsafeRegion oomUnsafe;
         if (void* result = allocImpl(n))
             return result;
         oomUnsafe.crash("LifoAlloc::allocInfallible");
         return nullptr;
     }
 
+    MOZ_ALWAYS_INLINE
+    void* allocInfallible(size_t n) {
+        return allocInfallibleOrCrash(n);
+    }
+
     // Ensures that enough space exists to satisfy N bytes worth of
     // allocation requests, not necessarily contiguous. Note that this does
     // not guarantee a successful single allocation of N bytes.
     MOZ_ALWAYS_INLINE
     bool ensureUnusedApproximate(size_t n) {
         size_t total = 0;
         for (BumpChunk* chunk = latest; chunk; chunk = chunk->next()) {
             total += chunk->unused();
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -5190,16 +5190,20 @@ Parser<FullParseHandler>::forStatement(Y
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
 
     /*
      * True if we have 'for (var/let/const ...)'.
      */
     bool isForDecl = false;
 
+    // True if a 'let' token at the head is parsed as an identifier instead of
+    // as starting a declaration.
+    bool letIsIdentifier = false;
+
     /* Non-null when isForDecl is true for a 'for (let ...)' statement. */
     RootedStaticBlockObject blockObj(context);
 
     /* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
     ParseNode* pn1;
 
     TokenStream::Modifier modifier = TokenStream::Operand;
     {
@@ -5217,29 +5221,48 @@ Parser<FullParseHandler>::forStatement(Y
             // expression.  But for declarations at the start of a for-loop
             // head, initializers can't contain |in|.  (Such syntax conflicts
             // with ES5's |for (var i = 0 in foo)| syntax, removed in ES6, that
             // we "support" by ignoring the |= 0|.)
             if (tt == TOK_VAR) {
                 isForDecl = true;
                 tokenStream.consumeKnownToken(tt, TokenStream::Operand);
                 pn1 = variables(yieldHandling, PNK_VAR, InForInit);
-            } else if (tt == TOK_LET || tt == TOK_CONST) {
+            } else if (tt == TOK_LET || tt == TOK_CONST ||
+                       (tt == TOK_NAME && tokenStream.nextName() == context->names().let)) {
                 handler.disableSyntaxParser();
-                bool constDecl = tt == TOK_CONST;
-                tokenStream.consumeKnownToken(tt, TokenStream::Operand);
-                isForDecl = true;
-                blockObj = StaticBlockObject::create(context);
-                if (!blockObj)
-                    return null();
-                // Initialize the enclosing scope manually for the call to
-                // |variables| below.
-                blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
-                pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
-                                nullptr, blockObj, DontHoistVars);
+
+                // Check for the backwards-compatibility corner case in sloppy
+                // mode like |for (let in e)| where the 'let' token should be
+                // parsed as an identifier.
+                bool parseDecl;
+                if (tt == TOK_NAME) {
+                    if (!peekShouldParseLetDeclaration(&parseDecl, TokenStream::Operand))
+                        return null();
+                    letIsIdentifier = !parseDecl;
+                } else {
+                    parseDecl = true;
+                    tokenStream.consumeKnownToken(tt, TokenStream::Operand);
+                }
+
+                if (parseDecl) {
+                    bool constDecl = tt == TOK_CONST;
+                    isForDecl = true;
+                    blockObj = StaticBlockObject::create(context);
+                    if (!blockObj)
+                        return null();
+
+                    // Initialize the enclosing scope manually for the call to
+                    // |variables| below.
+                    blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
+                    pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
+                                    nullptr, blockObj, DontHoistVars);
+                } else {
+                    pn1 = expr(InProhibited, yieldHandling, TripledotProhibited);
+                }
             } else {
                 // Pass |InProhibited| when parsing an expression so that |in|
                 // isn't parsed in a RelationalExpression as a binary operator.
                 // In this context, |in| is part of a for-in loop -- *not* part
                 // of a binary expression.
                 pn1 = expr(InProhibited, yieldHandling, TripledotProhibited);
             }
             if (!pn1)
@@ -5304,19 +5327,27 @@ Parser<FullParseHandler>::forStatement(Y
     Maybe<AutoPushStmtInfoPC> letStmt; /* used if blockObj != nullptr. */
     ParseNode* pn2;      /* forHead->pn_kid2 */
     ParseNode* pn3;      /* forHead->pn_kid3 */
     ParseNodeKind headKind = PNK_FORHEAD;
     if (pn1) {
         bool isForIn, isForOf;
         if (!matchInOrOf(&isForIn, &isForOf))
             return null();
+
+        // In for-in loops, a 'let' token may be used as an identifier for
+        // backwards-compatibility reasons, e.g., |for (let in e)|. In for-of
+        // loops, a 'let' token is never parsed as an identifier. Forbid
+        // trying to parse a for-of loop if we have parsed a 'let' token as an
+        // identifier above.
+        //
+        // See ES6 13.7.5.1.
         if (isForIn)
             headKind = PNK_FORIN;
-        else if (isForOf)
+        else if (isForOf && !letIsIdentifier)
             headKind = PNK_FOROF;
     }
 
     if (headKind == PNK_FOROF || headKind == PNK_FORIN) {
         /*
          * Parse the rest of the for/in or for/of head.
          *
          * Here pn1 is everything to the left of 'in' or 'of'. At the end of
@@ -5562,22 +5593,22 @@ Parser<SyntaxParseHandler>::forStatement
         if (tt == TOK_SEMI) {
             lhsNode = null();
         } else {
             /* Set lhsNode to a var list or an initializing expression. */
             if (tt == TOK_VAR) {
                 isForDecl = true;
                 tokenStream.consumeKnownToken(tt, TokenStream::Operand);
                 lhsNode = variables(yieldHandling, PNK_VAR, InForInit, &simpleForDecl);
-            }
-            else if (tt == TOK_CONST || tt == TOK_LET) {
+            } else if (tt == TOK_CONST || tt == TOK_LET ||
+                       (tt == TOK_NAME && tokenStream.nextName() == context->names().let))
+            {
                 JS_ALWAYS_FALSE(abortIfSyntaxParser());
                 return null();
-            }
-            else {
+            } else {
                 lhsNode = expr(InProhibited, yieldHandling, TripledotProhibited);
             }
             if (!lhsNode)
                 return null();
             modifier = TokenStream::None;
         }
     }
 
@@ -6623,16 +6654,81 @@ Parser<SyntaxParseHandler>::classDefinit
                                             ClassContext classContext,
                                             DefaultHandling defaultHandling)
 {
     MOZ_ALWAYS_FALSE(abortIfSyntaxParser());
     return SyntaxParseHandler::NodeFailure;
 }
 
 template <typename ParseHandler>
+bool
+Parser<ParseHandler>::shouldParseLetDeclaration(bool* parseDeclOut)
+{
+    // 'let' is a reserved keyword in strict mode and we shouldn't get here.
+    MOZ_ASSERT(!pc->sc->strict());
+
+    TokenKind tt;
+    *parseDeclOut = false;
+
+    if (!tokenStream.peekToken(&tt))
+        return false;
+
+    switch (tt) {
+      case TOK_NAME:
+        // |let let| is disallowed per ES6 13.3.1.1.
+        *parseDeclOut = tokenStream.nextName() != context->names().let;
+        break;
+
+      case TOK_LC:
+      case TOK_LB:
+        // A following name is always a declaration.
+        //
+        // |let {| and |let [| are destructuring declarations.
+        *parseDeclOut = true;
+        break;
+
+      case TOK_LP:
+        // Only parse let blocks for 1.7 and 1.8. Do not expose deprecated let
+        // blocks to content.
+        *parseDeclOut = versionNumber() == JSVERSION_1_7 || versionNumber() == JSVERSION_1_8;
+        break;
+
+      default:
+        break;
+    }
+
+    return true;
+}
+
+template <typename ParseHandler>
+bool
+Parser<ParseHandler>::peekShouldParseLetDeclaration(bool* parseDeclOut,
+                                                    TokenStream::Modifier modifier)
+{
+    *parseDeclOut = false;
+
+#ifdef DEBUG
+    TokenKind tt;
+    if (!tokenStream.peekToken(&tt, modifier))
+        return false;
+    MOZ_ASSERT(tt == TOK_NAME && tokenStream.nextName() == context->names().let);
+#endif
+
+    tokenStream.consumeKnownToken(TOK_NAME, modifier);
+    if (!shouldParseLetDeclaration(parseDeclOut))
+        return false;
+
+    // Unget the TOK_NAME of 'let' if not parsing a declaration.
+    if (!*parseDeclOut)
+        tokenStream.ungetToken();
+
+    return true;
+}
+
+template <typename ParseHandler>
 typename ParseHandler::Node
 Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirectives)
 {
     MOZ_ASSERT(checkOptionsCalled);
 
     JS_CHECK_RECURSION(context, return null());
 
     TokenKind tt;
@@ -6691,16 +6787,26 @@ Parser<ParseHandler>::statement(YieldHan
             if (!checkYieldNameValidity())
                 return null();
             return labeledStatement(yieldHandling);
         }
         return expressionStatement(yieldHandling);
       }
 
       case TOK_NAME: {
+        // 'let' is a contextual keyword in sloppy node. In strict mode, it is
+        // always lexed as TOK_LET.
+        if (tokenStream.currentName() == context->names().let) {
+            bool parseDecl;
+            if (!shouldParseLetDeclaration(&parseDecl))
+                return null();
+            if (parseDecl)
+                return lexicalDeclaration(yieldHandling, /* isConst = */ false);
+        }
+
         TokenKind next;
         if (!tokenStream.peekToken(&next))
             return null();
         if (next == TOK_COLON)
             return labeledStatement(yieldHandling);
         return expressionStatement(yieldHandling);
       }
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -795,16 +795,25 @@ class Parser : private JS::AutoGCRooter,
                                  bool* pbodyProcessed);
     bool finishFunctionDefinition(Node pn, FunctionBox* funbox, Node body);
     bool addFreeVariablesFromLazyFunction(JSFunction* fun, ParseContext<ParseHandler>* pc);
 
     bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach,
                                 ParseNodeKind headKind);
     bool checkForHeadConstInitializers(Node pn1);
 
+    // Use when the current token is TOK_NAME and is known to be 'let'.
+    bool shouldParseLetDeclaration(bool* parseDeclOut);
+
+    // Use when the lookahead token is TOK_NAME and is known to be 'let'. If a
+    // let declaration should be parsed, the TOK_NAME token of 'let' is
+    // consumed. Otherwise, the current token remains the TOK_NAME token of
+    // 'let'.
+    bool peekShouldParseLetDeclaration(bool* parseDeclOut, TokenStream::Modifier modifier);
+
   public:
     enum FunctionCallBehavior {
         PermitAssignmentToFunctionCalls,
         ForbidAssignmentToFunctionCalls
     };
 
     bool isValidSimpleAssignmentTarget(Node node,
                                        FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -994,29 +994,28 @@ TokenStream::checkForKeyword(const Keywo
 #endif
         )
     {
         return reportError(JSMSG_RESERVED_ID, kw->chars);
     }
 
     if (kw->tokentype != TOK_STRICT_RESERVED) {
         if (kw->version <= versionNumber()) {
+            // Treat 'let' as an identifier and contextually a keyword in
+            // sloppy mode. It is always a keyword in strict mode.
+            if (kw->tokentype == TOK_LET && !strictMode())
+                return true;
+
             // Working keyword.
             if (ttp) {
                 *ttp = kw->tokentype;
                 return true;
             }
             return reportError(JSMSG_RESERVED_ID, kw->chars);
         }
-
-        // The keyword is not in this version. Treat it as an identifier, unless
-        // it is let which we treat as TOK_STRICT_RESERVED by falling through to
-        // the code below (ES5 forbids it in strict mode).
-        if (kw->tokentype != TOK_LET)
-            return true;
     }
 
     // Strict reserved word.
     return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars);
 }
 
 bool
 TokenStream::checkForKeyword(JSAtom* atom, TokenKind* ttp)
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -360,16 +360,23 @@ class MOZ_STACK_CLASS TokenStream
 
     PropertyName* currentName() const {
         if (isCurrentTokenType(TOK_YIELD))
             return cx->names().yield;
         MOZ_ASSERT(isCurrentTokenType(TOK_NAME));
         return currentToken().name();
     }
 
+    PropertyName* nextName() const {
+        if (nextToken().type == TOK_YIELD)
+            return cx->names().yield;
+        MOZ_ASSERT(nextToken().type == TOK_NAME);
+        return nextToken().name();
+    }
+
     bool isCurrentTokenAssignment() const {
         return TokenKindIsAssignment(currentToken().type);
     }
 
     // Flag methods.
     bool isEOF() const { return flags.isEOF; }
     bool sawOctalEscape() const { return flags.sawOctalEscape; }
     bool hadError() const { return flags.hadError; }
@@ -994,22 +1001,22 @@ class MOZ_STACK_CLASS TokenStream
     void skipChars(int n) {
         while (--n >= 0)
             getChar();
     }
 
     void updateLineInfoForEOL();
     void updateFlagsForEOL();
 
-    const Token& nextToken() {
+    const Token& nextToken() const {
         MOZ_ASSERT(hasLookahead());
         return tokens[(cursor + 1) & ntokensMask];
     }
 
-    bool hasLookahead() { return lookahead > 0; }
+    bool hasLookahead() const { return lookahead > 0; }
 
     // Options used for parsing/tokenizing.
     const ReadOnlyCompileOptions& options_;
 
     Token               tokens[ntokens];    // circular token buffer
     unsigned            cursor;             // index of last parsed token
     unsigned            lookahead;          // count of lookahead tokens
     unsigned            lineno;             // current line number
--- a/js/src/jit-test/tests/basic/destructuring-rest-identifiers.js
+++ b/js/src/jit-test/tests/basic/destructuring-rest-identifiers.js
@@ -52,17 +52,17 @@ var strictIdentifiers = [
   'interface',
   'package',
   'private',
   'protected',
   'public',
   'static'
 ];
 assertThrowsInstanceOf(() => new Function('[...yield] = []'), SyntaxError);
-assertThrowsInstanceOf(() => new Function('[...let] = []'), SyntaxError);
+assertThrowsInstanceOf(() => new Function('"use strict"; [...let] = []'), SyntaxError);
 
 strictIdentifiers.forEach(ident =>
   assertThrowsInstanceOf(() =>
     new Function('"use strict"; [...' + ident + '] = []'), SyntaxError));
 
 var globalEval = eval;
 strictIdentifiers.forEach(ident => {
   globalEval(ident + ' = null');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parser/letContextualKeyword.js
@@ -0,0 +1,29 @@
+function expectError(str) {
+  var log = "";
+  try {
+    eval(str);
+  } catch (e) {
+    log += "e";
+    assertEq(e instanceof SyntaxError, true);
+  }
+  assertEq(log, "e");
+}
+
+eval(`let x = 42; assertEq(x, 42);`);
+eval(`var let = 42; assertEq(let, 42);`);
+eval(`let;`);
+eval(`[...let] = [];`);
+eval(`function let() { return 42; } assertEq(let(), 42);`)
+eval(`let {x:x} = {x:42}; assertEq(x, 42);`);
+eval(`let [x] = [42]; assertEq(x, 42);`);
+eval(`for (let x in [1]) { assertEq(x, "0"); }`);
+eval(`for (let x of [1]) { assertEq(x, 1); }`);
+eval(`for (let i = 0; i < 1; i++) { assertEq(i, 0); }`);
+eval(`for (let in [1]) { assertEq(let, "0"); }`);
+eval(`for (let of of [1]) { assertEq(of, 1); }`);
+eval(`for (let/1;;) { break; }`);
+expectError(`for (let of [1]) { }`);
+expectError(`let let = 42;`);
+expectError(`"use strict"; var let = 42;`);
+expectError(`"use strict"; function let() {}`);
+expectError(`"use strict"; for (let of [1]) {}`);
--- a/js/src/jit-test/tests/parser/truncation.js
+++ b/js/src/jit-test/tests/parser/truncation.js
@@ -1,17 +1,16 @@
 load(libdir + "asserts.js");
 
 var cases = [
     "{",
     "{ ;",
     "var",
     "var x,",
     "var x =",
-    "let",
     "let x,",
     "let x =",
     "const",
     "const x =",
     "const x = 1,",
     "if",
     "if (",
     "if (0) ; else",
--- a/js/src/jit/JitAllocPolicy.h
+++ b/js/src/jit/JitAllocPolicy.h
@@ -32,17 +32,17 @@ class TempAllocator
     static const size_t PreferredLifoChunkSize; // 32 KiB
 
     explicit TempAllocator(LifoAlloc* lifoAlloc)
       : lifoScope_(lifoAlloc)
     { }
 
     void* allocateInfallible(size_t bytes)
     {
-        return lifoScope_.alloc().allocInfallible(bytes);
+        return lifoScope_.alloc().allocInfallibleOrAssert(bytes);
     }
 
     void* allocate(size_t bytes)
     {
         void* p = lifoScope_.alloc().alloc(bytes);
         if (!ensureBallast())
             return nullptr;
         return p;
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -58,17 +58,17 @@
 // forgot to define the method in one of the macro assembler, or you forgot to
 // update the annotation of the macro assembler declaration.
 //
 // Some convenient short-cuts are used to avoid repeating the same list of
 // architectures on each method declaration, such as PER_ARCH and
 // PER_SHARED_ARCH.
 
 # define ALL_ARCH mips32, arm, arm64, x86, x64
-# define ALL_SHARED_ARCH mips32, arm, arm64, x86_shared
+# define ALL_SHARED_ARCH arm, arm64, x86_shared, mips_shared
 
 // * How this macro works:
 //
 // DEFINED_ON is a macro which check if, for the current architecture, the
 // method is defined on the macro assembler or not.
 //
 // For each architecutre, we have a macro named DEFINED_ON_arch.  This macro is
 // empty if this is not the current architecture.  Otherwise it must be either
@@ -102,16 +102,17 @@
 // annotation on the method declaration.
 
 # define DEFINED_ON_x86
 # define DEFINED_ON_x64
 # define DEFINED_ON_x86_shared
 # define DEFINED_ON_arm
 # define DEFINED_ON_arm64
 # define DEFINED_ON_mips32
+# define DEFINED_ON_mips_shared
 # define DEFINED_ON_none
 
 // Specialize for each architecture.
 #if defined(JS_CODEGEN_X86)
 # undef DEFINED_ON_x86
 # define DEFINED_ON_x86 define
 # undef DEFINED_ON_x86_shared
 # define DEFINED_ON_x86_shared define
@@ -124,16 +125,18 @@
 # undef DEFINED_ON_arm
 # define DEFINED_ON_arm define
 #elif defined(JS_CODEGEN_ARM64)
 # undef DEFINED_ON_arm64
 # define DEFINED_ON_arm64 define
 #elif defined(JS_CODEGEN_MIPS32)
 # undef DEFINED_ON_mips32
 # define DEFINED_ON_mips32 define
+# undef DEFINED_ON_mips_shared
+# define DEFINED_ON_mips_shared define
 #elif defined(JS_CODEGEN_NONE)
 # undef DEFINED_ON_none
 # define DEFINED_ON_none crash
 #else
 # error "Unknown architecture!"
 #endif
 
 # define DEFINED_ON_RESULT_crash   { MOZ_CRASH(); }
new file mode 100644
--- /dev/null
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_mips_shared_MacroAssembler_mips_shared_inl_h
+#define jit_mips_shared_MacroAssembler_mips_shared_inl_h
+
+#include "jit/mips-shared/MacroAssembler-mips-shared.h"
+
+namespace js {
+namespace jit {
+
+//{{{ check_macroassembler_style
+// ===============================================================
+// Logical instructions
+
+void
+MacroAssembler::not32(Register reg)
+{
+    ma_not(reg, reg);
+}
+
+void
+MacroAssembler::and32(Register src, Register dest)
+{
+    as_and(dest, dest, src);
+}
+
+void
+MacroAssembler::and32(Imm32 imm, Register dest)
+{
+    ma_and(dest, imm);
+}
+
+void
+MacroAssembler::and32(Imm32 imm, const Address& dest)
+{
+    load32(dest, SecondScratchReg);
+    ma_and(SecondScratchReg, imm);
+    store32(SecondScratchReg, dest);
+}
+
+void
+MacroAssembler::and32(const Address& src, Register dest)
+{
+    load32(src, SecondScratchReg);
+    ma_and(dest, SecondScratchReg);
+}
+
+void
+MacroAssembler::or32(Register src, Register dest)
+{
+    ma_or(dest, src);
+}
+
+void
+MacroAssembler::or32(Imm32 imm, Register dest)
+{
+    ma_or(dest, imm);
+}
+
+void
+MacroAssembler::or32(Imm32 imm, const Address& dest)
+{
+    load32(dest, SecondScratchReg);
+    ma_or(SecondScratchReg, imm);
+    store32(SecondScratchReg, dest);
+}
+
+void
+MacroAssembler::xor32(Imm32 imm, Register dest)
+{
+    ma_xor(dest, imm);
+}
+
+//}}} check_macroassembler_style
+// ===============================================================
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_mips_shared_MacroAssembler_mips_shared_inl_h */
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -783,8 +783,193 @@ MacroAssemblerMIPSShared::asMasm()
     return *static_cast<MacroAssembler*>(this);
 }
 
 const MacroAssembler&
 MacroAssemblerMIPSShared::asMasm() const
 {
     return *static_cast<const MacroAssembler*>(this);
 }
+
+//{{{ check_macroassembler_style
+// ===============================================================
+// Stack manipulation functions.
+
+void
+MacroAssembler::PushRegsInMask(LiveRegisterSet set)
+{
+    int32_t diffF = set.fpus().getPushSizeInBytes();
+    int32_t diffG = set.gprs().size() * sizeof(intptr_t);
+
+    reserveStack(diffG);
+    for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
+        diffG -= sizeof(intptr_t);
+        storePtr(*iter, Address(StackPointer, diffG));
+    }
+    MOZ_ASSERT(diffG == 0);
+
+    // Double values have to be aligned. We reserve extra space so that we can
+    // start writing from the first aligned location.
+    // We reserve a whole extra double so that the buffer has even size.
+    ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1)));
+    reserveStack(diffF + sizeof(double));
+
+    for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) {
+        if ((*iter).code() % 2 == 0)
+            as_sd(*iter, SecondScratchReg, -diffF);
+        diffF -= sizeof(double);
+    }
+    MOZ_ASSERT(diffF == 0);
+}
+
+void
+MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
+{
+    int32_t diffG = set.gprs().size() * sizeof(intptr_t);
+    int32_t diffF = set.fpus().getPushSizeInBytes();
+    const int32_t reservedG = diffG;
+    const int32_t reservedF = diffF;
+
+    // Read the buffer form the first aligned location.
+    ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
+    ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1)));
+
+    for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) {
+        if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
+            // Use assembly l.d because we have alligned the stack.
+            as_ld(*iter, SecondScratchReg, -diffF);
+        diffF -= sizeof(double);
+    }
+    freeStack(reservedF + sizeof(double));
+    MOZ_ASSERT(diffF == 0);
+
+    for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
+        diffG -= sizeof(intptr_t);
+        if (!ignore.has(*iter))
+            loadPtr(Address(StackPointer, diffG), *iter);
+    }
+    freeStack(reservedG);
+    MOZ_ASSERT(diffG == 0);
+}
+
+void
+MacroAssembler::Push(Register reg)
+{
+    ma_push(reg);
+    adjustFrame(sizeof(intptr_t));
+}
+
+void
+MacroAssembler::Push(const Imm32 imm)
+{
+    ma_li(ScratchRegister, imm);
+    ma_push(ScratchRegister);
+    adjustFrame(sizeof(intptr_t));
+}
+
+void
+MacroAssembler::Push(const ImmWord imm)
+{
+    ma_li(ScratchRegister, imm);
+    ma_push(ScratchRegister);
+    adjustFrame(sizeof(intptr_t));
+}
+
+void
+MacroAssembler::Push(const ImmPtr imm)
+{
+    Push(ImmWord(uintptr_t(imm.value)));
+}
+
+void
+MacroAssembler::Push(const ImmGCPtr ptr)
+{
+    ma_li(ScratchRegister, ptr);
+    ma_push(ScratchRegister);
+    adjustFrame(sizeof(intptr_t));
+}
+
+void
+MacroAssembler::Push(FloatRegister f)
+{
+    ma_push(f);
+    adjustFrame(sizeof(double));
+}
+
+void
+MacroAssembler::Pop(Register reg)
+{
+    ma_pop(reg);
+    adjustFrame(-sizeof(intptr_t));
+}
+
+void
+MacroAssembler::Pop(const ValueOperand& val)
+{
+    popValue(val);
+    framePushed_ -= sizeof(Value);
+}
+
+
+// ===============================================================
+// Simple call functions.
+
+void
+MacroAssembler::call(Register reg)
+{
+    as_jalr(reg);
+    as_nop();
+}
+
+void
+MacroAssembler::call(Label* label)
+{
+    ma_bal(label);
+}
+
+void
+MacroAssembler::call(AsmJSImmPtr target)
+{
+    movePtr(target, CallReg);
+    call(CallReg);
+}
+
+void
+MacroAssembler::call(ImmWord target)
+{
+    call(ImmPtr((void*)target.value));
+}
+
+void
+MacroAssembler::call(ImmPtr target)
+{
+    BufferOffset bo = m_buffer.nextOffset();
+    addPendingJump(bo, target, Relocation::HARDCODED);
+    ma_call(target);
+}
+
+void
+MacroAssembler::call(JitCode* c)
+{
+    BufferOffset bo = m_buffer.nextOffset();
+    addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
+    ma_liPatchable(ScratchRegister, ImmPtr(c->raw()));
+    callJitNoProfiler(ScratchRegister);
+}
+
+// ===============================================================
+// Jit Frames.
+
+uint32_t
+MacroAssembler::pushFakeReturnAddress(Register scratch)
+{
+    CodeLabel cl;
+
+    ma_li(scratch, cl.dest());
+    Push(scratch);
+    bind(cl.src());
+    uint32_t retAddr = currentOffset();
+
+    addCodeLabel(cl);
+    return retAddr;
+}
+
+//}}} check_macroassembler_style
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -4,57 +4,26 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_mips32_MacroAssembler_mips32_inl_h
 #define jit_mips32_MacroAssembler_mips32_inl_h
 
 #include "jit/mips32/MacroAssembler-mips32.h"
 
+#include "jit/mips-shared/MacroAssembler-mips-shared-inl.h"
+
 namespace js {
 namespace jit {
 
 //{{{ check_macroassembler_style
 // ===============================================================
 // Logical instructions
 
 void
-MacroAssembler::not32(Register reg)
-{
-    ma_not(reg, reg);
-}
-
-void
-MacroAssembler::and32(Register src, Register dest)
-{
-    as_and(dest, dest, src);
-}
-
-void
-MacroAssembler::and32(Imm32 imm, Register dest)
-{
-    ma_and(dest, imm);
-}
-
-void
-MacroAssembler::and32(Imm32 imm, const Address& dest)
-{
-    load32(dest, SecondScratchReg);
-    ma_and(SecondScratchReg, imm);
-    store32(SecondScratchReg, dest);
-}
-
-void
-MacroAssembler::and32(const Address& src, Register dest)
-{
-    load32(src, SecondScratchReg);
-    ma_and(dest, SecondScratchReg);
-}
-
-void
 MacroAssembler::andPtr(Register src, Register dest)
 {
     ma_and(dest, src);
 }
 
 void
 MacroAssembler::andPtr(Imm32 imm, Register dest)
 {
@@ -64,36 +33,16 @@ MacroAssembler::andPtr(Imm32 imm, Regist
 void
 MacroAssembler::and64(Imm64 imm, Register64 dest)
 {
     and32(Imm32(imm.value & LOW_32_MASK), dest.low);
     and32(Imm32((imm.value >> 32) & LOW_32_MASK), dest.high);
 }
 
 void
-MacroAssembler::or32(Register src, Register dest)
-{
-    ma_or(dest, src);
-}
-
-void
-MacroAssembler::or32(Imm32 imm, Register dest)
-{
-    ma_or(dest, imm);
-}
-
-void
-MacroAssembler::or32(Imm32 imm, const Address& dest)
-{
-    load32(dest, SecondScratchReg);
-    ma_or(SecondScratchReg, imm);
-    store32(SecondScratchReg, dest);
-}
-
-void
 MacroAssembler::orPtr(Register src, Register dest)
 {
     ma_or(dest, src);
 }
 
 void
 MacroAssembler::orPtr(Imm32 imm, Register dest)
 {
@@ -103,22 +52,16 @@ MacroAssembler::orPtr(Imm32 imm, Registe
 void
 MacroAssembler::or64(Register64 src, Register64 dest)
 {
     or32(src.low, dest.low);
     or32(src.high, dest.high);
 }
 
 void
-MacroAssembler::xor32(Imm32 imm, Register dest)
-{
-    ma_xor(dest, imm);
-}
-
-void
 MacroAssembler::xorPtr(Register src, Register dest)
 {
     ma_xor(dest, src);
 }
 
 void
 MacroAssembler::xorPtr(Imm32 imm, Register dest)
 {
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -2493,185 +2493,27 @@ MacroAssemblerMIPSCompat::profilerExitFr
     branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
 }
 
 //{{{ check_macroassembler_style
 // ===============================================================
 // Stack manipulation functions.
 
 void
-MacroAssembler::PushRegsInMask(LiveRegisterSet set)
-{
-    int32_t diffF = set.fpus().getPushSizeInBytes();
-    int32_t diffG = set.gprs().size() * sizeof(intptr_t);
-
-    reserveStack(diffG);
-    for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
-        diffG -= sizeof(intptr_t);
-        storePtr(*iter, Address(StackPointer, diffG));
-    }
-    MOZ_ASSERT(diffG == 0);
-
-    // Double values have to be aligned. We reserve extra space so that we can
-    // start writing from the first aligned location.
-    // We reserve a whole extra double so that the buffer has even size.
-    ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1)));
-    reserveStack(diffF + sizeof(double));
-
-    for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) {
-        if ((*iter).code() % 2 == 0)
-            as_sd(*iter, SecondScratchReg, -diffF);
-        diffF -= sizeof(double);
-    }
-    MOZ_ASSERT(diffF == 0);
-}
-
-void
-MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
-{
-    int32_t diffG = set.gprs().size() * sizeof(intptr_t);
-    int32_t diffF = set.fpus().getPushSizeInBytes();
-    const int32_t reservedG = diffG;
-    const int32_t reservedF = diffF;
-
-    // Read the buffer form the first aligned location.
-    ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
-    ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1)));
-
-    for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); iter++) {
-        if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
-            // Use assembly l.d because we have alligned the stack.
-            as_ld(*iter, SecondScratchReg, -diffF);
-        diffF -= sizeof(double);
-    }
-    freeStack(reservedF + sizeof(double));
-    MOZ_ASSERT(diffF == 0);
-
-    for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
-        diffG -= sizeof(intptr_t);
-        if (!ignore.has(*iter))
-            loadPtr(Address(StackPointer, diffG), *iter);
-    }
-    freeStack(reservedG);
-    MOZ_ASSERT(diffG == 0);
-}
-
-void
-MacroAssembler::Push(Register reg)
-{
-    ma_push(reg);
-    adjustFrame(sizeof(intptr_t));
-}
-
-void
-MacroAssembler::Push(const Imm32 imm)
-{
-    ma_li(ScratchRegister, imm);
-    ma_push(ScratchRegister);
-    adjustFrame(sizeof(intptr_t));
-}
-
-void
-MacroAssembler::Push(const ImmWord imm)
-{
-    ma_li(ScratchRegister, imm);
-    ma_push(ScratchRegister);
-    adjustFrame(sizeof(intptr_t));
-}
-
-void
-MacroAssembler::Push(const ImmPtr imm)
-{
-    Push(ImmWord(uintptr_t(imm.value)));
-}
-
-void
-MacroAssembler::Push(const ImmGCPtr ptr)
-{
-    ma_li(ScratchRegister, ptr);
-    ma_push(ScratchRegister);
-    adjustFrame(sizeof(intptr_t));
-}
-
-void
-MacroAssembler::Push(FloatRegister f)
-{
-    ma_push(f);
-    adjustFrame(sizeof(double));
-}
-
-void
-MacroAssembler::Pop(Register reg)
-{
-    ma_pop(reg);
-    adjustFrame(-sizeof(intptr_t));
-}
-
-void
-MacroAssembler::Pop(const ValueOperand& val)
-{
-    popValue(val);
-    framePushed_ -= sizeof(Value);
-}
-
-void
 MacroAssembler::reserveStack(uint32_t amount)
 {
     if (amount)
         subPtr(Imm32(amount), StackPointer);
     adjustFrame(amount);
 }
 
 // ===============================================================
 // Simple call functions.
 
 void
-MacroAssembler::call(Register reg)
-{
-    as_jalr(reg);
-    as_nop();
-}
-
-void
-MacroAssembler::call(Label* label)
-{
-    ma_bal(label);
-}
-
-void
-MacroAssembler::call(AsmJSImmPtr target)
-{
-    movePtr(target, CallReg);
-    call(CallReg);
-}
-
-void
-MacroAssembler::call(ImmWord target)
-{
-    call(ImmPtr((void*)target.value));
-}
-
-void
-MacroAssembler::call(ImmPtr target)
-{
-    BufferOffset bo = m_buffer.nextOffset();
-    addPendingJump(bo, target, Relocation::HARDCODED);
-    ma_call(target);
-}
-
-void
-MacroAssembler::call(JitCode* c)
-{
-    BufferOffset bo = m_buffer.nextOffset();
-    addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
-    ma_liPatchable(ScratchRegister, ImmPtr(c->raw()));
-    callJitNoProfiler(ScratchRegister);
-}
-
-void
 MacroAssembler::callAndPushReturnAddress(Register callee)
 {
     // Push return address during jalr delay slot.
     subPtr(Imm32(sizeof(intptr_t)), StackPointer);
     as_jalr(callee);
     storePtr(ra, Address(StackPointer, 0));
 }
 
@@ -2780,26 +2622,9 @@ MacroAssembler::callWithABINoProfiler(co
     // Load the callee in t9, as above.
     loadPtr(Address(fun.base, fun.offset), t9);
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
     call(t9);
     callWithABIPost(stackAdjust, result);
 }
 
-// ===============================================================
-// Jit Frames.
-
-uint32_t
-MacroAssembler::pushFakeReturnAddress(Register scratch)
-{
-    CodeLabel cl;
-
-    ma_li(scratch, cl.dest());
-    Push(scratch);
-    bind(cl.src());
-    uint32_t retAddr = currentOffset();
-
-    addCodeLabel(cl);
-    return retAddr;
-}
-
 //}}} check_macroassembler_style
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -744,17 +744,17 @@ struct JSCompartment
         return jitCompartment_;
     }
 
     enum DeprecatedLanguageExtension {
         DeprecatedForEach = 0,              // JS 1.6+
         // NO LONGER USING 1
         DeprecatedLegacyGenerator = 2,      // JS 1.7+
         DeprecatedExpressionClosure = 3,    // Added in JS 1.8
-        DeprecatedLetBlock = 4,             // Added in JS 1.7
+        // NO LONGER USING 4
         // NO LONGER USING 5
         DeprecatedNoSuchMethod = 6,         // JS 1.7+
         DeprecatedFlagsArgument = 7,        // JS 1.3 or older
         // NO LONGER USING 8
         DeprecatedRestoredRegExpStatics = 9,// Unknown
         DeprecatedLanguageExtensionCount
     };
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -349,16 +349,17 @@ namespace js {
             js::proxy_GetProperty,                                                      \
             js::proxy_SetProperty,                                                      \
             js::proxy_GetOwnPropertyDescriptor,                                         \
             js::proxy_DeleteProperty,                                                   \
             js::proxy_Watch, js::proxy_Unwatch,                                         \
             js::proxy_GetElements,                                                      \
             nullptr,             /* enumerate       */                                  \
             nullptr,             /* thisObject      */                                  \
+            js::proxy_FunToString,                                                      \
         }                                                                               \
     }
 
 #define PROXY_CLASS_DEF(name, flags)                                    \
   PROXY_CLASS_WITH_EXT(name, flags,                                     \
                        PROXY_MAKE_EXT(                                  \
                          nullptr, /* outerObject */                     \
                          nullptr, /* innerObject */                     \
@@ -414,16 +415,18 @@ extern JS_FRIEND_API(JSObject*)
 proxy_innerObject(JSObject* obj);
 extern JS_FRIEND_API(bool)
 proxy_Watch(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
 extern JS_FRIEND_API(bool)
 proxy_Unwatch(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
 extern JS_FRIEND_API(bool)
 proxy_GetElements(JSContext* cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
                   ElementAdder* adder);
+extern JS_FRIEND_API(JSString*)
+proxy_FunToString(JSContext* cx, JS::HandleObject proxy, unsigned indent);
 
 /**
  * A class of objects that return source code on demand.
  *
  * When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't
  * retain the source code (and doesn't do lazy bytecode generation). If we ever
  * need the source code, say, in response to a call to Function.prototype.
  * toSource or Debugger.Source.prototype.text, then we call the 'load' member
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1103,18 +1103,19 @@ js::FunctionToString(JSContext* cx, Hand
     }
     return out.finishString();
 }
 
 JSString*
 fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent)
 {
     if (!obj->is<JSFunction>()) {
-        if (obj->is<ProxyObject>())
-            return Proxy::fun_toString(cx, obj, indent);
+        if (JSFunToStringOp op = obj->getOps()->funToString)
+            return op(cx, obj, indent);
+
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_INCOMPATIBLE_PROTO,
                              js_Function_str, js_toString_str,
                              "object");
         return nullptr;
     }
 
     RootedFunction fun(cx, &obj->as<JSFunction>());
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -733,16 +733,22 @@ js::proxy_Unwatch(JSContext* cx, HandleO
 
 bool
 js::proxy_GetElements(JSContext* cx, HandleObject proxy, uint32_t begin, uint32_t end,
                       ElementAdder* adder)
 {
     return Proxy::getElements(cx, proxy, begin, end, adder);
 }
 
+JSString*
+js::proxy_FunToString(JSContext* cx, HandleObject proxy, unsigned indent)
+{
+    return Proxy::fun_toString(cx, proxy, indent);
+}
+
 const Class js::ProxyObject::class_ =
     PROXY_CLASS_DEF("Proxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy));
 
 const Class* const js::ProxyClassPtr = &js::ProxyObject::class_;
 
 JS_FRIEND_API(JSObject*)
 js::NewProxyObject(JSContext* cx, const BaseProxyHandler* handler, HandleValue priv, JSObject* proto_,
                    const ProxyOptions& options)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3979,35 +3979,40 @@ PrintProfilerEvents(JSContext* cx, unsig
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (cx->runtime()->spsProfiler.enabled())
         js::RegisterRuntimeProfilingEventMarker(cx->runtime(), &PrintProfilerEvents_Callback);
     args.rval().setUndefined();
     return true;
 }
 
-#if defined(JS_SIMULATOR_ARM)
+#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS64)
 typedef Vector<char16_t, 0, SystemAllocPolicy> StackChars;
 Vector<StackChars, 0, SystemAllocPolicy> stacks;
 
 static void
 SingleStepCallback(void* arg, jit::Simulator* sim, void* pc)
 {
     JSRuntime* rt = reinterpret_cast<JSRuntime*>(arg);
 
     // If profiling is not enabled, don't do anything.
     if (!rt->spsProfiler.enabled())
         return;
 
     JS::ProfilingFrameIterator::RegisterState state;
     state.pc = pc;
+#if defined(JS_SIMULATOR_ARM)
     state.sp = (void*)sim->get_register(jit::Simulator::sp);
     state.lr = (void*)sim->get_register(jit::Simulator::lr);
-
-    DebugOnly<void*> lastStackAddress = nullptr;
+#elif defined(JS_SIMULATOR_MIPS64)
+    state.sp = (void*)sim->getRegister(jit::Simulator::sp);
+    state.lr = (void*)sim->getRegister(jit::Simulator::ra);
+#endif
+
+    mozilla::DebugOnly<void*> lastStackAddress = nullptr;
     StackChars stack;
     uint32_t frameNo = 0;
     for (JS::ProfilingFrameIterator i(rt, state); !i.done(); ++i) {
         MOZ_ASSERT(i.stackAddress() != nullptr);
         MOZ_ASSERT(lastStackAddress <= i.stackAddress());
         lastStackAddress = i.stackAddress();
         JS::ProfilingFrameIterator::Frame frames[16];
         uint32_t nframes = i.extractStack(frames, 0, 16);
@@ -4027,34 +4032,34 @@ SingleStepCallback(void* arg, jit::Simul
         stacks.append(Move(stack));
     }
 }
 #endif
 
 static bool
 EnableSingleStepProfiling(JSContext* cx, unsigned argc, Value* vp)
 {
-#if defined(JS_SIMULATOR_ARM)
+#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS64)
     CallArgs args = CallArgsFromVp(argc, vp);
 
     jit::Simulator* sim = cx->runtime()->simulator();
     sim->enable_single_stepping(SingleStepCallback, cx->runtime());
 
     args.rval().setUndefined();
     return true;
 #else
     JS_ReportError(cx, "single-step profiling not enabled on this platform");
     return false;
 #endif
 }
 
 static bool
 DisableSingleStepProfiling(JSContext* cx, unsigned argc, Value* vp)
 {
-#if defined(JS_SIMULATOR_ARM)
+#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS64)
     CallArgs args = CallArgsFromVp(argc, vp);
 
     jit::Simulator* sim = cx->runtime()->simulator();
     sim->disable_single_stepping();
 
     AutoValueVector elems(cx);
     for (size_t i = 0; i < stacks.length(); i++) {
         JSString* stack = JS_NewUCStringCopyN(cx, stacks[i].begin(), stacks[i].length());
@@ -6203,17 +6208,17 @@ SetRuntimeOptions(JSRuntime* rt, const O
 
 #if defined(JS_SIMULATOR_ARM)
     if (op.getBoolOption("arm-sim-icache-checks"))
         jit::Simulator::ICacheCheckingEnabled = true;
 
     int32_t stopAt = op.getIntOption("arm-sim-stop-at");
     if (stopAt >= 0)
         jit::Simulator::StopSimAt = stopAt;
-#elif defined(JS_SIMULATOR_MIPS32)
+#elif defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
     if (op.getBoolOption("mips-sim-icache-checks"))
         jit::Simulator::ICacheCheckingEnabled = true;
 
     int32_t stopAt = op.getIntOption("mips-sim-stop-at");
     if (stopAt >= 0)
         jit::Simulator::StopSimAt = stopAt;
 #endif
 
@@ -6505,17 +6510,17 @@ main(int argc, char** argv, char** envp)
         || !op.addIntOption('\0', "asm-pool-max-offset", "OFFSET",
                             "The maximum pc relative OFFSET permitted in pool reference instructions.", 1024)
 #endif
 #if defined(JS_SIMULATOR_ARM)
         || !op.addBoolOption('\0', "arm-sim-icache-checks", "Enable icache flush checks in the ARM "
                              "simulator.")
         || !op.addIntOption('\0', "arm-sim-stop-at", "NUMBER", "Stop the ARM simulator after the given "
                             "NUMBER of instructions.", -1)
-#elif defined(JS_SIMULATOR_MIPS32)
+#elif defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
 	|| !op.addBoolOption('\0', "mips-sim-icache-checks", "Enable icache flush checks in the MIPS "
                              "simulator.")
         || !op.addIntOption('\0', "mips-sim-stop-at", "NUMBER", "Stop the MIPS simulator after the given "
                             "NUMBER of instructions.", -1)
 #endif
         || !op.addIntOption('\0', "nursery-size", "SIZE-MB", "Set the maximum nursery size in MB", 16)
 #ifdef JS_GC_ZEAL
         || !op.addStringOption('z', "gc-zeal", "LEVEL[,N]", gc::ZealModeHelpText)
deleted file mode 100644
--- a/js/src/tests/js1_6/extensions/regress-352392.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */
-
-//-----------------------------------------------------------------------------
-var BUGNUMBER = 352392;
-var summary = 'Do not hang/crash |for each| over object with getter set to map';
-var actual = 'No Crash';
-var expect = 'No Crash';
-
-
-//-----------------------------------------------------------------------------
-test();
-//-----------------------------------------------------------------------------
-
-function test()
-{
-  enterFunc ('test');
-  printBugNumber(BUGNUMBER);
-  printStatus (summary);
-
-  expect = 'SyntaxError: invalid for each loop';
-  try
-  {
-    var obj = { };
-    Object.defineProperty(obj, "y", { get: Array.prototype.map, enumerable: true, configurable: true });
-    eval('(function() { for each(let z in obj) { } })()');
-  }
-  catch(ex)
-  {
-    actual = ex + '';
-  }
-
-  reportCompare(expect, actual, summary);
-
-  exitFunc ('test');
-}
--- a/js/src/tests/js1_7/lexical/regress-351515.js
+++ b/js/src/tests/js1_7/lexical/regress-351515.js
@@ -35,17 +35,17 @@ try
 catch(ex)
 {
   actual = ex.name;
 }
 reportCompare(expect, actual, summary + ': local: yield = 1');
 
 try
 {
-  expect = "SyntaxError";
+  expect = "No Error";
   eval('let = 1;');
   actual = 'No Error';
 }
 catch(ex)
 {
   actual = ex.name;
 }
 reportCompare(expect, actual, summary + ': global: let = 1');
@@ -78,17 +78,17 @@ function test()
   catch(ex)
   {
     actual = ex.name;
   }
   reportCompare(expect, actual, summary + ': function () {var yield;}');
 
   try
   {
-    expect = "SyntaxError";
+    expect = "No Error";
     eval('var let = 1;');
     actual = 'No Error';
   }
   catch(ex)
   {
     actual = ex.name;
   }
   reportCompare(expect, actual, summary + ': function () { var let;}');
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -793,16 +793,21 @@ InitElemOperation(JSContext* cx, HandleO
 static MOZ_ALWAYS_INLINE bool
 InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t index, HandleValue val)
 {
     JSOp op = JSOp(*pc);
     MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC);
 
     MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
 
+    if (op == JSOP_INITELEM_INC && index == INT32_MAX) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE);
+        return false;
+    }
+
     /*
      * If val is a hole, do not call DefineElement.
      *
      * Furthermore, if the current op is JSOP_INITELEM_INC, always call
      * SetLengthProperty even if it is not the last element initialiser,
      * because it may be followed by JSOP_SPREAD, which will not set the array
      * length if nothing is spread.
      *
@@ -815,21 +820,16 @@ InitArrayElemOperation(JSContext* cx, js
             if (!SetLengthProperty(cx, obj, index + 1))
                 return false;
         }
     } else {
         if (!DefineElement(cx, obj, index, val, nullptr, nullptr, JSPROP_ENUMERATE))
             return false;
     }
 
-    if (op == JSOP_INITELEM_INC && index == INT32_MAX) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE);
-        return false;
-    }
-
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
 ProcessCallSiteObjOperation(JSContext* cx, RootedObject& cso, RootedObject& raw,
                             RootedValue& rawValue)
 {
     bool extensible;
--- a/js/src/vm/Keywords.h
+++ b/js/src/vm/Keywords.h
@@ -57,15 +57,11 @@
     macro(public, public_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
     macro(static, static_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
     /* \
      * Yield is a token inside function*.  Outside of a function*, it is a \
      * future reserved keyword in strict mode, but a keyword in JS1.7 even \
      * when strict.  Punt logic to parser. \
      */ \
     macro(yield, yield, TOK_YIELD, JSVERSION_DEFAULT) \
-    /* \
-     * Let is a future reserved keyword in strict mode, and a keyword in \
-     * JS1.7. \
-     */ \
-    macro(let, let, TOK_LET, JSVERSION_1_7)
+    macro(let, let, TOK_LET, JSVERSION_DEFAULT)
 
 #endif /* vm_Keywords_h */
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -661,16 +661,17 @@ const XPCWrappedNativeJSClass XPC_WN_NoH
         nullptr, // getProperty
         nullptr, // setProperty
         nullptr, // getOwnPropertyDescriptor
         nullptr, // deleteProperty
         nullptr, nullptr, // watch/unwatch
         nullptr, // getElements
         nullptr, // enumerate
         XPC_WN_JSOp_ThisValue,
+        nullptr, // funToString
     }
   }
 };
 
 
 /***************************************************************************/
 
 static bool
--- a/media/libstagefright/binding/AnnexB.cpp
+++ b/media/libstagefright/binding/AnnexB.cpp
@@ -215,42 +215,44 @@ ParseNALUnits(ByteWriter& aBw, ByteReade
 
 bool
 AnnexB::ConvertSampleToAVCC(mozilla::MediaRawData* aSample)
 {
   if (IsAVCC(aSample)) {
     return ConvertSampleTo4BytesAVCC(aSample);
   }
   if (!IsAnnexB(aSample)) {
-    // Not AnnexB, can't convert.
-    return false;
+    // Not AnnexB, nothing to convert.
+    return true;
   }
 
   mozilla::Vector<uint8_t> nalu;
   ByteWriter writer(nalu);
   ByteReader reader(aSample->Data(), aSample->Size());
 
   ParseNALUnits(writer, reader);
   nsAutoPtr<MediaRawDataWriter> samplewriter(aSample->CreateWriter());
   return samplewriter->Replace(nalu.begin(), nalu.length());
 }
 
 already_AddRefed<mozilla::MediaByteBuffer>
 AnnexB::ExtractExtraData(const mozilla::MediaRawData* aSample)
 {
   RefPtr<mozilla::MediaByteBuffer> extradata = new mozilla::MediaByteBuffer;
-  if (IsAVCC(aSample) && HasSPS(aSample->mExtraData)) {
+  if (HasSPS(aSample->mExtraData)) {
     // We already have an explicit extradata, re-use it.
     extradata = aSample->mExtraData;
     return extradata.forget();
   }
 
   if (IsAnnexB(aSample)) {
+    // We can't extract data from AnnexB.
     return extradata.forget();
   }
+
   // SPS content
   mozilla::Vector<uint8_t> sps;
   ByteWriter spsw(sps);
   int numSps = 0;
   // PPS content
   mozilla::Vector<uint8_t> pps;
   ByteWriter ppsw(pps);
   int numPps = 0;
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -600,24 +600,24 @@ public class GeckoAppShell
         SensorManager sm = (SensorManager)
             getContext().getSystemService(Context.SENSOR_SERVICE);
 
         switch(aSensortype) {
         case GeckoHalDefines.SENSOR_ORIENTATION:
             if (gOrientationSensor == null)
                 gOrientationSensor = sm.getDefaultSensor(Sensor.TYPE_ORIENTATION);
             if (gOrientationSensor != null)
-                sm.registerListener(gi.getSensorEventListener(), gOrientationSensor, SensorManager.SENSOR_DELAY_GAME);
+                sm.registerListener(gi.getSensorEventListener(), gOrientationSensor, SensorManager.SENSOR_DELAY_FASTEST);
             break;
 
         case GeckoHalDefines.SENSOR_ACCELERATION:
             if (gAccelerometerSensor == null)
                 gAccelerometerSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
             if (gAccelerometerSensor != null)
-                sm.registerListener(gi.getSensorEventListener(), gAccelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
+                sm.registerListener(gi.getSensorEventListener(), gAccelerometerSensor, SensorManager.SENSOR_DELAY_FASTEST);
             break;
 
         case GeckoHalDefines.SENSOR_PROXIMITY:
             if (gProximitySensor == null)
                 gProximitySensor = sm.getDefaultSensor(Sensor.TYPE_PROXIMITY);
             if (gProximitySensor != null)
                 sm.registerListener(gi.getSensorEventListener(), gProximitySensor, SensorManager.SENSOR_DELAY_NORMAL);
             break;
@@ -628,38 +628,38 @@ public class GeckoAppShell
             if (gLightSensor != null)
                 sm.registerListener(gi.getSensorEventListener(), gLightSensor, SensorManager.SENSOR_DELAY_NORMAL);
             break;
 
         case GeckoHalDefines.SENSOR_LINEAR_ACCELERATION:
             if (gLinearAccelerometerSensor == null)
                 gLinearAccelerometerSensor = sm.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
             if (gLinearAccelerometerSensor != null)
-                sm.registerListener(gi.getSensorEventListener(), gLinearAccelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
+                sm.registerListener(gi.getSensorEventListener(), gLinearAccelerometerSensor, SensorManager.SENSOR_DELAY_FASTEST);
             break;
 
         case GeckoHalDefines.SENSOR_GYROSCOPE:
             if (gGyroscopeSensor == null)
                 gGyroscopeSensor = sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
             if (gGyroscopeSensor != null)
-                sm.registerListener(gi.getSensorEventListener(), gGyroscopeSensor, SensorManager.SENSOR_DELAY_GAME);
+                sm.registerListener(gi.getSensorEventListener(), gGyroscopeSensor, SensorManager.SENSOR_DELAY_FASTEST);
             break;
 
         case GeckoHalDefines.SENSOR_ROTATION_VECTOR:
             if (gRotationVectorSensor == null)
                 gRotationVectorSensor = sm.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
             if (gRotationVectorSensor != null)
-                sm.registerListener(gi.getSensorEventListener(), gRotationVectorSensor, SensorManager.SENSOR_DELAY_GAME);
+                sm.registerListener(gi.getSensorEventListener(), gRotationVectorSensor, SensorManager.SENSOR_DELAY_FASTEST);
             break;
 
         case GeckoHalDefines.SENSOR_GAME_ROTATION_VECTOR:
             if (gGameRotationVectorSensor == null)
                 gGameRotationVectorSensor = sm.getDefaultSensor(15 /* Sensor.TYPE_GAME_ROTATION_VECTOR */); // API >= 18
             if (gGameRotationVectorSensor != null)
-                sm.registerListener(gi.getSensorEventListener(), gGameRotationVectorSensor, SensorManager.SENSOR_DELAY_GAME);
+                sm.registerListener(gi.getSensorEventListener(), gGameRotationVectorSensor, SensorManager.SENSOR_DELAY_FASTEST);
             break;
 
         default:
             Log.w(LOGTAG, "Error! Can't enable unknown SENSOR type " + aSensortype);
         }
     }
 
     @WrapForJNI
--- a/mobile/android/base/GeckoEditable.java
+++ b/mobile/android/base/GeckoEditable.java
@@ -849,44 +849,24 @@ final class GeckoEditable extends JNIObj
             break;
         }
         if (action.mShouldUpdate) {
             geckoUpdateGecko(false);
         }
     }
 
     private void notifyCommitComposition() {
-        // Gecko already committed its composition, and
-        // we should remove the composition on our side as well.
-        boolean wasComposing = false;
-        final Object[] spans = mText.getSpans(0, mText.length(), Object.class);
-
-        for (Object span : spans) {
-            if ((mText.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
-                mText.removeSpan(span);
-                wasComposing = true;
-            }
-        }
-
-        if (!wasComposing) {
-            return;
-        }
-
-        // Generate a text change notification if we actually cleared the composition.
-        final CharSequence text = TextUtils.stringOrSpannedString(mText);
-        geckoPostToIc(new Runnable() {
-            @Override
-            public void run() {
-                mListener.onTextChange(text, 0, text.length(), text.length());
-            }
-        });
+        // Gecko already committed its composition. However, Android keyboards
+        // have trouble dealing with us removing the composition manually on
+        // the Java side. Therefore, we keep the composition intact on the Java
+        // side. The text content should still be in-sync on both sides.
     }
 
     private void notifyCancelComposition() {
-        // Composition should have been cancelled on our side
+        // Composition should have been canceled on our side
         // through text update notifications; verify that here.
         if (DEBUG) {
             final Object[] spans = mText.getSpans(0, mText.length(), Object.class);
             for (Object span : spans) {
                 if ((mText.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
                     throw new IllegalStateException("composition not cancelled");
                 }
             }
--- a/mobile/android/base/GeckoInputConnection.java
+++ b/mobile/android/base/GeckoInputConnection.java
@@ -12,16 +12,17 @@ import java.util.concurrent.SynchronousQ
 
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.GamepadUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.util.ThreadUtils.AssertBehavior;
 
 import android.content.Context;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.SpannableString;
 import android.text.method.KeyListener;
@@ -319,16 +320,39 @@ class GeckoInputConnection
                                         Math.max(selStart, selEnd));
                 Clipboard.setText(copiedText);
                 break;
         }
         return true;
     }
 
     @Override
+    public boolean performPrivateCommand(final String action, final Bundle data) {
+        switch (action) {
+            case "process-gecko-events":
+                // Process all currently pending Gecko thread events before returning.
+
+                final Editable editable = getEditable();
+                if (editable == null) {
+                    return false;
+                }
+
+                // Removing an invalid span is essentially a no-op, but it does force the
+                // current thread to wait for the Gecko thread when we call length(), in order
+                // to process the removeSpan event. Once Gecko thread processes the removeSpan
+                // event, all previous events in the Gecko event queue would have been
+                // processed as well.
+                editable.removeSpan(null);
+                editable.length();
+                return true;
+        }
+        return false;
+    }
+
+    @Override
     public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
         if (req == null)
             return null;
 
         if ((flags & GET_EXTRACTED_TEXT_MONITOR) != 0)
             mUpdateRequest = req;
 
         Editable editable = getEditable();
--- a/mobile/android/tests/browser/robocop/components/GeckoViewComponent.java
+++ b/mobile/android/tests/browser/robocop/components/GeckoViewComponent.java
@@ -1,43 +1,45 @@
 /* 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/. */
 
 package org.mozilla.gecko.tests.components;
 
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotNull;
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertNotSame;
+import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertSame;
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertTrue;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.tests.UITestContext;
 import org.mozilla.gecko.tests.helpers.FrameworkHelper;
 import org.mozilla.gecko.tests.helpers.WaitHelper;
 
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
 import android.view.View;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 
 import com.jayway.android.robotium.solo.Condition;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
 /**
  * A class representing any interactions that take place on GeckoView.
  */
 public class GeckoViewComponent extends BaseComponent {
 
-    public interface InputConnectionTest {
-        public void test(InputConnection ic, EditorInfo info);
-    }
-
     public final TextInput mTextInput;
 
     public GeckoViewComponent(final UITestContext testContext) {
         super(testContext);
         mTextInput = new TextInput();
     }
 
     /**
@@ -54,16 +56,81 @@ public class GeckoViewComponent extends 
         mTestContext.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 FrameworkHelper.setViewContext(geckoView, newContext);
             }
         });
     }
 
+    public static abstract class InputConnectionTest {
+        protected Handler inputConnectionHandler;
+
+        /**
+         * Processes pending events on the input connection thread before returning.
+         * Must be called on the input connection thread during a test.
+         */
+        protected void processInputConnectionEvents() {
+            fAssertSame("Should be called on input connection thread",
+                    Looper.myLooper(), inputConnectionHandler.getLooper());
+
+            // Adapted from GeckoThread.pumpMessageLoop.
+            MessageQueue queue = Looper.myQueue();
+            queue.addIdleHandler(new MessageQueue.IdleHandler() {
+                @Override
+                public boolean queueIdle() {
+                    final Message msg = Message.obtain(inputConnectionHandler);
+                    msg.obj = inputConnectionHandler;
+                    inputConnectionHandler.sendMessageAtFrontOfQueue(msg);
+                    return false; // Remove this idle handler.
+                }
+            });
+
+            final Method getNextMessage;
+            try {
+                getNextMessage = queue.getClass().getDeclaredMethod("next");
+            } catch (final NoSuchMethodException e) {
+                throw new UnsupportedOperationException(e);
+            }
+            getNextMessage.setAccessible(true);
+
+            while (true) {
+                final Message msg;
+                try {
+                    msg = (Message) getNextMessage.invoke(queue);
+                } catch (final IllegalAccessException | InvocationTargetException e) {
+                    throw new UnsupportedOperationException(e);
+                }
+                if (msg.obj == inputConnectionHandler &&
+                        msg.getTarget() == inputConnectionHandler) {
+                    // Our idle signal
+                    break;
+                } else if (msg.getTarget() == null) {
+                    Looper.myLooper().quit();
+                    break;
+                }
+                msg.getTarget().dispatchMessage(msg);
+            }
+        }
+
+        /**
+         * Processes pending events on the Gecko thread before returning.
+         * Must be called on the input connection thread during a test.
+         */
+        protected void processGeckoEvents(final InputConnection ic) {
+            fAssertSame("Should be called on input connection thread",
+                    Looper.myLooper(), inputConnectionHandler.getLooper());
+
+            fAssertTrue("Should be able to process Gecko events",
+                    ic.performPrivateCommand("process-gecko-events", null));
+        }
+
+        public abstract void test(InputConnection ic, EditorInfo info);
+    }
+
     public class TextInput {
         private TextInput() {
         }
 
         private InputMethodManager getInputMethodManager() {
             final InputMethodManager imm = (InputMethodManager)
                 mActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
             fAssertNotNull("Must have an InputMethodManager", imm);
@@ -144,40 +211,42 @@ public class GeckoViewComponent extends 
                 public Object getSystemService(String name) {
                     if (Context.INPUT_METHOD_SERVICE.equals(name)) {
                         return null;
                     }
                     return super.getSystemService(name);
                 }
             });
 
-            (new InputConnectionTestRunner(test)).runOnHandler(inputConnectionHandler);
+            (new InputConnectionTestRunner(test, inputConnectionHandler)).launch();
 
             setContext(oldGeckoViewContext);
             return this;
         }
 
         private class InputConnectionTestRunner implements Runnable {
             private final InputConnectionTest mTest;
             private boolean mDone;
 
-            public InputConnectionTestRunner(final InputConnectionTest test) {
+            public InputConnectionTestRunner(final InputConnectionTest test,
+                                             final Handler handler) {
+                test.inputConnectionHandler = handler;
                 mTest = test;
             }
 
-            public synchronized void runOnHandler(final Handler inputConnectionHandler) {
+            public synchronized void launch() {
                 // Below, we are blocking the instrumentation thread to wait on the
                 // InputConnection thread. Therefore, the InputConnection thread must not be
                 // the same as the instrumentation thread to avoid a deadlock. This should
                 // always be the case and we perform a sanity check to make sure.
                 fAssertNotSame("InputConnection should not be running on instrumentation thread",
-                    Looper.myLooper(), inputConnectionHandler.getLooper());
+                    Looper.myLooper(), mTest.inputConnectionHandler.getLooper());
 
                 mDone = false;
-                inputConnectionHandler.post(this);
+                mTest.inputConnectionHandler.post(this);
                 do {
                     try {
                         wait();
                     } catch (InterruptedException e) {
                         // Ignore interrupts
                     }
                 } while (!mDone);
             }
@@ -187,16 +256,16 @@ public class GeckoViewComponent extends 
                 final EditorInfo info = new EditorInfo();
                 final InputConnection ic = getView().onCreateInputConnection(info);
                 fAssertNotNull("Must have an InputConnection", ic);
                 // Restore the IC to a clean state
                 ic.clearMetaKeyStates(-1);
                 ic.finishComposingText();
                 mTest.test(ic, info);
                 synchronized (this) {
-                    // Test finished; return from runOnHandler
+                    // Test finished; return from launch().
                     mDone = true;
                     notify();
                 }
             }
         }
     }
 }
--- a/mobile/android/tests/browser/robocop/helpers/TextInputHelper.java
+++ b/mobile/android/tests/browser/robocop/helpers/TextInputHelper.java
@@ -17,17 +17,17 @@ public final class TextInputHelper {
     private TextInputHelper() { /* To disallow instantiation. */ }
 
     private static ExtractedText getExtractedText(final InputConnection ic) {
         ExtractedTextRequest req = new ExtractedTextRequest();
         ExtractedText extract = ic.getExtractedText(req, 0);
         return extract;
     }
 
-    private static String getText(final InputConnection ic) {
+    public static String getText(final InputConnection ic) {
         return getExtractedText(ic).text.toString();
     }
 
     public static void assertText(final String message,
                                   final InputConnection ic,
                                   final String text) {
         fAssertEquals(message, text, getText(ic));
     }
--- a/mobile/android/tests/browser/robocop/robocop_input.html
+++ b/mobile/android/tests/browser/robocop/robocop_input.html
@@ -1,18 +1,25 @@
 <!DOCTYPE html>
 <html>
   <head>
     <title>Robocop Input</title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
   </head>
   <body onload="fillInput()">
-    <input id="input">
+    <p><input id="input" type="text"></p>
+    <p><input id="resetting-input" type="text"></p>
     <script>
       function fillInput() {
         // fill the input with the URL hash if provided
         var input = document.getElementById("input");
         input.value = window.location.hash.slice(1); // remove leading #
         input.focus();
+
+        // An input that resets the editor on every input by resetting the value property.
+        var resetting_input = document.getElementById("resetting-input");
+        resetting_input.addEventListener('input', function () {
+            this.value = this.value;
+        });
       }
     </script>
   </body>
 </html>
--- a/mobile/android/tests/browser/robocop/testInputConnection.java
+++ b/mobile/android/tests/browser/robocop/testInputConnection.java
@@ -5,21 +5,26 @@
 package org.mozilla.gecko.tests;
 
 import static org.mozilla.gecko.tests.helpers.AssertionHelper.fAssertEquals;
 import static org.mozilla.gecko.tests.helpers.TextInputHelper.assertSelection;
 import static org.mozilla.gecko.tests.helpers.TextInputHelper.assertSelectionAt;
 import static org.mozilla.gecko.tests.helpers.TextInputHelper.assertText;
 import static org.mozilla.gecko.tests.helpers.TextInputHelper.assertTextAndSelection;
 import static org.mozilla.gecko.tests.helpers.TextInputHelper.assertTextAndSelectionAt;
+import static org.mozilla.gecko.tests.helpers.TextInputHelper.getText;
+import static org.mozilla.gecko.tests.helpers.WaitHelper.waitFor;
 
 import org.mozilla.gecko.tests.components.GeckoViewComponent.InputConnectionTest;
 import org.mozilla.gecko.tests.helpers.GeckoHelper;
 import org.mozilla.gecko.tests.helpers.NavigationHelper;
 
+import com.jayway.android.robotium.solo.Condition;
+
+import android.view.KeyEvent;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 
 /**
  * Tests the proper operation of GeckoInputConnection
  */
 public class testInputConnection extends UITest {
 
@@ -29,20 +34,24 @@ public class testInputConnection extends
         GeckoHelper.blockForReady();
 
         final String url = mStringHelper.ROBOCOP_INPUT_URL + "#" + INITIAL_TEXT;
         NavigationHelper.enterAndLoadUrl(url);
         mToolbar.assertTitle(url);
 
         mGeckoView.mTextInput
             .waitForInputConnection()
-            .testInputConnection(new BasicInputConnectionTest());
+            // First run tests inside the normal input field.
+            .testInputConnection(new BasicInputConnectionTest())
+            // Then switch focus to the resetting input field, and run tests there.
+            .testInputConnection(new FocusNextInputFieldTest())
+            .testInputConnection(new ResettingInputConnectionTest());
     }
 
-    private class BasicInputConnectionTest implements InputConnectionTest {
+    private class BasicInputConnectionTest extends InputConnectionTest {
         @Override
         public void test(InputConnection ic, EditorInfo info) {
             // Test initial text provided by the hash in the test page URL
             assertText("Initial text matches URL hash", ic, INITIAL_TEXT);
 
             // Test setSelection
             ic.setSelection(0, 3);
             assertSelection("Can set selection to range", ic, 0, 3);
@@ -104,11 +113,94 @@ public class testInputConnection extends
             assertTextAndSelectionAt("Can set the same composing text", ic, "bar", 3);
             ic.setComposingText("bar", 1);
             assertTextAndSelectionAt("Can set the same composing text again", ic, "bar", 3);
             ic.finishComposingText();
             assertTextAndSelectionAt("Can finish composing text", ic, "bar", 3);
 
             ic.deleteSurroundingText(3, 0);
             assertTextAndSelectionAt("Can clear text", ic, "", 0);
+
+            // Bug 1209465, cannot enter ideographic space character by itself (U+3000).
+            ic.commitText("\u3000", 1);
+            assertTextAndSelectionAt("Can commit ideographic space", ic, "\u3000", 1);
+
+            ic.deleteSurroundingText(1, 0);
+            assertTextAndSelectionAt("Can clear text", ic, "", 0);
+        }
+    }
+
+    /**
+     * FocusNextInputFieldTest is used to switch focus from one input field to
+     * another on the test page by sending a tab key.
+     */
+    private class FocusNextInputFieldTest extends InputConnectionTest {
+        @Override
+        public void test(final InputConnection ic, EditorInfo info) {
+            // First clear all text.
+            ic.setSelection(0, 0);
+            assertSelectionAt("Can set selection to start", ic, 0);
+
+            ic.deleteSurroundingText(0, Integer.MAX_VALUE);
+            assertTextAndSelectionAt("Can clear all text", ic, "", 0);
+
+            // Set dummy text in currently focused input so we can check when we have switched focus.
+            final String dummyText = "dummy switch input text";
+            ic.commitText(dummyText, 1);
+            assertTextAndSelectionAt("Can commit text", ic, dummyText, dummyText.length());
+
+            final KeyEvent tabKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_TAB);
+            ic.sendKeyEvent(tabKey);
+            ic.sendKeyEvent(KeyEvent.changeAction(tabKey, KeyEvent.ACTION_UP));
+        }
+    }
+
+    /**
+     * ResettingInputConnectionTest performs tests on the resetting input in
+     * robocop_input.html. Any test that uses the normal input should be put in
+     * BasicInputConnectionTest.
+     */
+    private class ResettingInputConnectionTest extends InputConnectionTest {
+        @Override
+        public void test(final InputConnection ic, EditorInfo info) {
+            waitFor("focus change", new Condition() {
+                @Override
+                public boolean isSatisfied() {
+                    return "".equals(getText(ic));
+                }
+            });
+
+            // Bug 1199658, duplication when page has JS that resets input field value.
+
+            ic.commitText("foo", 1);
+            assertTextAndSelectionAt("Can commit text (resetting)", ic, "foo", 3);
+
+            ic.setComposingRegion(0, 3);
+            // The bug appears after composition update events are processed. We only
+            // issue these events after some back-and-forth calls between the Gecko thread
+            // and the input connection thread. Therefore, to ensure these events are
+            // issued and to ensure the bug appears, we have to process all Gecko events,
+            // then all input connection events, and finally all Gecko events again.
+            processGeckoEvents(ic);
+            processInputConnectionEvents();
+            processGeckoEvents(ic);
+            assertTextAndSelectionAt("Can set composing region (resetting)", ic, "foo", 3);
+
+            ic.setComposingText("foobar", 1);
+            processGeckoEvents(ic);
+            processInputConnectionEvents();
+            processGeckoEvents(ic);
+            assertTextAndSelectionAt("Can change composing text (resetting)", ic, "foobar", 6);
+
+            ic.setComposingText("baz", 1);
+            processGeckoEvents(ic);
+            processInputConnectionEvents();
+            processGeckoEvents(ic);
+            assertTextAndSelectionAt("Can reset composing text (resetting)", ic, "baz", 3);
+
+            ic.finishComposingText();
+            assertTextAndSelectionAt("Can finish composing text (resetting)", ic, "baz", 3);
+
+            ic.deleteSurroundingText(3, 0);
+            assertTextAndSelectionAt("Can clear text", ic, "", 0);
         }
     }
 }
--- a/modules/libjar/nsJAR.cpp
+++ b/modules/libjar/nsJAR.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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 <string.h>
 #include "nsJARInputStream.h"
 #include "nsJAR.h"
 #include "nsIFile.h"
 #include "nsIX509Cert.h"
@@ -1071,26 +1072,21 @@ nsZipReaderCache::Init(uint32_t cacheSiz
     os->AddObserver(this, "chrome-flush-caches", true);
     os->AddObserver(this, "flush-cache-entry", true);
   }
 // ignore failure of the observer registration.
 
   return NS_OK;
 }
 
-static PLDHashOperator
-DropZipReaderCache(const nsACString &aKey, nsJAR* aZip, void*)
-{
-  aZip->SetZipReaderCache(nullptr);
-  return PL_DHASH_NEXT;
-}
-
 nsZipReaderCache::~nsZipReaderCache()
 {
-  mZips.EnumerateRead(DropZipReaderCache, nullptr);
+  for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+    iter.UserData()->SetZipReaderCache(nullptr);
+  }
 
 #ifdef ZIP_CACHE_HIT_RATE
   printf("nsZipReaderCache size=%d hits=%d lookups=%d rate=%f%% flushes=%d missed %d\n",
          mCacheSize, mZipCacheHits, mZipCacheLookups,
          (float)mZipCacheHits / mZipCacheLookups,
          mZipCacheFlushes, mZipSyncMisses);
 #endif
 }
@@ -1231,46 +1227,16 @@ nsZipReaderCache::GetFd(nsIFile* zipFile
   rv = zip->GetNSPRFileDesc(aRetVal);
   // Do this to avoid possible deadlock on mLock with ReleaseZip().
   MutexAutoUnlock unlock(mLock);
   RefPtr<nsJAR> zipTemp = zip.forget();
   return rv;
 #endif /* XP_WIN */
 }
 
-static PLDHashOperator
-FindOldestZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
-{
-  nsJAR** oldestPtr = static_cast<nsJAR**>(aClosure);
-  nsJAR* oldest = *oldestPtr;
-  nsJAR* current = aZip;
-  PRIntervalTime currentReleaseTime = current->GetReleaseTime();
-  if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
-    if (oldest == nullptr ||
-        currentReleaseTime < oldest->GetReleaseTime()) {
-      *oldestPtr = current;
-    }
-  }
-  return PL_DHASH_NEXT;
-}
-
-struct ZipFindData {nsJAR* zip; bool found;};
-
-static PLDHashOperator
-FindZip(const nsACString &aKey, nsJAR* aZip, void* aClosure)
-{
-  ZipFindData* find_data = static_cast<ZipFindData*>(aClosure);
-
-  if (find_data->zip == aZip) {
-    find_data->found = true;
-    return PL_DHASH_STOP;
-  }
-  return PL_DHASH_NEXT;
-}
-
 nsresult
 nsZipReaderCache::ReleaseZip(nsJAR* zip)
 {
   nsresult rv;
   MutexAutoLock lock(mLock);
 
   // It is possible that two thread compete for this zip. The dangerous
   // case is where one thread Releases the zip and discovers that the ref
@@ -1282,32 +1248,48 @@ nsZipReaderCache::ReleaseZip(nsJAR* zip)
   // the cache and calls its Release method sending the ref count to 0 and
   // deleting the zip. However, the second thread is still blocked at the
   // start of ReleaseZip, but the 'zip' param now hold a reference to a
   // deleted zip!
   //
   // So, we are going to try safeguarding here by searching our hashtable while
   // locked here for the zip. We return fast if it is not found.
 
-  ZipFindData find_data = {zip, false};
-  mZips.EnumerateRead(FindZip, &find_data);
-  if (!find_data.found) {
+  bool found = false;
+  for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+    if (zip == iter.UserData()) {
+      found = true;
+      break;
+    }
+  }
+
+  if (!found) {
 #ifdef ZIP_CACHE_HIT_RATE
     mZipSyncMisses++;
 #endif
     return NS_OK;
   }
 
   zip->SetReleaseTime();
 
   if (mZips.Count() <= mCacheSize)
     return NS_OK;
 
+  // Find the oldest zip.
   nsJAR* oldest = nullptr;
-  mZips.EnumerateRead(FindOldestZip, &oldest);
+  for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+    nsJAR* current = iter.UserData();
+    PRIntervalTime currentReleaseTime = current->GetReleaseTime();
+    if (currentReleaseTime != PR_INTERVAL_NO_TIMEOUT) {
+      if (oldest == nullptr ||
+          currentReleaseTime < oldest->GetReleaseTime()) {
+        oldest = current;
+      }
+    }
+  }
 
   // Because of the craziness above it is possible that there is no zip that
   // needs removing.
   if (!oldest)
     return NS_OK;
 
 #ifdef ZIP_CACHE_HIT_RATE
     mZipCacheFlushes++;
@@ -1357,17 +1339,19 @@ nsZipReaderCache::Observe(nsISupports *a
                           const char16_t *aSomeData)
 {
   if (strcmp(aTopic, "memory-pressure") == 0) {
     MutexAutoLock lock(mLock);
     mZips.Enumerate(FindFlushableZip, nullptr);
   }
   else if (strcmp(aTopic, "chrome-flush-caches") == 0) {
     MutexAutoLock lock(mLock);
-    mZips.EnumerateRead(DropZipReaderCache, nullptr);
+    for (auto iter = mZips.Iter(); !iter.Done(); iter.Next()) {
+      iter.UserData()->SetZipReaderCache(nullptr);
+    }
     mZips.Clear();
   }
   else if (strcmp(aTopic, "flush-cache-entry") == 0) {
     nsCOMPtr<nsIFile> file = do_QueryInterface(aSubject);
     if (!file)
       return NS_OK;
 
     nsAutoCString uri;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -340,17 +340,17 @@ pref("media.raw.enabled", true);
 pref("media.ogg.enabled", true);
 pref("media.opus.enabled", true);
 #ifdef MOZ_WAVE
 pref("media.wave.enabled", true);
 #endif
 #ifdef MOZ_WEBM
 pref("media.webm.enabled", true);
 #if defined(MOZ_FMP4) && defined(MOZ_WMF)
-pref("media.webm.intel_decoder.enabled", false);
+pref("media.webm.intel_decoder.enabled", true);
 #endif
 #endif
 #ifdef MOZ_GSTREAMER
 pref("media.gstreamer.enabled", true);
 pref("media.gstreamer.enable-blacklist", true);
 #endif
 #ifdef MOZ_APPLEMEDIA
 pref("media.apple.mp3.enabled", true);
@@ -519,16 +519,19 @@ pref("media.video-queue.default-size", 1
 
 // The maximum number of queued frames to send to the compositor.
 // By default, send all of them.
 pref("media.video-queue.send-to-compositor-size", 9999);
 
 // Whether to disable the video stats to prevent fingerprinting
 pref("media.video_stats.enabled", true);
 
+// Weather we allow AMD switchable graphics
+pref("layers.amd-switchable-gfx.enabled", true);
+
 // Whether to use async panning and zooming
 pref("layers.async-pan-zoom.enabled", false);
 
 // Whether to enable event region building during painting
 pref("layout.event-regions.enabled", false);
 
 // APZ preferences. For documentation/details on what these prefs do, check
 // gfx/layers/apz/src/AsyncPanZoomController.cpp.
--- a/netwerk/protocol/http/InterceptedChannel.cpp
+++ b/netwerk/protocol/http/InterceptedChannel.cpp
@@ -17,16 +17,21 @@
 
 namespace mozilla {
 namespace net {
 
 extern bool
 WillRedirect(const nsHttpResponseHead * response);
 
 extern nsresult
+DoUpdateExpirationTime(nsHttpChannel* aSelf,
+                       nsICacheEntry* aCacheEntry,
+                       nsHttpResponseHead* aResponseHead,
+                       uint32_t& aExpirationTime);
+extern nsresult
 DoAddCacheEntryHeaders(nsHttpChannel *self,
                        nsICacheEntry *entry,
                        nsHttpRequestHead *requestHead,
                        nsHttpResponseHead *responseHead,
                        nsISupports *securityInfo);
 
 NS_IMPL_ISUPPORTS(InterceptedChannelBase, nsIInterceptedChannel)
 
@@ -198,16 +203,21 @@ InterceptedChannelChrome::FinishSynthesi
 
   // First we ensure the appropriate metadata is set on the synthesized cache entry
   // (i.e. the flattened response head)
 
   nsCOMPtr<nsISupports> securityInfo;
   nsresult rv = mChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  uint32_t expirationTime = 0;
+  rv = DoUpdateExpirationTime(mChannel, mSynthesizedCacheEntry,
+                              mSynthesizedResponseHead.ref(),
+                              expirationTime);
+
   rv = DoAddCacheEntryHeaders(mChannel, mSynthesizedCacheEntry,
                               mChannel->GetRequestHead(),
                               mSynthesizedResponseHead.ref(), securityInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> originalURI;
   mChannel->GetURI(getter_AddRefs(originalURI));
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -3730,62 +3730,75 @@ nsHttpChannel::AssembleCacheKey(const ch
     // Strip any trailing #ref from the URL before using it as the key
     const char *p = strchr(spec, '#');
     if (p)
         cacheKey.Append(spec, p - spec);
     else
         cacheKey.Append(spec);
 }
 
+nsresult
+DoUpdateExpirationTime(nsHttpChannel* aSelf,
+                       nsICacheEntry* aCacheEntry,
+                       nsHttpResponseHead* aResponseHead,
+                       uint32_t& aExpirationTime)
+{
+    MOZ_ASSERT(aExpirationTime == 0);
+    NS_ENSURE_TRUE(aResponseHead, NS_ERROR_FAILURE);
+
+    nsresult rv;
+
+    if (!aResponseHead->MustValidate()) {
+        uint32_t freshnessLifetime = 0;
+
+        rv = aResponseHead->ComputeFreshnessLifetime(&freshnessLifetime);
+        if (NS_FAILED(rv)) return rv;
+
+        if (freshnessLifetime > 0) {
+            uint32_t now = NowInSeconds(), currentAge = 0;
+
+            rv = aResponseHead->ComputeCurrentAge(now, aSelf->GetRequestTime(), &currentAge);
+            if (NS_FAILED(rv)) return rv;
+
+            LOG(("freshnessLifetime = %u, currentAge = %u\n",
+                freshnessLifetime, currentAge));
+
+            if (freshnessLifetime > currentAge) {
+                uint32_t timeRemaining = freshnessLifetime - currentAge;
+                // be careful... now + timeRemaining may overflow
+                if (now + timeRemaining < now)
+                    aExpirationTime = uint32_t(-1);
+                else
+                    aExpirationTime = now + timeRemaining;
+            }
+            else
+                aExpirationTime = now;
+        }
+    }
+
+    rv = aCacheEntry->SetExpirationTime(aExpirationTime);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return rv;
+}
+
 // UpdateExpirationTime is called when a new response comes in from the server.
 // It updates the stored response-time and sets the expiration time on the
 // cache entry.
 //
 // From section 13.2.4 of RFC2616, we compute expiration time as follows:
 //
 //    timeRemaining = freshnessLifetime - currentAge
 //    expirationTime = now + timeRemaining
 //
 nsresult
 nsHttpChannel::UpdateExpirationTime()
 {
-    NS_ENSURE_TRUE(mResponseHead, NS_ERROR_FAILURE);
-
-    nsresult rv;
-
     uint32_t expirationTime = 0;
-    if (!mResponseHead->MustValidate()) {
-        uint32_t freshnessLifetime = 0;
-
-        rv = mResponseHead->ComputeFreshnessLifetime(&freshnessLifetime);
-        if (NS_FAILED(rv)) return rv;
-
-        if (freshnessLifetime > 0) {
-            uint32_t now = NowInSeconds(), currentAge = 0;
-
-            rv = mResponseHead->ComputeCurrentAge(now, mRequestTime, &currentAge);
-            if (NS_FAILED(rv)) return rv;
-
-            LOG(("freshnessLifetime = %u, currentAge = %u\n",
-                freshnessLifetime, currentAge));
-
-            if (freshnessLifetime > currentAge) {
-                uint32_t timeRemaining = freshnessLifetime - currentAge;
-                // be careful... now + timeRemaining may overflow
-                if (now + timeRemaining < now)
-                    expirationTime = uint32_t(-1);
-                else
-                    expirationTime = now + timeRemaining;
-            }
-            else
-                expirationTime = now;
-        }
-    }
-
-    rv = mCacheEntry->SetExpirationTime(expirationTime);
+    nsresult rv = DoUpdateExpirationTime(this, mCacheEntry, mResponseHead, expirationTime);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (mOfflineCacheEntry) {
         rv = mOfflineCacheEntry->SetExpirationTime(expirationTime);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -183,16 +183,21 @@ public: /* internal necko use only */
         return NS_OK;
     }
 
     nsresult SetTopWindowURI(nsIURI* aTopWindowURI) {
         mTopWindowURI = aTopWindowURI;
         return NS_OK;
     }
 
+    uint32_t GetRequestTime() const
+    {
+        return mRequestTime;
+    }
+
     nsresult OpenCacheEntry(bool usingSSL);
     nsresult ContinueConnect();
 
     nsresult StartRedirectChannelToURI(nsIURI *, uint32_t);
 
     // This allows cache entry to be marked as foreign even after channel itself
     // is gone.  Needed for e10s (see HttpChannelParent::RecvDocumentChannelCleanup)
     class OfflineCacheEntryAsForeignMarker {
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -425,26 +425,29 @@ nsHttpHandler::AddStandardRequestHeaders
     nsresult rv;
 
     // Add the "User-Agent" header
     rv = request->SetHeader(nsHttp::User_Agent, UserAgent(),
                             false, nsHttpHeaderArray::eVarietyDefault);
     if (NS_FAILED(rv)) return rv;
 
     // MIME based content negotiation lives!
-    // Add the "Accept" header
+    // Add the "Accept" header.  Note, this is set as an override because the
+    // service worker expects to see it.  The other "default" headers are
+    // hidden from service worker interception.
     rv = request->SetHeader(nsHttp::Accept, mAccept,
-                            false, nsHttpHeaderArray::eVarietyDefault);
+                            false, nsHttpHeaderArray::eVarietyOverride);
     if (NS_FAILED(rv)) return rv;
 
-    // Add the "Accept-Language" header
+    // Add the "Accept-Language" header.  This header is also exposed to the
+    // service worker.
     if (!mAcceptLanguages.IsEmpty()) {
         // Add the "Accept-Language" header
         rv = request->SetHeader(nsHttp::Accept_Language, mAcceptLanguages,
-                                false, nsHttpHeaderArray::eVarietyDefault);
+                                false, nsHttpHeaderArray::eVarietyOverride);
         if (NS_FAILED(rv)) return rv;
     }
 
     // Add the "Accept-Encoding" header
     if (isSecure) {
         rv = request->SetHeader(nsHttp::Accept_Encoding, mHttpsAcceptEncodings,
                                 false, nsHttpHeaderArray::eVarietyDefault);
     } else {
--- a/python/mozbuild/mozbuild/compilation/database.py
+++ b/python/mozbuild/mozbuild/compilation/database.py
@@ -32,41 +32,67 @@ class CompileDBBackend(CommonBackend):
         self._flags = {}
 
         log_manager = LoggingManager()
         self._cmd = MozbuildObject(self.environment.topsrcdir, ConfigSettings(),
                                    log_manager, self.environment.topobjdir)
 
 
     def consume_object(self, obj):
-        if isinstance(obj, UnifiedSources):
-            # For unified sources, only include the unified source file.
-            # Note that unified sources are never used for host sources.
-            for f in obj.unified_source_mapping:
-                flags = self._get_dir_flags(obj.objdir)
-                self._build_db_line(obj, self.environment, f[0],
-                                    obj.canonical_suffix, flags, False)
-        elif isinstance(obj, Sources) or isinstance(obj, HostSources) or \
-             isinstance(obj, GeneratedSources):
+        consumed = CommonBackend.consume_object(self, obj)
+
+        if consumed:
+            return True
+
+        if isinstance(obj, Sources) or isinstance(obj, HostSources) or \
+           isinstance(obj, GeneratedSources):
             # For other sources, include each source file.
             for f in obj.files:
                 flags = self._get_dir_flags(obj.objdir)
-                self._build_db_line(obj, self.environment, f,
+                self._build_db_line(obj.objdir, self.environment, f,
                                     obj.canonical_suffix, flags,
                                     isinstance(obj, HostSources))
 
         return True
 
     def consume_finished(self):
+        CommonBackend.consume_finished(self)
+
         import json
         # Output the database (a JSON file) to objdir/compile_commands.json
         outputfile = os.path.join(self.environment.topobjdir, 'compile_commands.json')
         with self._write_file(outputfile) as jsonout:
             json.dump(self._db, jsonout, indent=0)
 
+    def _process_unified_sources(self, obj):
+        # For unified sources, only include the unified source file.
+        # Note that unified sources are never used for host sources.
+        for f in obj.unified_source_mapping:
+            flags = self._get_dir_flags(obj.objdir)
+            self._build_db_line(obj.objdir, self.environment, f[0],
+                                obj.canonical_suffix, flags, False)
+
+    def _handle_idl_manager(self, idl_manager):
+        pass
+
+    def _handle_ipdl_sources(self, ipdl_dir, sorted_ipdl_sources,
+                             unified_ipdl_cppsrcs_mapping):
+        flags = self._get_dir_flags(ipdl_dir)
+        for f in unified_ipdl_cppsrcs_mapping:
+            self._build_db_line(ipdl_dir, self.environment, f[0],
+                                '.cpp', flags, False)
+
+    def _handle_webidl_build(self, bindings_dir, unified_source_mapping,
+                             webidls, expected_build_output_files,
+                             global_define_files):
+        flags = self._get_dir_flags(bindings_dir)
+        for f in unified_source_mapping:
+            self._build_db_line(bindings_dir, self.environment, f[0],
+                                '.cpp', flags, False)
+
     def _get_dir_flags(self, directory):
         if directory in self._flags:
             return self._flags[directory]
 
         from mozbuild.util import resolve_target_to_make
 
         make_dir, make_target = resolve_target_to_make(self.environment.topobjdir, directory)
         if make_dir is None and make_target is None:
@@ -81,17 +107,17 @@ class CompileDBBackend(CommonBackend):
                 continue
 
             build_vars[name] = util.get_flags(self.environment.topobjdir, directory,
                                               build_vars, name)
 
         self._flags[directory] = build_vars
         return self._flags[directory]
 
-    def _build_db_line(self, obj, cenv, filename, canonical_suffix, flags, ishost):
+    def _build_db_line(self, objdir, cenv, filename, canonical_suffix, flags, ishost):
         # Distinguish between host and target files.
         prefix = 'HOST_' if ishost else ''
         if canonical_suffix == '.c':
             compiler = cenv.substs[prefix + 'CC']
             cflags = flags['COMPILE_CFLAGS']
             # Add the Objective-C flags if needed.
             if filename.endswith('.m'):
                 cflags += ' ' + flags['COMPILE_CMFLAGS']
@@ -107,13 +133,13 @@ class CompileDBBackend(CommonBackend):
         cmd = ' '.join([
           compiler,
           '-o', '/dev/null', '-c',
           cflags,
           filename,
         ])
 
         self._db.append({
-            'directory': obj.objdir,
+            'directory': objdir,
             'command': cmd,
             'file': filename
         })
 
--- a/testing/docker/phone-builder/bin/pre-build.sh
+++ b/testing/docker/phone-builder/bin/pre-build.sh
@@ -24,19 +24,16 @@ ccache -s
 # Figure out where the remote manifest is so we can use caches for it.
 MANIFEST=$(repository-url.py $GECKO_HEAD_REPOSITORY $GECKO_HEAD_REV b2g/config/$TARGET/sources.xml)
 tc-vcs repo-checkout $WORKSPACE/B2G https://git.mozilla.org/b2g/B2G.git $MANIFEST
 
 # Ensure symlink has been created to gecko...
 rm -f $WORKSPACE/B2G/gecko
 ln -s $WORKSPACE/gecko $WORKSPACE/B2G/gecko
 
-### Install package dependencies
-. ../builder/install-packages.sh $WORKSPACE/gecko
-
 debug_flag=""
 if [ 0$B2G_DEBUG -ne 0 ]; then
   debug_flag='--debug'
 fi
 
 if ! aws --output=text s3 ls s3://b2g-phone-backups/; then
     echo "[aws:error] Failed to connect to AWS! Are the AWS credentials ok?"
     exit 1
--- a/testing/mozharness/configs/unittests/mac_unittest.py
+++ b/testing/mozharness/configs/unittests/mac_unittest.py
@@ -45,17 +45,17 @@ config = {
         "jittest": ["jit-test/*"],
         "mozbase": ["mozbase/*"],
         "mozmill": ["mozmill/*"],
     },
     "suite_definitions": {
         "cppunittest": {
             "options": [
                 "--symbols-path=%(symbols_path)s",
-                "--xre-path=%(abs_app_dir)s"
+                "--xre-path=%(abs_res_dir)s"
             ],
             "run_filename": "runcppunittests.py",
             "testsdir": "cppunittest"
         },
         "jittest": {
             "options": [
                 "tests/bin/js",
                 "--no-slow",
--- a/testing/runcppunittests.py
+++ b/testing/runcppunittests.py
@@ -232,18 +232,16 @@ def update_mozinfo():
         dirs.add(path)
         path = os.path.split(path)[0]
     mozinfo.find_and_update_from_json(*dirs)
 
 def run_test_harness(options, args):
     update_mozinfo()
     progs = extract_unittests_from_args(args, mozinfo.info, options.manifest_path)
     options.xre_path = os.path.abspath(options.xre_path)
-    if mozinfo.isMac:
-        options.xre_path = os.path.join(os.path.dirname(options.xre_path), 'Resources')
     tester = CPPUnitTests()
     result = tester.run_tests(progs, options.xre_path, options.symbols_path)
 
     return result
 
 def main():
     parser = CPPUnittestOptions()
     mozlog.commandline.add_logging_group(parser)
--- a/testing/taskcluster/taskcluster_graph/commit_parser.py
+++ b/testing/taskcluster/taskcluster_graph/commit_parser.py
@@ -163,17 +163,19 @@ def parse_test_chunks(aliases, all_tests
             if name in seen_chunks:
                 seen_chunks[name].add(chunk)
             else:
                 seen_chunks[name] = set([chunk])
                 test['test'] = name
                 test['only_chunks'] = seen_chunks[name]
                 results.append(test)
 
-    return results;
+    # uniquify the results over the test names
+    results = {test['test']: test for test in results}.values()
+    return results
 
 def extract_tests_from_platform(test_jobs, build_platform, build_task, tests):
     '''
     Build the list of tests from the current build.
 
     :param dict test_jobs: Entire list of tests (from job_flags.yml).
     :param dict build_platform: Current build platform.
     :param str build_task: Build task path.
--- a/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml
+++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_debug.yml
@@ -17,17 +17,16 @@ task:
       build-aries-debug-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'aries'
       DEBUG: 0
       VARIANT: userdebug
       GAIA_OPTIMIZE: '1'
       B2G_SYSTEM_APPS: '1'
       MOZHARNESS_CONFIG: b2g/taskcluster-spark.py
-      TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt'
     command:
       - phone
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
--- a/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml
+++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_dogfood.yml
@@ -13,17 +13,16 @@ task:
     cache:
       build-aries-spark-dogfood: /home/worker/workspace
       build-aries-spark-dogfood-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       VARIANT: userdebug
       DOGFOOD: 1
       HARDWARE_COMPOSER: 0
       MOZHARNESS_CONFIG: b2g/taskcluster-spark-dogfood.py
-      TOOLTOOL_MANIFEST: 'b2g/config/aries-dogfood/releng-aries-dogfood.tt'
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
       groupSymbol: Aries-DogFood
       groupName: Aries Device Image
--- a/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_eng.yml
@@ -12,17 +12,16 @@ task:
 
   payload:
     cache:
       build-aries-eng: /home/worker/workspace
       build-aries-eng-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'aries'
       MOZHARNESS_CONFIG: b2g/taskcluster-spark.py
-      TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt'
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: Be
       groupSymbol: Aries
       groupName: Aries Device Image
--- a/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml
+++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_opt.yml
@@ -17,17 +17,16 @@ task:
       build-aries-opt-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'aries'
       DEBUG: 0
       VARIANT: user
       GAIA_OPTIMIZE: '1'
       B2G_SYSTEM_APPS: '1'
       MOZHARNESS_CONFIG: b2g/taskcluster-spark.py
-      TOOLTOOL_MANIFEST: 'b2g/config/aries/releng-aries.tt'
     command:
       - phone
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
--- a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml
+++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_debug.yml
@@ -11,10 +11,9 @@ task:
     - 'docker-worker:cache:build-aries-spark-ota-debug-objdir-gecko-{{project}}'
   payload:
     cache:
       build-aries-spark-ota-debug: /home/worker/workspace
       build-aries-spark-ota-debug-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       VARIANT: userdebug
       B2G_DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/aries-spark-ota/releng-aries-spark-ota.tt'
 
--- a/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml
+++ b/testing/taskcluster/tasks/builds/b2g_aries_spark_ota_opt.yml
@@ -10,9 +10,9 @@ task:
     - 'docker-worker:cache:build-aries-spark-ota-user'
     - 'docker-worker:cache:build-aries-spark-ota-user-objdir-gecko-{{project}}'
   payload:
     cache:
       build-aries-spark-ota-user: /home/worker/workspace
       build-aries-spark-ota-user-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       VARIANT: user
-      TOOLTOOL_MANIFEST: 'b2g/config/aries-spark-ota/releng-aries-spark-ota.tt'
+
--- a/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_dolphin_512_eng.yml
@@ -15,9 +15,9 @@ task:
         platform: b2g-device-image
 
   payload:
     cache:
       build-dolphin-512-eng: /home/worker/workspace
     env:
       TARGET: 'dolphin-512'
       VARIANT: eng
-      TOOLTOOL_MANIFEST: 'b2g/config/dolphin-512/releng-dolphin-512.tt'
+
--- a/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml
+++ b/testing/taskcluster/tasks/builds/b2g_dolphin_512_opt.yml
@@ -13,9 +13,8 @@ task:
       machine:
         platform: b2g-device-image
 
   payload:
     cache:
       build-dolphin-512-opt: /home/worker/workspace
     env:
       TARGET: 'dolphin-512'
-      TOOLTOOL_MANIFEST: 'b2g/config/dolphin-512/releng-dolphin-512.tt'
\ No newline at end of file
--- a/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_dolphin_eng.yml
@@ -15,9 +15,8 @@ task:
         platform: b2g-device-image
 
   payload:
     cache:
       build-dolphin-eng: /home/worker/workspace
     env:
       TARGET: 'dolphin'
       VARIANT: eng
-      TOOLTOOL_MANIFEST: 'b2g/config/dolphin/releng-dolphin.tt'
\ No newline at end of file
--- a/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml
+++ b/testing/taskcluster/tasks/builds/b2g_dolphin_opt.yml
@@ -13,9 +13,9 @@ task:
       machine:
         platform: b2g-device-image
 
   payload:
     cache:
       build-dolphin-opt: /home/worker/workspace
     env:
       TARGET: 'dolphin'
-      TOOLTOOL_MANIFEST: 'b2g/config/dolphin/releng-dolphin.tt'
+
--- a/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml
+++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_debug.yml
@@ -3,29 +3,27 @@
   variables:
     build_name: 'flame-kk'
     build_type: 'debug'
 task:
   workerType: flame-kk
   scopes:
     - 'docker-worker:cache:build-flame-kk-debug'
     - 'docker-worker:cache:build-flame-kk-debug-objdir-gecko-{{project}}'
-    - 'docker-worker:relengapi-proxy:tooltool.download.internal'
   metadata:
     name: '[TC] B2G Flame KK Debug'
 
   payload:
     cache:
       build-flame-kk-debug: /home/worker/workspace
       build-flame-kk-debug-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'flame-kk'
       DEBUG: 0
       VARIANT: userdebug
-      TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt'
     command:
       - phone
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
--- a/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_eng.yml
@@ -2,27 +2,25 @@
   from: 'tasks/builds/b2g_phone_eng_base.yml'
   variables:
     build_name: 'flame-kk-eng'
     build_type: 'opt'
 task:
   scopes:
     - 'docker-worker:cache:build-flame-kk-eng'
     - 'docker-worker:cache:build-flame-kk-eng-objdir-gecko-{{project}}'
-    - 'docker-worker:relengapi-proxy:tooltool.download.internal'
   metadata:
     name: '[TC] B2G Flame KK Eng'
 
   payload:
     cache:
       build-flame-kk-eng: /home/worker/workspace
       build-flame-kk-eng-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'flame-kk'
-      TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt'
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: Be
       groupSymbol: Flame-KK
       groupName: Flame KitKat Device Image
--- a/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml
+++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_opt.yml
@@ -3,28 +3,26 @@
   variables:
     build_name: 'flame-kk'
     build_type: 'opt'
 task:
   workerType: flame-kk
   scopes:
     - 'docker-worker:cache:build-flame-kk-opt'
     - 'docker-worker:cache:build-flame-kk-opt-objdir-gecko-{{project}}'
-    - 'docker-worker:relengapi-proxy:tooltool.download.internal'
   metadata:
     name: '[TC] B2G Flame KK Opt'
 
   payload:
     cache:
       build-flame-kk-opt: /home/worker/workspace
       build-flame-kk-opt-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'flame-kk'
       DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt'
     command:
       - phone
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
--- a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml
+++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_debug.yml
@@ -12,9 +12,8 @@ task:
 
   payload:
     cache:
       build-flame-kk-ota-debug: /home/worker/workspace
       build-flame-kk-ota-debug-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       VARIANT: userdebug
       B2G_DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/flame-kk-ota/releng-flame-kk-ota.tt'
\ No newline at end of file
--- a/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml
+++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_ota_opt.yml
@@ -11,9 +11,8 @@ task:
     - 'docker-worker:cache:build-flame-kk-ota-user-objdir-gecko-{{project}}'
 
   payload:
     cache:
       build-flame-kk-ota-user: /home/worker/workspace
       build-flame-kk-ota-user-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       VARIANT: user
-      TOOLTOOL_MANIFEST: 'b2g/config/flame-kk-ota/releng-flame-kk-ota.tt'
\ No newline at end of file
--- a/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_flame_kk_spark_eng.yml
@@ -11,18 +11,16 @@ task:
     name: '[TC] B2G Flame KK Eng (spark)'
 
   payload:
     cache:
       build-flame-kk-spark-eng: /home/worker/workspace
       build-flame-kk-spark-eng-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'flame-kk'
-      MOZHARNESS_CONFIG: b2g/taskcluster-spark.py
-      TOOLTOOL_MANIFEST: 'b2g/config/flame-kk/releng-flame-kk.tt'
   extra:
     treeherderEnv:
       - staging
     treeherder:
       symbol: Be
       groupSymbol: Flame-KK-spark
       groupName: Flame KitKat Device Image
       machine:
--- a/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_eng.yml
@@ -2,31 +2,24 @@
   from: 'tasks/builds/b2g_phone_eng_base.yml'
   variables:
     build_name: 'nexus-4-eng'
     build_type: 'opt'
 task:
   workerType: flame-kk
   scopes:
     - 'docker-worker:cache:build-nexus-4-eng'
-    - 'docker-worker:relengapi-proxy:tooltool.download.internal'
   metadata:
     name: '[TC] B2G Nexus 4 Eng'
   payload:
     cache:
       build-nexus-4-eng: /home/worker/object-folder
     env:
       TARGET: 'nexus-4'
       DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/nexus-4/releng-mako.tt'
-    command:
-      - >
-        checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/phone-builder &&
-        buildbot_step 'Build' ./build-phone.sh $HOME/workspace
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: Be
       groupSymbol: Nexus 4
       groupName: Nexus 4 Device Image
--- a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_eng.yml
@@ -3,32 +3,25 @@
   variables:
     build_name: 'nexus-4-kk-eng'
     build_type: 'opt'
 task:
   workerType: flame-kk
   scopes:
     - 'docker-worker:cache:build-nexus-4-kk-eng'
     - 'docker-worker:cache:build-nexus-4-kk-eng-objdir-gecko-{{project}}'
-    - 'docker-worker:relengapi-proxy:tooltool.download.internal'
   metadata:
     name: '[TC] B2G Nexus 4 KK Eng'
   payload:
     cache:
       build-nexus-4-kk-eng: /home/worker/workspace
       build-nexus-4-kk-eng-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'nexus-4-kk'
       DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/nexus-4-kk/releng-mako.tt'
-    command:
-      - >
-        checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/phone-builder &&
-        buildbot_step 'Build' ./build-phone.sh $HOME/workspace
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: Be
       groupSymbol: Nexus 4 KK
       groupName: Nexus 4 Kitkat Device Image
--- a/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml
+++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_kk_user.yml
@@ -3,27 +3,25 @@
   variables:
     build_name: 'nexus-4-kk-user'
     build_type: 'opt'
 task:
   workerType: flame-kk
   scopes:
     - 'docker-worker:cache:build-nexus-4-kk-user'
     - 'docker-worker:cache:build-nexus-4-kk-user-objdir-gecko-{{project}}'
-    - 'docker-worker:relengapi-proxy:tooltool.download.internal'
   metadata:
     name: '[TC] B2G Nexus 4 KK User'
   payload:
     cache:
       build-nexus-4-kk-user: /home/worker/workspace
       build-nexus-4-kk-user-objdir-gecko-{{project}}: /home/worker/objdir-gecko
     env:
       TARGET: 'nexus-4-kk'
       DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/nexus-4-kk/releng-mako.tt'
     command:
       - phone
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
--- a/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml
+++ b/testing/taskcluster/tasks/builds/b2g_nexus_4_user.yml
@@ -2,27 +2,25 @@
   from: 'tasks/builds/b2g_phone_base.yml'
   variables:
     build_name: 'nexus-4-user'
     build_type: 'opt'
 task:
   workerType: flame-kk
   scopes:
     - 'docker-worker:cache:build-nexus-4-user'
-    - 'docker-worker:relengapi-proxy:tooltool.download.internal'
   metadata:
     name: '[TC] B2G Nexus 4 User'
 
   payload:
     cache:
       build-nexus-4-user: /home/worker/object-folder
     env:
       TARGET: 'nexus-4'
       DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/nexus-4/releng-mako.tt'
     command:
       - phone
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
--- a/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml
+++ b/testing/taskcluster/tasks/builds/b2g_nexus_5l_eng.yml
@@ -10,22 +10,16 @@ task:
   metadata:
     name: '[TC] B2G Nexus 5-L Eng'
   payload:
     cache:
       build-nexus-5-l-eng: /home/worker/object-folder
     env:
       TARGET: 'nexus-5-l'
       DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/nexus-5-l/releng-nexus5.tt'
-    command:
-      - >
-        checkout-gecko workspace &&
-        cd ./workspace/gecko/testing/taskcluster/scripts/phone-builder &&
-        buildbot_step 'Build' ./build-phone.sh $HOME/workspace
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: Be
       groupSymbol: Nexus 5-L
       groupName: Nexus 5-L Device Image
--- a/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml
+++ b/testing/taskcluster/tasks/builds/b2g_nexus_5l_user.yml
@@ -11,17 +11,16 @@ task:
     name: '[TC] B2G Nexus 5-L User'
 
   payload:
     cache:
       build-nexus-5-l-user: /home/worker/object-folder
     env:
       TARGET: 'nexus-5-l'
       DEBUG: 0
-      TOOLTOOL_MANIFEST: 'b2g/config/nexus-5-l/releng-nexus5.tt'
     command:
       - phone
   extra:
     treeherderEnv:
       - production
       - staging
     treeherder:
       symbol: B
--- a/testing/taskcluster/tasks/builds/b2g_phone_base.yml
+++ b/testing/taskcluster/tasks/builds/b2g_phone_base.yml
@@ -1,19 +1,15 @@
 $inherits:
   from: 'tasks/phone_build.yml'
 task:
-  scopes:
-    - 'docker-worker:cache:tooltool-cache'
   metadata:
     description: |
       Android phones + b2g environment used in full stack testing.
   payload:
-    cache:
-      tooltool-cache: '/home/worker/tooltool-cache'
     env:
       MOZILLA_OFFICIAL: '1'
       ENABLE_DEFAULT_BOOTANIMATION: 'true'
       B2G_UPDATER: '1'
       REPO_TRACE: 1
       VARIANT: user
 
     # Emulators can take a very long time to build!
--- a/testing/taskcluster/tasks/phone_build.yml
+++ b/testing/taskcluster/tasks/phone_build.yml
@@ -49,18 +49,16 @@ task:
 
 
     env:
       # Common environment variables for checking out gecko
       GECKO_BASE_REPOSITORY: '{{base_repository}}'
       GECKO_HEAD_REPOSITORY: '{{head_repository}}'
       GECKO_HEAD_REV: '{{head_rev}}'
       GECKO_HEAD_REF: '{{head_ref}}'
-      TOOLTOOL_REPO: 'https://git.mozilla.org/build/tooltool.git'
-      TOOLTOOL_REV: 'master'
 
   extra:
     build_product: 'b2g'
     index:
       rank: {{pushlog_id}}
     treeherder:
       groupSymbol: tc
       groupName: Submitted by taskcluster
--- a/testing/taskcluster/tests/test_commit_parser.py
+++ b/testing/taskcluster/tests/test_commit_parser.py
@@ -21,65 +21,65 @@ class TestCommitParser(unittest.TestCase
 
     def test_normalize_test_list_all(self):
         self.assertEqual(
             normalize_test_list({}, ['woot'], 'all'),
             [{ 'test': 'woot' }]
         )
 
     def test_normalize_test_list_specific_tests(self):
-        self.assertEqual(
-            normalize_test_list({}, ['woot'], 'a,b,c'),
-            [{ 'test': 'a' }, { 'test': 'b' }, { 'test': 'c' }]
+        self.assertEqual(sorted(
+            normalize_test_list({}, ['woot'], 'a,b,c')),
+            sorted([{ 'test': 'a' }, { 'test': 'b' }, { 'test': 'c' }])
         )
 
     def test_normalize_test_list_specific_tests_with_whitespace(self):
-        self.assertEqual(
-            normalize_test_list({}, ['woot'], 'a, b, c'),
-            [{ 'test': 'a' }, { 'test': 'b' }, { 'test': 'c' }]
+        self.assertEqual(sorted(
+            normalize_test_list({}, ['woot'], 'a, b, c')),
+            sorted([{ 'test': 'a' }, { 'test': 'b' }, { 'test': 'c' }])
         )
 
     def test_normalize_test_list_with_alias(self):
-        self.assertEqual(
-            normalize_test_list({ "a": "alpha" }, ['woot'], 'a, b, c'),
-            [{ 'test': 'alpha' }, { 'test': 'b' }, { 'test': 'c' }]
+        self.assertEqual(sorted(
+            normalize_test_list({ "a": "alpha" }, ['woot'], 'a, b, c')),
+            sorted([{ 'test': 'alpha' }, { 'test': 'b' }, { 'test': 'c' }])
         )
 
     def test_normalize_test_list_with_alias_and_chunk(self):
         self.assertEqual(
             normalize_test_list({ "a": "alpha" }, ['woot'], 'a-1, a-3'),
             [{ 'test': 'alpha', "only_chunks": set([1, 3])  }]
         )
 
     def test_normalize_test_list_with_alias_pattern(self):
-        self.assertEqual(
+        self.assertEqual(sorted(
             normalize_test_list({ "a": '/.*oo.*/' },
                                 ['woot', 'foo', 'bar'],
-                                'a, b, c'),
-            [{ 'test': t } for t in ['woot', 'foo', 'b', 'c']]
+                                'a, b, c')),
+            sorted([{ 'test': t } for t in ['woot', 'foo', 'b', 'c']])
         )
 
     def test_normalize_test_list_with_alias_pattern_anchored(self):
-        self.assertEqual(
+        self.assertEqual(sorted(
             normalize_test_list({ "a": '/.*oo/' },
                                 ['woot', 'foo', 'bar'],
-                                'a, b, c'),
-            [{ 'test': t } for t in ['foo', 'b', 'c']]
+                                'a, b, c')),
+            sorted([{ 'test': t } for t in ['foo', 'b', 'c']])
         )
 
     def test_normalize_test_list_with_alias_pattern_list(self):
-        self.assertEqual( sorted(
+        self.assertEqual(sorted(
             normalize_test_list({ "a": ['/.*oo/', 'bar', '/bi.*/'] },
                                 ['woot', 'foo', 'bar', 'bing', 'baz'],
                                 'a, b')),
             sorted([{ 'test': t } for t in ['foo', 'bar', 'bing', 'b']])
         )
 
     def test_normalize_test_list_with_alias_pattern_list_chunks(self):
-        self.assertEqual( sorted(
+        self.assertEqual(sorted(
             normalize_test_list({ "a": ['/.*oo/', 'bar', '/bi.*/'] },
                                 ['woot', 'foo', 'bar', 'bing', 'baz'],
                                 'a-1, a-4, b')),
             sorted([{'test': 'b'}] + [
                 { 'test': t, 'only_chunks': set([1, 4])} for t in ['foo', 'bar', 'bing']])
         )
 
     def test_invalid_commit(self):
--- a/testing/tools/autotry/autotry.py
+++ b/testing/tools/autotry/autotry.py
@@ -180,17 +180,17 @@ class AutoTry(object):
         if os.path.exists(os.path.join(self.topsrcdir, '.hg')):
             self._use_git = False
         else:
             self._use_git = True
 
     @property
     def resolver(self):
         if self._resolver is None:
-            self._resolver = self.resolver_func
+            self._resolver = self._resolver_func()
         return self._resolver
 
     @property
     def config_path(self):
         return os.path.join(self.mach_context.state_dir, "autotry.ini")
 
     def load_config(self, name):
         config = ConfigParser.RawConfigParser()
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -26301,16 +26301,20 @@
         "path": "webaudio/the-audio-api/the-audiodestinationnode-interface/idl-test.html",
         "url": "/webaudio/the-audio-api/the-audiodestinationnode-interface/idl-test.html"
       },
       {
         "path": "webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueAtTime.html",
         "url": "/webaudio/the-audio-api/the-audioparam-interface/retrospective-setValueAtTime.html"
       },
       {
+        "path": "webaudio/the-audio-api/the-audionode-interface/audionode-connect-return-value.html",
+        "url": "/webaudio/the-audio-api/the-audionode-interface/audionode-connect-return-value.html"
+      },
+      {
         "path": "webaudio/the-audio-api/the-delaynode-interface/idl-test.html",
         "url": "/webaudio/the-audio-api/the-delaynode-interface/idl-test.html"
       },
       {
         "path": "webaudio/the-audio-api/the-gainnode-interface/idl-test.html",
         "url": "/webaudio/the-audio-api/the-gainnode-interface/idl-test.html"
       },
       {
--- a/testing/web-platform/meta/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html.ini
+++ b/testing/web-platform/meta/html/semantics/embedded-content/media-elements/offsets-into-the-media-resource/currentTime.html.ini
@@ -1,8 +1,5 @@
 [currentTime.html]
   type: testharness
   [setting currentTime with a media controller present]
     expected: FAIL
 
-  [setting currentTime when readyState is HAVE_NOTHING]
-    expected: FAIL
-
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-header-visibility.https.html
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/fetch-header-visibility.https.html
@@ -18,17 +18,17 @@
       })
       .then(function() {
         var frame = document.createElement('iframe');
         frame.src = scope;
         document.body.appendChild(frame);
 
         // Resolve a promise when we recieve 2 success messages
         return new Promise(function(resolve, reject) {
-          var remaining = 2;
+          var remaining = 4;
           function onMessage(e) {
             if (e.data == 'PASS') {
               remaining--;
               if (remaining == 0) {
                 resolve();
               } else {
                 return;
               }
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-header-visibility-iframe.html
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-header-visibility-iframe.html
@@ -27,9 +27,40 @@
     if (text == 'NO_UA') {
       parent.postMessage('PASS', '*');
     } else {
       parent.postMessage('noUA FAIL - expected "NO_UA", got "' + text + '"', '*');
     }
   }).catch(function(err) {
     parent.postMessage('noUA FAIL - unexpected error: ' + err, '*');
   });
+
+  var uri = document.location + '?check-accept-header';
+  var headers = new Headers();
+  headers.set('Accept', 'hmm');
+
+  // Check for custom accept header
+  fetch(uri, { headers: headers }).then(function(response) {
+    return response.text();
+  }).then(function(text) {
+    if (text === headers.get('Accept')) {
+      parent.postMessage('PASS', '*');
+    } else {
+      parent.postMessage('custom accept FAIL - expected ' + headers.get('Accept') +
+                         ' got "' + text + '"', '*');
+    }
+  }).catch(function(err) {
+    parent.postMessage('custom accept FAIL - unexpected error: ' + err, '*');
+  });
+
+  // Check for default accept header
+  fetch(uri).then(function(response) {
+    return response.text();
+  }).then(function(text) {
+    if (text === '*/*') {
+      parent.postMessage('PASS', '*');
+    } else {
+      parent.postMessage('accept FAIL - expected */* got "' + text + '"', '*');
+    }
+  }).catch(function(err) {
+    parent.postMessage('accept FAIL - unexpected error: ' + err, '*');
+  });
 </script>
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-rewrite-worker.js
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/fetch-rewrite-worker.js
@@ -58,16 +58,24 @@ self.addEventListener('fetch', function(
         // We have a user agent!
         event.respondWith(new Response(new Blob([ua])));
       } else {
         // We don't have a user-agent!
         event.respondWith(new Response(new Blob(["NO_UA"])));
       }
       return;
     }
+    if (params['check-accept-header']) {
+      var accept = event.request.headers.get('Accept');
+      if (accept) {
+        event.respondWith(new Response(accept));
+      } else {
+        event.respondWith(new Response('NO_ACCEPT'));
+      }
+    }
     event.respondWith(new Promise(function(resolve, reject) {
         var request = event.request;
         if (url) {
           request = new Request(url, init);
         }
         fetch(request).then(function(response) {
           var expectedType = params['expected_type'];
           if (expectedType && response.type !== expectedType) {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/webaudio/the-audio-api/the-audionode-interface/audionode-connect-return-value.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>Test the return value of connect when connecting two AudioNodes</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function(t) {
+  var context = new OfflineAudioContext(1, 1, 44100);
+  var g1 = context.createGain();
+  var g2 = context.createGain();
+  var rv = g1.connect(g2);
+  assert_equals(rv, g2);
+  var rv = g1.connect(g2);
+  assert_equals(rv, g2);
+}, "connect should return the node connected to.");
+</script>
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1938,23 +1938,30 @@ nsWindow::GetIMEComposition()
 
 /*
     Remove the composition but leave the text content as-is
 */
 void
 nsWindow::RemoveIMEComposition()
 {
     // Remove composition on Gecko side
-    if (!GetIMEComposition()) {
+    const RefPtr<mozilla::TextComposition> composition(GetIMEComposition());
+    if (!composition) {
         return;
     }
 
     RefPtr<nsWindow> kungFuDeathGrip(this);
-    WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommitAsIs,
-                                                  this);
+
+    // We have to use eCompositionCommit instead of eCompositionCommitAsIs
+    // because TextComposition has a workaround for eCompositionCommitAsIs
+    // that prevents compositions containing a single ideographic space
+    // character from working (see bug 1209465)..
+    WidgetCompositionEvent compositionCommitEvent(
+            true, eCompositionCommit, this);
+    compositionCommitEvent.mData = composition->String();
     InitEvent(compositionCommitEvent, nullptr);
     DispatchEvent(&compositionCommitEvent);
 }
 
 /*
  * Send dummy key events for pages that are unaware of input events,
  * to provide web compatibility for pages that depend on key events.
  * Our dummy key events have 0 as the keycode.
@@ -2385,21 +2392,18 @@ nsWindow::Natives::OnImeReplaceText(int3
         range.mRangeType = NS_TEXTRANGE_RAWINPUT;
         event.mRanges = new TextRangeArray();
         event.mRanges->AppendElement(range);
 
         window.DispatchEvent(&event);
     }
 
     // Don't end composition when composing text or composition was destroyed.
-    if (!aComposing && window.GetIMEComposition()) {
-        WidgetCompositionEvent compositionCommitEvent(
-                true, eCompositionCommitAsIs, &window);
-        window.InitEvent(compositionCommitEvent, nullptr);
-        window.DispatchEvent(&compositionCommitEvent);
+    if (!aComposing) {
+        window.RemoveIMEComposition();
     }
 
     if (mInputContext.mMayBeIMEUnaware) {
         SendIMEDummyKeyEvents();
     }
     OnImeSynchronize();
 }
 
--- a/widget/nsClipboardProxy.cpp
+++ b/widget/nsClipboardProxy.cpp
@@ -24,17 +24,17 @@ nsClipboardProxy::nsClipboardProxy()
 NS_IMETHODIMP
 nsClipboardProxy::SetData(nsITransferable *aTransferable,
                           nsIClipboardOwner *anOwner, int32_t aWhichClipboard)
 {
   ContentChild* child = ContentChild::GetSingleton();
 
   IPCDataTransfer ipcDataTransfer;
   nsContentUtils::TransferableToIPCTransferable(aTransferable, &ipcDataTransfer,
-                                                child, nullptr);
+                                                false, child, nullptr);
 
   bool isPrivateData = false;
   aTransferable->GetIsPrivateData(&isPrivateData);
   child->SendSetClipboard(ipcDataTransfer, isPrivateData, aWhichClipboard);
 
   return NS_OK;
 }
 
--- a/widget/nsDragServiceProxy.cpp
+++ b/widget/nsDragServiceProxy.cpp
@@ -31,16 +31,17 @@ nsDragServiceProxy::InvokeDragSessionImp
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument);
   NS_ENSURE_STATE(doc->GetDocShell());
   mozilla::dom::TabChild* child =
     mozilla::dom::TabChild::GetFrom(doc->GetDocShell());
   NS_ENSURE_STATE(child);
   nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers;
   nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables,
                                                   dataTransfers,
+                                                  false,
                                                   child->Manager(),
                                                   nullptr);
 
   if (mHasImage || mSelection) {
     nsIntRect dragRect;
     nsPresContext* pc;
     RefPtr<mozilla::gfx::SourceSurface> surface;
     DrawDrag(mSourceNode, aRegion, mScreenX, mScreenY,