Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 28 Oct 2015 10:52:29 +0100
changeset 269939 75cb7b35f0213a448121f15f50511099fb8c58cb
parent 269938 f1cef30cb767723c80ffbe186fd17adfca12cef6 (current diff)
parent 269907 fc706d376f0658e560a59c3dd520437b18e8c4a4 (diff)
child 269940 a5a31b8a5383c1683e73e7e470e2e95b55aff8a6
push id29595
push userkwierso@gmail.com
push dateWed, 28 Oct 2015 23:41:46 +0000
treeherdermozilla-central@769f29c92bb2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to fx-team
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
 }
 ]
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
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
 }
 ]
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c72c9278ddc2f442d193474993d36e7f2cfb08c4"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c72c9278ddc2f442d193474993d36e7f2cfb08c4"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
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-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- 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/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "a26eadc5e1133d5112b6cbc10badbb7670a1090f", 
+        "git_revision": "2e89362de40a6c9c36525d36317fa1ae8e67e143", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "a99ff14b3258f49f5902775a5e3b849f3455714a", 
+    "revision": "4a596a387a18b019fc2763b3509940d52154d72c", 
     "repo_path": "integration/gaia-central"
 }
--- 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-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- 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-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
--- 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/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="2e89362de40a6c9c36525d36317fa1ae8e67e143"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
--- 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,