Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 19 Sep 2014 14:19:13 -0400
changeset 206252 42f7ab962b3145cf40c9d4377654084b472bfe0e
parent 206177 d75c3d4ba074a041465f4af34cf13d499e0d0c99 (current diff)
parent 206251 a084c4cfd8a1ce35927526d38985ef805427c144 (diff)
child 206253 a5e8a4bff19453058c41eed9633691f4a7bff990
push id8859
push userryanvm@gmail.com
push dateFri, 19 Sep 2014 18:19:29 +0000
treeherderfx-team@42f7ab962b31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone35.0a1
Merge m-c to fx-team.
content/media/mediasource/ContainerParser.cpp
--- 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="fe92ddd450e03b38edb2d465de7897971d68ac68">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
@@ -130,14 +130,14 @@
   <project name="device/sprd" path="device/sprd" revision="0351ccd65808a2486e0fefb99674ca7a64c2c6dc"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="4e58336019b5cbcfd134caf55b142236cf986618"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="facca8d3e35431b66f85a4eb42bc6c5b24bd04da"/>
   <project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
   <project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
   <project name="kernel/common" path="kernel" revision="28aab3bd1139b6beea545f50dee8903c0634de84"/>
   <project name="platform/system/core" path="system/core" revision="53d584d4a4b4316e4de9ee5f210d662f89b44e7e"/>
-  <project name="u-boot" path="u-boot" revision="2d7a801a3e002078f885e8085fad374a564682e5"/>
+  <project name="u-boot" path="u-boot" revision="982c1fd67b89d5573317c1796cf5b0143de44e8a"/>
   <project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="6974f8e771d4d8e910357a6739ab124768891e8f"/>
-  <project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="69c8c336794666b010e34b2f501d89118513c546"/>
+  <project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="1d4697b16ed039fd1de0a23bda150523e743e2ad"/>
   <project name="vendor/sprd/partner" path="vendor/sprd/partner" revision="8649c7145972251af11b0639997edfecabfc7c2e"/>
   <project name="vendor/sprd/proprietories" path="vendor/sprd/proprietories" revision="d2466593022f7078aaaf69026adf3367c2adb7bb"/>
 </manifest>
--- 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="4d1e85908d792d9468c4da7040acd191fbb51b40">
     <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="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-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="fe92ddd450e03b38edb2d465de7897971d68ac68">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
--- 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="4d1e85908d792d9468c4da7040acd191fbb51b40">
     <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="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- 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="fe92ddd450e03b38edb2d465de7897971d68ac68">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
@@ -127,17 +127,17 @@
   <remove-project name="platform/hardware/libhardware"/>
   <remove-project name="platform/external/bluetooth/bluedroid"/>
   <!--original fetch url was git://github.com/t2m-foxfone/-->
   <remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
   <default remote="caf" revision="LNX.LA.3.5.2.1.1" sync-j="4"/>
   <!-- Flame specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
-  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="6f72b9d7a2322043fd0c4ba889ad689b084081c5"/>
+  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="960533f716ce31dfad357e87fa2f1d9ee5e94674"/>
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="893238eb1215f8fd4f3747169170cc5e1cc33969"/>
   <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="b2af89ae378a119819a9c86d9a12e573c7130459"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
   <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="c1814713bd2d07c2af0c236007badc8732a34324"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="6b58ab45e3e56c1fc20708cc39fa2264c52558df"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "98ad49da1fb006f0dcd8ed1af37382ab531ef016", 
+    "revision": "02fabec9910191bf6f99cb9879a1e6603d5ed7c3", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
     <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="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
     <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="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="4d1e85908d792d9468c4da7040acd191fbb51b40">
     <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="d170091ba1b5597b05f37fb259f6b8eb02568798"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="12d634c63ec8a41553a9f150c38260c992dc0020"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="f2f293787d4a86257c9e78a35bd3f73b31b706e2"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f3e998242fb9a857cf50f5bf3a02304a530ea617"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1464,21 +1464,26 @@ notification[value="translation"] menuli
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
   -moz-image-region: rect(0px 32px 16px 16px);
   width: 16px;
   height: 16px;
 }
 
 .ac-result-type-keyword,
 .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage) {
-  list-style-image: url(moz-icon://stock/gtk-find?size=menu);
+  list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
   width: 16px;
   height: 16px;
 }
 
+.ac-result-type-keyword[selected="true"],
+.autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage, selected) {
+  list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
+}
+
 .ac-result-type-tag,
 .autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/tag.png");
   width: 16px;
   height: 16px;
 }
 
 .ac-comment {
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -2170,20 +2170,24 @@ toolbarbutton[sdk-button="true"][cui-are
 .ac-result-type-bookmark,
 .autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
   -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 .ac-result-type-keyword,
 .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage) {
-  list-style-image: url(chrome://global/skin/icons/search-textbox.png);
-  margin: 2px;
-  width: 12px;
-  height: 12px;
+  list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
+  width: 16px;
+  height: 16px;
+}
+
+.ac-result-type-keyword[selected="true"],
+.autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage, selected) {
+  list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
 }
 
 richlistitem[selected="true"][current="true"] > .ac-title-box > .ac-result-type-bookmark,
 .autocomplete-treebody::-moz-tree-image(selected, current, bookmark, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -1390,22 +1390,32 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
 
 richlistitem[selected="true"][current="true"] > .ac-title-box > .ac-result-type-bookmark,
 .autocomplete-treebody::-moz-tree-image(selected, current, bookmark, treecolAutoCompleteImage) {
   -moz-image-region: rect(0px 48px 16px 32px);
 }
 
 .ac-result-type-keyword,
 .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage) {
-  list-style-image: url(chrome://global/skin/icons/Search-glass.png);
-  -moz-image-region: rect(0px 32px 16px 16px);
+  list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
   width: 16px;
   height: 16px;
 }
 
+%ifdef WINDOWS_AERO
+@media not all and (-moz-windows-default-theme) {
+%endif
+  .ac-result-type-keyword[selected="true"],
+  .autocomplete-treebody::-moz-tree-image(keyword, treecolAutoCompleteImage, selected) {
+    list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
+  }
+%ifdef WINDOWS_AERO
+}
+%endif
+
 .ac-result-type-tag,
 .autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
   list-style-image: url("chrome://browser/skin/places/tag.png");
   width: 16px;
   height: 16px;
 }
 
 .ac-comment {
--- a/content/base/src/DirectionalityUtils.cpp
+++ b/content/base/src/DirectionalityUtils.cpp
@@ -315,22 +315,25 @@ GetDirectionFromText(const char16_t* aTe
 
     if (NS_IS_HIGH_SURROGATE(ch) &&
         start < end &&
         NS_IS_LOW_SURROGATE(*start)) {
       ch = SURROGATE_TO_UCS4(ch, *start++);
       current++;
     }
 
-    Directionality dir = GetDirectionFromChar(ch);
-    if (dir != eDir_NotSet) {
-      if (aFirstStrong) {
-        *aFirstStrong = current;
+    // Just ignore lone surrogates
+    if (!IS_SURROGATE(ch)) {
+      Directionality dir = GetDirectionFromChar(ch);
+      if (dir != eDir_NotSet) {
+        if (aFirstStrong) {
+          *aFirstStrong = current;
+        }
+        return dir;
       }
-      return dir;
     }
   }
 
   if (aFirstStrong) {
     *aFirstStrong = UINT32_MAX;
   }
   return eDir_NotSet;
 }
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaRecorder.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "DOMMediaStream.h"
 #include "EncodedBufferCache.h"
 #include "MediaEncoder.h"
+#include "mozilla/StaticPtr.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/AudioStreamTrack.h"
 #include "mozilla/dom/BlobEvent.h"
 #include "mozilla/dom/RecordErrorEvent.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 #include "nsError.h"
 #include "nsIDocument.h"
@@ -30,16 +31,83 @@ PRLogModuleInfo* gMediaRecorderLog;
 #else
 #define LOG(type, msg)
 #endif
 
 namespace mozilla {
 
 namespace dom {
 
+/**
++ * MediaRecorderReporter measures memory being used by the Media Recorder.
++ *
++ * It is a singleton reporter and the single class object lives as long as at
++ * least one Recorder is registered. In MediaRecorder, the reporter is unregistered
++ * when it is destroyed.
++ */
+class MediaRecorderReporter MOZ_FINAL : public nsIMemoryReporter
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  MediaRecorderReporter() {};
+  static MediaRecorderReporter* UniqueInstance();
+  void InitMemoryReporter();
+
+  static void AddMediaRecorder(MediaRecorder *aRecorder)
+  {
+    GetRecorders().AppendElement(aRecorder);
+  }
+
+  static void RemoveMediaRecorder(MediaRecorder *aRecorder)
+  {
+    RecordersArray& recorders = GetRecorders();
+    recorders.RemoveElement(aRecorder);
+    if (recorders.IsEmpty()) {
+      sUniqueInstance = nullptr;
+    }
+  }
+
+  NS_METHOD
+  CollectReports(nsIHandleReportCallback* aHandleReport,
+                 nsISupports* aData, bool aAnonymize)
+  {
+    int64_t amount = 0;
+    RecordersArray& recorders = GetRecorders();
+    for (size_t i = 0; i < recorders.Length(); ++i) {
+      amount += recorders[i]->SizeOfExcludingThis(MallocSizeOf);
+    }
+
+  #define MEMREPORT(_path, _amount, _desc)                                    \
+    do {                                                                      \
+      nsresult rv;                                                            \
+      rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \
+                                   KIND_HEAP, UNITS_BYTES, _amount,           \
+                                   NS_LITERAL_CSTRING(_desc), aData);         \
+      NS_ENSURE_SUCCESS(rv, rv);                                              \
+    } while (0)
+
+    MEMREPORT("explicit/media/recorder", amount,
+              "Memory used by media recorder.");
+
+    return NS_OK;
+  }
+
+private:
+  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
+  virtual ~MediaRecorderReporter();
+  static StaticRefPtr<MediaRecorderReporter> sUniqueInstance;
+  typedef nsTArray<MediaRecorder*> RecordersArray;
+  static RecordersArray& GetRecorders()
+  {
+    return UniqueInstance()->mRecorders;
+  }
+  RecordersArray mRecorders;
+};
+NS_IMPL_ISUPPORTS(MediaRecorderReporter, nsIMemoryReporter);
+
 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaRecorder, DOMEventTargetHelper,
                                    mDOMStream, mAudioNode)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaRecorder)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentActivity)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(MediaRecorder, DOMEventTargetHelper)
@@ -327,16 +395,24 @@ public:
   bool IsEncoderError()
   {
     if (mEncoder && mEncoder->HasError()) {
       return true;
     }
     return false;
   }
 
+  size_t
+  SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+  {
+    size_t amount = mEncoder->SizeOfExcludingThis(aMallocSizeOf);
+    return amount;
+  }
+
+
 private:
   // Only DestroyRunnable is allowed to delete Session object.
   virtual ~Session()
   {
     LOG(PR_LOG_DEBUG, ("Session.~Session (%p)", this));
     CleanupStreams();
   }
   // Pull encoded media data from MediaEncoder and put into EncodedBufferCache.
@@ -676,28 +752,29 @@ MediaRecorder::Start(const Optional<int3
   if (aTimeSlice.WasPassed()) {
     if (aTimeSlice.Value() < 0) {
       aResult.Throw(NS_ERROR_INVALID_ARG);
       return;
     }
 
     timeSlice = aTimeSlice.Value();
   }
-
+  MediaRecorderReporter::AddMediaRecorder(this);
   mState = RecordingState::Recording;
   // Start a session.
   mSessions.AppendElement();
   mSessions.LastElement() = new Session(this, timeSlice);
   mSessions.LastElement()->Start();
 }
 
 void
 MediaRecorder::Stop(ErrorResult& aResult)
 {
   LOG(PR_LOG_DEBUG, ("MediaRecorder.Stop %p", this));
+  MediaRecorderReporter::RemoveMediaRecorder(this);
   if (mState == RecordingState::Inactive) {
     aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
   mState = RecordingState::Inactive;
   MOZ_ASSERT(mSessions.Length() > 0);
   mSessions.LastElement()->Stop();
 }
@@ -983,10 +1060,41 @@ MediaRecorder::GetSourcePrincipal()
   if (mDOMStream != nullptr) {
     return mDOMStream->GetPrincipal();
   }
   MOZ_ASSERT(mAudioNode != nullptr);
   nsIDocument* doc = mAudioNode->GetOwner()->GetExtantDoc();
   return doc ? doc->NodePrincipal() : nullptr;
 }
 
+size_t
+MediaRecorder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t amount = 42;
+  for (size_t i = 0; i < mSessions.Length(); ++i) {
+    amount += mSessions[i]->SizeOfExcludingThis(aMallocSizeOf);
+  }
+  return amount;
+}
+
+StaticRefPtr<MediaRecorderReporter> MediaRecorderReporter::sUniqueInstance;
+
+MediaRecorderReporter* MediaRecorderReporter::UniqueInstance()
+{
+  if (!sUniqueInstance) {
+    sUniqueInstance = new MediaRecorderReporter();
+    sUniqueInstance->InitMemoryReporter();
+  }
+  return sUniqueInstance;
+ }
+
+void MediaRecorderReporter::InitMemoryReporter()
+{
+  RegisterWeakMemoryReporter(this);
+}
+
+MediaRecorderReporter::~MediaRecorderReporter()
+{
+  UnregisterWeakMemoryReporter(this);
+}
+
 }
 }
--- a/content/media/MediaRecorder.h
+++ b/content/media/MediaRecorder.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MediaRecorder_h
 #define MediaRecorder_h
 
 #include "mozilla/dom/MediaRecorderBinding.h"
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/MemoryReporting.h"
 #include "nsIDocumentActivity.h"
 
 // Max size for allowing queue encoded data in memory
 #define MAX_ALLOW_MEMORY_BUFFER 1024000
 namespace mozilla {
 
 class AudioNodeStream;
 class DOMMediaStream;
@@ -85,16 +86,21 @@ public:
   // Construct a recorder with a Web Audio destination node as its source.
   static already_AddRefed<MediaRecorder>
   Constructor(const GlobalObject& aGlobal,
               AudioNode& aSrcAudioNode,
               uint32_t aSrcOutput,
               const MediaRecorderOptions& aInitDict,
               ErrorResult& aRv);
 
+  /*
+   * Measure the size of the buffer, and memory occupied by mAudioEncoder
+   * and mVideoEncoder
+   */
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   // EventHandler
   IMPL_EVENT_HANDLER(dataavailable)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(start)
   IMPL_EVENT_HANDLER(stop)
   IMPL_EVENT_HANDLER(warning)
 
   NS_DECL_NSIDOCUMENTACTIVITY
--- a/content/media/encoder/MediaEncoder.cpp
+++ b/content/media/encoder/MediaEncoder.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "MediaEncoder.h"
 #include "MediaDecoder.h"
 #include "nsIPrincipal.h"
 #include "nsMimeTypes.h"
 #include "prlog.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/StaticPtr.h"
 
 #include "OggWriter.h"
 #ifdef MOZ_OPUS
 #include "OpusTrackEncoder.h"
 
 #endif
 
 #ifdef MOZ_VORBIS
@@ -199,16 +200,19 @@ MediaEncoder::GetEncodedData(nsTArray<ns
       rv = CopyMetadataToMuxer(mVideoEncoder.get());
       if (NS_FAILED(rv)) {
         LOG(PR_LOG_ERROR, ("Error! Fail to Set Video Metadata"));
         break;
       }
 
       rv = mWriter->GetContainerData(aOutputBufs,
                                      ContainerWriter::GET_HEADER);
+      if (aOutputBufs != nullptr) {
+        mSizeOfBuffer = aOutputBufs->SizeOfExcludingThis(MallocSizeOf);
+      }
       if (NS_FAILED(rv)) {
        LOG(PR_LOG_ERROR,("Error! writer fail to generate header!"));
        mState = ENCODE_ERROR;
        break;
       }
       LOG(PR_LOG_DEBUG, ("Finish ENCODE_METADDATA TimeStamp = %f", GetEncodeTimeStamp()));
       mState = ENCODE_TRACK;
       break;
@@ -231,30 +235,34 @@ MediaEncoder::GetEncodedData(nsTArray<ns
       }
       LOG(PR_LOG_DEBUG, ("Video encoded TimeStamp = %f", GetEncodeTimeStamp()));
       // In audio only or video only case, let unavailable track's flag to be true.
       bool isAudioCompleted = (mAudioEncoder && mAudioEncoder->IsEncodingComplete()) || !mAudioEncoder;
       bool isVideoCompleted = (mVideoEncoder && mVideoEncoder->IsEncodingComplete()) || !mVideoEncoder;
       rv = mWriter->GetContainerData(aOutputBufs,
                                      isAudioCompleted && isVideoCompleted ?
                                      ContainerWriter::FLUSH_NEEDED : 0);
+      if (aOutputBufs != nullptr) {
+        mSizeOfBuffer = aOutputBufs->SizeOfExcludingThis(MallocSizeOf);
+      }
       if (NS_SUCCEEDED(rv)) {
         // Successfully get the copy of final container data from writer.
         reloop = false;
       }
       mState = (mWriter->IsWritingComplete()) ? ENCODE_DONE : ENCODE_TRACK;
       LOG(PR_LOG_DEBUG, ("END ENCODE_TRACK TimeStamp = %f "
           "mState = %d aComplete %d vComplete %d",
           GetEncodeTimeStamp(), mState, isAudioCompleted, isVideoCompleted));
       break;
     }
 
     case ENCODE_DONE:
     case ENCODE_ERROR:
       LOG(PR_LOG_DEBUG, ("MediaEncoder has been shutdown."));
+      mSizeOfBuffer = 0;
       mShutdown = true;
       reloop = false;
       break;
     default:
       MOZ_CRASH("Invalid encode state");
     }
   }
 }
@@ -318,9 +326,26 @@ MediaEncoder::IsWebMEncoderEnabled()
 #ifdef MOZ_OMX_ENCODER
 bool
 MediaEncoder::IsOMXEncoderEnabled()
 {
   return Preferences::GetBool("media.encoder.omx.enabled");
 }
 #endif
 
+/*
+ * SizeOfExcludingThis measures memory being used by the Media Encoder.
+ * Currently it measures the size of the Encoder buffer and memory occupied
+ * by mAudioEncoder and mVideoEncoder.
+ */
+size_t
+MediaEncoder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t amount = 0;
+  if (mState == ENCODE_TRACK) {
+    amount = mSizeOfBuffer +
+             (mAudioEncoder != nullptr ? mAudioEncoder->SizeOfExcludingThis(aMallocSizeOf) : 0) +
+             (mVideoEncoder != nullptr ? mVideoEncoder->SizeOfExcludingThis(aMallocSizeOf) : 0);
+  }
+  return amount;
 }
+
+}
--- a/content/media/encoder/MediaEncoder.h
+++ b/content/media/encoder/MediaEncoder.h
@@ -5,16 +5,18 @@
 
 #ifndef MediaEncoder_h_
 #define MediaEncoder_h_
 
 #include "mozilla/DebugOnly.h"
 #include "TrackEncoder.h"
 #include "ContainerWriter.h"
 #include "MediaStreamGraph.h"
+#include "nsIMemoryReporter.h"
+#include "mozilla/MemoryReporting.h"
 
 namespace mozilla {
 
 /**
  * MediaEncoder is the framework of encoding module, it controls and manages
  * procedures between ContainerWriter and TrackEncoder. ContainerWriter packs
  * the encoded track data with a specific container (e.g. ogg, mp4).
  * AudioTrackEncoder and VideoTrackEncoder are subclasses of TrackEncoder, and
@@ -61,16 +63,17 @@ public :
                AudioTrackEncoder* aAudioEncoder,
                VideoTrackEncoder* aVideoEncoder,
                const nsAString& aMIMEType)
     : mWriter(aWriter)
     , mAudioEncoder(aAudioEncoder)
     , mVideoEncoder(aVideoEncoder)
     , mStartTime(TimeStamp::Now())
     , mMIMEType(aMIMEType)
+    , mSizeOfBuffer(0)
     , mState(MediaEncoder::ENCODE_METADDATA)
     , mShutdown(false)
   {}
 
   ~MediaEncoder() {};
 
   /**
    * Notified by the control loop of MediaStreamGraph; aQueueMedia is the raw
@@ -135,26 +138,34 @@ public :
 #ifdef MOZ_WEBM_ENCODER
   static bool IsWebMEncoderEnabled();
 #endif
 
 #ifdef MOZ_OMX_ENCODER
   static bool IsOMXEncoderEnabled();
 #endif
 
+  MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
+  /*
+   * Measure the size of the buffer, and memory occupied by mAudioEncoder
+   * and mVideoEncoder
+   */
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
 private:
   // Get encoded data from trackEncoder and write to muxer
   nsresult WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder);
   // Get metadata from trackEncoder and copy to muxer
   nsresult CopyMetadataToMuxer(TrackEncoder* aTrackEncoder);
   nsAutoPtr<ContainerWriter> mWriter;
   nsAutoPtr<AudioTrackEncoder> mAudioEncoder;
   nsAutoPtr<VideoTrackEncoder> mVideoEncoder;
   TimeStamp mStartTime;
   nsString mMIMEType;
+  int64_t mSizeOfBuffer;
   int mState;
   bool mShutdown;
   // Get duration from create encoder, for logging purpose
   double GetEncodeTimeStamp()
   {
     TimeDuration decodeTime;
     decodeTime = TimeStamp::Now() - mStartTime;
     return decodeTime.ToMilliseconds();
--- a/content/media/encoder/TrackEncoder.cpp
+++ b/content/media/encoder/TrackEncoder.cpp
@@ -168,16 +168,22 @@ AudioTrackEncoder::DeInterleaveTrackData
 {
   for (int32_t i = 0; i < aChannels; ++i) {
     for(int32_t j = 0; j < aDuration; ++j) {
       aOutput[i * aDuration + j] = aInput[i + j * aChannels];
     }
   }
 }
 
+size_t
+AudioTrackEncoder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  return mRawSegment.SizeOfExcludingThis(aMallocSizeOf);
+}
+
 void
 VideoTrackEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
                                             TrackID aID,
                                             TrackRate aTrackRate,
                                             TrackTicks aTrackOffset,
                                             uint32_t aTrackEvents,
                                             const MediaSegment& aQueuedMedia)
 {
@@ -258,9 +264,15 @@ VideoTrackEncoder::NotifyEndOfStream()
          DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT, DEFAULT_TRACK_RATE);
   }
 
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   mEndOfStream = true;
   mReentrantMonitor.NotifyAll();
 }
 
+size_t
+VideoTrackEncoder::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  return mRawSegment.SizeOfExcludingThis(aMallocSizeOf);
 }
+
+}
--- a/content/media/encoder/TrackEncoder.h
+++ b/content/media/encoder/TrackEncoder.h
@@ -163,16 +163,20 @@ public:
                                   AudioDataValue* aOutput);
 
   /**
    * De-interleaves the aInput data and stores the result into aOutput.
    * No up-mix or down-mix operations inside.
    */
   static void DeInterleaveTrackData(AudioDataValue* aInput, int32_t aDuration,
                                     int32_t aChannels, AudioDataValue* aOutput);
+  /**
+  * Measure size of mRawSegment
+  */
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 protected:
   /**
    * Number of samples per channel in a pcm buffer. This is also the value of
    * frame size required by audio encoder, and mReentrantMonitor will be
    * notified when at least this much data has been added to mRawSegment.
    */
   virtual int GetPacketDuration() { return 0; }
@@ -236,16 +240,20 @@ public:
    * Notified by the same callbcak of MediaEncoder when it has received a track
    * change from MediaStreamGraph. Called on the MediaStreamGraph thread.
    */
   void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
                                 TrackRate aTrackRate,
                                 TrackTicks aTrackOffset,
                                 uint32_t aTrackEvents,
                                 const MediaSegment& aQueuedMedia) MOZ_OVERRIDE;
+  /**
+  * Measure size of mRawSegment
+  */
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
 protected:
   /**
    * Initialized the video encoder. In order to collect the value of width and
    * height of source frames, this initialization is delayed until we have
    * received the first valid video frame from MediaStreamGraph;
    * mReentrantMonitor will be notified after it has successfully initialized,
    * and this method is called on the MediaStramGraph thread.
copy from content/media/mediasource/SourceBuffer.cpp
copy to content/media/mediasource/ContainerParser.cpp
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/ContainerParser.cpp
@@ -1,113 +1,81 @@
 /* -*- 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 "SourceBuffer.h"
+#include "ContainerParser.h"
 
-#include "AsyncEventRunner.h"
-#include "MediaSourceUtils.h"
-#include "TrackBuffer.h"
 #include "WebMBufferedParser.h"
 #include "mozilla/Endian.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/FloatingPoint.h"
-#include "mozilla/Preferences.h"
-#include "mozilla/dom/MediaSourceBinding.h"
-#include "mozilla/dom/TimeRanges.h"
 #include "mp4_demuxer/BufferStream.h"
 #include "mp4_demuxer/MoofParser.h"
-#include "nsError.h"
-#include "nsIEventTarget.h"
-#include "nsIRunnable.h"
-#include "nsThreadUtils.h"
 #include "prlog.h"
 
-struct JSContext;
-class JSObject;
-
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaSourceLog();
 extern PRLogModuleInfo* GetMediaSourceAPILog();
 
 #define MSE_DEBUG(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
 #define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define MSE_DEBUG(...)
 #define MSE_DEBUGV(...)
 #define MSE_API(...)
 #endif
 
 namespace mozilla {
 
-class ContainerParser {
-public:
-  virtual ~ContainerParser() {}
-
-  // Return true if aData starts with an initialization segment.
-  // The base implementation exists only for debug logging and is expected
-  // to be called first from the overriding implementation.
-  virtual bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
-  {
-    MSE_DEBUG("ContainerParser(%p)::IsInitSegmentPresent aLength=%u [%x%x%x%x]",
-              this, aLength,
-              aLength > 0 ? aData[0] : 0,
-              aLength > 1 ? aData[1] : 0,
-              aLength > 2 ? aData[2] : 0,
-              aLength > 3 ? aData[3] : 0);
-    return false;
-  }
+bool
+ContainerParser::IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
+{
+MSE_DEBUG("ContainerParser(%p)::IsInitSegmentPresent aLength=%u [%x%x%x%x]",
+            this, aLength,
+            aLength > 0 ? aData[0] : 0,
+            aLength > 1 ? aData[1] : 0,
+            aLength > 2 ? aData[2] : 0,
+            aLength > 3 ? aData[3] : 0);
+return false;
+}
 
-  // Return true if aData starts with a media segment.
-  // The base implementation exists only for debug logging and is expected
-  // to be called first from the overriding implementation.
-  virtual bool IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength)
-  {
-    MSE_DEBUG("ContainerParser(%p)::IsMediaSegmentPresent aLength=%u [%x%x%x%x]",
-              this, aLength,
-              aLength > 0 ? aData[0] : 0,
-              aLength > 1 ? aData[1] : 0,
-              aLength > 2 ? aData[2] : 0,
-              aLength > 3 ? aData[3] : 0);
-    return false;
-  }
+bool
+ContainerParser::IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength)
+{
+  MSE_DEBUG("ContainerParser(%p)::IsMediaSegmentPresent aLength=%u [%x%x%x%x]",
+            this, aLength,
+            aLength > 0 ? aData[0] : 0,
+            aLength > 1 ? aData[1] : 0,
+            aLength > 2 ? aData[2] : 0,
+            aLength > 3 ? aData[3] : 0);
+  return false;
+}
 
-  // Parse aData to extract the start and end frame times from the media
-  // segment.  aData may not start on a parser sync boundary.  Return true
-  // if aStart and aEnd have been updated.
-  virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
-                                          int64_t& aStart, int64_t& aEnd)
-  {
-    return false;
-  }
+bool
+ContainerParser::ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
+                                            int64_t& aStart, int64_t& aEnd)
+{
+  return false;
+}
 
-  // Compare aLhs and rHs, considering any error that may exist in the
-  // timestamps from the format's base representation.  Return true if aLhs
-  // == aRhs within the error epsilon.
-  virtual bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
-  {
-    NS_WARNING("Using default ContainerParser::TimestampFuzzyEquals implementation");
-    return aLhs == aRhs;
-  }
+bool
+ContainerParser::TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
+{
+  NS_WARNING("Using default ContainerParser::TimestampFuzzyEquals implementation");
+  return aLhs == aRhs;
+}
 
-  virtual const nsTArray<uint8_t>& InitData()
-  {
-    MOZ_ASSERT(mInitData.Length() > 0);
-    return mInitData;
-  }
-
-  static ContainerParser* CreateForMIMEType(const nsACString& aType);
-
-protected:
-  nsTArray<uint8_t> mInitData;
-};
+const nsTArray<uint8_t>&
+ContainerParser::InitData()
+{
+  MOZ_ASSERT(mHasInitData);
+  return mInitData;
+}
 
 class WebMContainerParser : public ContainerParser {
 public:
   WebMContainerParser()
     : mParser(0), mOffset(0)
   {}
 
   static const unsigned NS_PER_USEC = 1000;
@@ -178,16 +146,17 @@ public:
       if (!mapping.IsEmpty()) {
         length = mapping[0].mSyncOffset;
         MOZ_ASSERT(length <= aLength);
       }
       MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.",
                 this, length);
 
       mInitData.ReplaceElementsAt(0, mInitData.Length(), aData, length);
+      mHasInitData = true;
     }
     mOffset += aLength;
 
     if (mapping.IsEmpty()) {
       return false;
     }
 
     // Exclude frames that we don't enough data to cover the end of.
@@ -268,16 +237,17 @@ public:
     if (initSegment) {
       const MediaByteRange& range = mParser->mInitRange;
       MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.",
                 this, range.mEnd - range.mStart);
 
       mInitData.ReplaceElementsAt(0, mInitData.Length(),
                                   aData + range.mStart,
                                   range.mEnd - range.mStart);
+      mHasInitData = true;
     }
 
     mp4_demuxer::Interval<mp4_demuxer::Microseconds> compositionRange =
       mParser->GetCompositionRange(byteRanges);
 
     mStream->DiscardBefore(mParser->mOffset);
 
     if (compositionRange.IsNull()) {
@@ -290,451 +260,22 @@ public:
     return true;
   }
 
 private:
   nsRefPtr<mp4_demuxer::BufferStream> mStream;
   nsAutoPtr<mp4_demuxer::MoofParser> mParser;
 };
 
-
 /*static*/ ContainerParser*
 ContainerParser::CreateForMIMEType(const nsACString& aType)
 {
   if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) {
     return new WebMContainerParser();
   }
 
   if (aType.LowerCaseEqualsLiteral("video/mp4") || aType.LowerCaseEqualsLiteral("audio/mp4")) {
     return new MP4ContainerParser();
   }
   return new ContainerParser();
 }
 
-namespace dom {
-
-void
-SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::SetMode(aMode=%d)", this, aMode);
-  if (!IsAttached() || mUpdating) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
-  if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
-    mMediaSource->SetReadyState(MediaSourceReadyState::Open);
-  }
-  // TODO: Test append state.
-  // TODO: If aMode is "sequence", set sequence start time.
-  mAppendMode = aMode;
-}
-
-void
-SourceBuffer::SetTimestampOffset(double aTimestampOffset, ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::SetTimestampOffset(aTimestampOffset=%f)", this, aTimestampOffset);
-  if (!IsAttached() || mUpdating) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  MOZ_ASSERT(mMediaSource->ReadyState() != MediaSourceReadyState::Closed);
-  if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
-    mMediaSource->SetReadyState(MediaSourceReadyState::Open);
-  }
-  // TODO: Test append state.
-  // TODO: If aMode is "sequence", set sequence start time.
-  mTimestampOffset = aTimestampOffset;
-}
-
-already_AddRefed<TimeRanges>
-SourceBuffer::GetBuffered(ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  if (!IsAttached()) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return nullptr;
-  }
-  nsRefPtr<TimeRanges> ranges = new TimeRanges();
-  double highestEndTime = mTrackBuffer->Buffered(ranges);
-  if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
-    // Set the end time on the last range to highestEndTime by adding a
-    // new range spanning the current end time to highestEndTime, which
-    // Normalize() will then merge with the old last range.
-    ranges->Add(ranges->GetEndTime(), highestEndTime);
-    ranges->Normalize();
-  }
-  MSE_DEBUGV("SourceBuffer(%p)::GetBuffered ranges=%s", this, DumpTimeRanges(ranges).get());
-  return ranges.forget();
-}
-
-void
-SourceBuffer::SetAppendWindowStart(double aAppendWindowStart, ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::SetAppendWindowStart(aAppendWindowStart=%f)", this, aAppendWindowStart);
-  if (!IsAttached() || mUpdating) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  if (aAppendWindowStart < 0 || aAppendWindowStart >= mAppendWindowEnd) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    return;
-  }
-  mAppendWindowStart = aAppendWindowStart;
-}
-
-void
-SourceBuffer::SetAppendWindowEnd(double aAppendWindowEnd, ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::SetAppendWindowEnd(aAppendWindowEnd=%f)", this, aAppendWindowEnd);
-  if (!IsAttached() || mUpdating) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  if (IsNaN(aAppendWindowEnd) ||
-      aAppendWindowEnd <= mAppendWindowStart) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    return;
-  }
-  mAppendWindowEnd = aAppendWindowEnd;
-}
-
-void
-SourceBuffer::AppendBuffer(const ArrayBuffer& aData, ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::AppendBuffer(ArrayBuffer)", this);
-  aData.ComputeLengthAndData();
-  AppendData(aData.Data(), aData.Length(), aRv);
-}
-
-void
-SourceBuffer::AppendBuffer(const ArrayBufferView& aData, ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::AppendBuffer(ArrayBufferView)", this);
-  aData.ComputeLengthAndData();
-  AppendData(aData.Data(), aData.Length(), aRv);
-}
-
-void
-SourceBuffer::Abort(ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::Abort()", this);
-  if (!IsAttached()) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  if (mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  if (mUpdating) {
-    // TODO: Abort segment parser loop, buffer append, and stream append loop algorithms.
-    AbortUpdating();
-  }
-  // TODO: Run reset parser algorithm.
-  mAppendWindowStart = 0;
-  mAppendWindowEnd = PositiveInfinity<double>();
-
-  MSE_DEBUG("SourceBuffer(%p)::Abort() Discarding decoder", this);
-  mTrackBuffer->DiscardDecoder();
-}
-
-void
-SourceBuffer::Remove(double aStart, double aEnd, ErrorResult& aRv)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p)::Remove(aStart=%f, aEnd=%f)", this, aStart, aEnd);
-  if (!IsAttached()) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  if (IsNaN(mMediaSource->Duration()) ||
-      aStart < 0 || aStart > mMediaSource->Duration() ||
-      aEnd <= aStart || IsNaN(aEnd)) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
-    return;
-  }
-  if (mUpdating || mMediaSource->ReadyState() != MediaSourceReadyState::Open) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return;
-  }
-  StartUpdating();
-  /// TODO: Run coded frame removal algorithm.
-
-  // Run the final step of the coded frame removal algorithm asynchronously
-  // to ensure the SourceBuffer's updating flag transition behaves as
-  // required by the spec.
-  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
-  NS_DispatchToMainThread(event);
-}
-
-void
-SourceBuffer::Detach()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_DEBUG("SourceBuffer(%p)::Detach", this);
-  if (mTrackBuffer) {
-    mTrackBuffer->Detach();
-  }
-  mTrackBuffer = nullptr;
-  mMediaSource = nullptr;
-}
-
-void
-SourceBuffer::Ended()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(IsAttached());
-  MSE_DEBUG("SourceBuffer(%p)::Ended", this);
-  mTrackBuffer->DiscardDecoder();
-}
-
-SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
-  : DOMEventTargetHelper(aMediaSource->GetParentObject())
-  , mMediaSource(aMediaSource)
-  , mType(aType)
-  , mAppendWindowStart(0)
-  , mAppendWindowEnd(PositiveInfinity<double>())
-  , mTimestampOffset(0)
-  , mAppendMode(SourceBufferAppendMode::Segments)
-  , mUpdating(false)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aMediaSource);
-  mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
-                                            75 * (1 << 20));
-  mParser = ContainerParser::CreateForMIMEType(aType);
-  mTrackBuffer = new TrackBuffer(aMediaSource->GetDecoder(), aType);
-  MSE_DEBUG("SourceBuffer(%p)::SourceBuffer: Create mParser=%p mTrackBuffer=%p",
-            this, mParser.get(), mTrackBuffer.get());
-}
-
-SourceBuffer::~SourceBuffer()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mMediaSource);
-  MSE_DEBUG("SourceBuffer(%p)::~SourceBuffer", this);
-}
-
-MediaSource*
-SourceBuffer::GetParentObject() const
-{
-  return mMediaSource;
-}
-
-JSObject*
-SourceBuffer::WrapObject(JSContext* aCx)
-{
-  return SourceBufferBinding::Wrap(aCx, this);
-}
-
-void
-SourceBuffer::DispatchSimpleEvent(const char* aName)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_API("SourceBuffer(%p) Dispatch event '%s'", this, aName);
-  DispatchTrustedEvent(NS_ConvertUTF8toUTF16(aName));
-}
-
-void
-SourceBuffer::QueueAsyncSimpleEvent(const char* aName)
-{
-  MSE_DEBUG("SourceBuffer(%p) Queuing event '%s'", this, aName);
-  nsCOMPtr<nsIRunnable> event = new AsyncEventRunner<SourceBuffer>(this, aName);
-  NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
-}
-
-void
-SourceBuffer::StartUpdating()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mUpdating);
-  mUpdating = true;
-  QueueAsyncSimpleEvent("updatestart");
-}
-
-void
-SourceBuffer::StopUpdating()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mUpdating);
-  mUpdating = false;
-  QueueAsyncSimpleEvent("update");
-  QueueAsyncSimpleEvent("updateend");
-}
-
-void
-SourceBuffer::AbortUpdating()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mUpdating);
-  mUpdating = false;
-  QueueAsyncSimpleEvent("abort");
-  QueueAsyncSimpleEvent("updateend");
-}
-
-void
-SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
-{
-  MSE_DEBUG("SourceBuffer(%p)::AppendData(aLength=%u)", this, aLength);
-  if (!PrepareAppend(aRv)) {
-    return;
-  }
-  StartUpdating();
-  // TODO: Run more of the buffer append algorithm asynchronously.
-  if (mParser->IsInitSegmentPresent(aData, aLength)) {
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: New initialization segment.", this);
-    mMediaSource->QueueInitializationEvent();
-    mTrackBuffer->DiscardDecoder();
-    if (!mTrackBuffer->NewDecoder()) {
-      aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
-      return;
-    }
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
-  } else if (!mTrackBuffer->HasInitSegment()) {
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
-    Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
-    ErrorResult dummy;
-    mMediaSource->EndOfStream(decodeError, dummy);
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-  int64_t start, end;
-  if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) {
-    int64_t lastStart, lastEnd;
-    mTrackBuffer->LastTimestamp(lastStart, lastEnd);
-    if (mParser->IsMediaSegmentPresent(aData, aLength) &&
-        !mParser->TimestampsFuzzyEqual(start, lastEnd)) {
-      MSE_DEBUG("SourceBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]",
-                this, lastStart, lastEnd, start, end);
-
-      // This data is earlier in the timeline than data we have already
-      // processed, so we must create a new decoder to handle the decoding.
-      mTrackBuffer->DiscardDecoder();
-
-      // If we've got a decoder here, it's not initialized, so we can use it
-      // rather than creating a new one.
-      if (!mTrackBuffer->NewDecoder()) {
-        aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
-        return;
-      }
-      MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
-      const nsTArray<uint8_t>& initData = mParser->InitData();
-      mTrackBuffer->AppendData(initData.Elements(), initData.Length());
-      mTrackBuffer->SetLastStartTimestamp(start);
-    }
-    mTrackBuffer->SetLastEndTimestamp(end);
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment last=[%lld, %lld] [%lld, %lld]",
-              this, lastStart, lastEnd, start, end);
-  }
-  if (!mTrackBuffer->AppendData(aData, aLength)) {
-    Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
-    ErrorResult dummy;
-    mMediaSource->EndOfStream(decodeError, dummy);
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-
-  // Schedule the state machine thread to ensure playback starts
-  // if required when data is appended.
-  mMediaSource->GetDecoder()->ScheduleStateMachineThread();
-
-  // Run the final step of the buffer append algorithm asynchronously to
-  // ensure the SourceBuffer's updating flag transition behaves as required
-  // by the spec.
-  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
-  NS_DispatchToMainThread(event);
-}
-
-bool
-SourceBuffer::PrepareAppend(ErrorResult& aRv)
-{
-  if (!IsAttached() || mUpdating) {
-    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return false;
-  }
-  if (mMediaSource->ReadyState() == MediaSourceReadyState::Ended) {
-    mMediaSource->SetReadyState(MediaSourceReadyState::Open);
-  }
-
-  // Eviction uses a byte threshold. If the buffer is greater than the
-  // number of bytes then data is evicted. The time range for this
-  // eviction is reported back to the media source. It will then
-  // evict data before that range across all SourceBuffers it knows
-  // about.
-  // TODO: Make the eviction threshold smaller for audio-only streams.
-  // TODO: Drive evictions off memory pressure notifications.
-  // TODO: Consider a global eviction threshold  rather than per TrackBuffer.
-  bool evicted = mTrackBuffer->EvictData(mEvictionThreshold);
-  if (evicted) {
-    MSE_DEBUG("SourceBuffer(%p)::AppendData Evict; current buffered start=%f",
-              this, GetBufferedStart());
-
-    // We notify that we've evicted from the time range 0 through to
-    // the current start point.
-    mMediaSource->NotifyEvicted(0.0, GetBufferedStart());
-  }
-
-  // TODO: Test buffer full flag.
-  return true;
-}
-
-double
-SourceBuffer::GetBufferedStart()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  ErrorResult dummy;
-  nsRefPtr<TimeRanges> ranges = GetBuffered(dummy);
-  return ranges->Length() > 0 ? ranges->GetStartTime() : 0;
-}
-
-double
-SourceBuffer::GetBufferedEnd()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  ErrorResult dummy;
-  nsRefPtr<TimeRanges> ranges = GetBuffered(dummy);
-  return ranges->Length() > 0 ? ranges->GetEndTime() : 0;
-}
-
-void
-SourceBuffer::Evict(double aStart, double aEnd)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MSE_DEBUG("SourceBuffer(%p)::Evict(aStart=%f, aEnd=%f)", this, aStart, aEnd);
-  double currentTime = mMediaSource->GetDecoder()->GetCurrentTime();
-  double evictTime = aEnd;
-  const double safety_threshold = 5;
-  if (currentTime + safety_threshold >= evictTime) {
-    evictTime -= safety_threshold;
-  }
-  mTrackBuffer->EvictBefore(evictTime);
-}
-
-#if defined(DEBUG)
-void
-SourceBuffer::Dump(const char* aPath)
-{
-  if (mTrackBuffer) {
-    mTrackBuffer->Dump(aPath);
-  }
-}
-#endif
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(SourceBuffer, DOMEventTargetHelper,
-                                   mMediaSource)
-
-NS_IMPL_ADDREF_INHERITED(SourceBuffer, DOMEventTargetHelper)
-NS_IMPL_RELEASE_INHERITED(SourceBuffer, DOMEventTargetHelper)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SourceBuffer)
-NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
-
-} // namespace dom
-
 } // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/media/mediasource/ContainerParser.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_CONTAINERPARSER_H_
+#define MOZILLA_CONTAINERPARSER_H_
+
+#include "nsTArray.h"
+
+namespace mozilla {
+
+class ContainerParser {
+public:
+  ContainerParser() : mHasInitData(false) {}
+  virtual ~ContainerParser() {}
+
+  // Return true if aData starts with an initialization segment.
+  // The base implementation exists only for debug logging and is expected
+  // to be called first from the overriding implementation.
+  virtual bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength);
+
+  // Return true if aData starts with a media segment.
+  // The base implementation exists only for debug logging and is expected
+  // to be called first from the overriding implementation.
+  virtual bool IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength);
+
+  // Parse aData to extract the start and end frame times from the media
+  // segment.  aData may not start on a parser sync boundary.  Return true
+  // if aStart and aEnd have been updated.
+  virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
+                                          int64_t& aStart, int64_t& aEnd);
+
+  // Compare aLhs and rHs, considering any error that may exist in the
+  // timestamps from the format's base representation.  Return true if aLhs
+  // == aRhs within the error epsilon.
+  virtual bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs);
+
+  const nsTArray<uint8_t>& InitData();
+
+  bool HasInitData()
+  {
+    return mHasInitData;
+  }
+
+  static ContainerParser* CreateForMIMEType(const nsACString& aType);
+
+protected:
+  nsTArray<uint8_t> mInitData;
+  bool mHasInitData;
+};
+
+} // namespace mozilla
+#endif /* MOZILLA_CONTAINERPARSER_H_ */
--- a/content/media/mediasource/SourceBuffer.cpp
+++ b/content/media/mediasource/SourceBuffer.cpp
@@ -4,25 +4,21 @@
  * 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 "SourceBuffer.h"
 
 #include "AsyncEventRunner.h"
 #include "MediaSourceUtils.h"
 #include "TrackBuffer.h"
-#include "WebMBufferedParser.h"
-#include "mozilla/Endian.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/MediaSourceBinding.h"
 #include "mozilla/dom/TimeRanges.h"
-#include "mp4_demuxer/BufferStream.h"
-#include "mp4_demuxer/MoofParser.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
 
 struct JSContext;
 class JSObject;
@@ -37,283 +33,16 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #else
 #define MSE_DEBUG(...)
 #define MSE_DEBUGV(...)
 #define MSE_API(...)
 #endif
 
 namespace mozilla {
 
-class ContainerParser {
-public:
-  virtual ~ContainerParser() {}
-
-  // Return true if aData starts with an initialization segment.
-  // The base implementation exists only for debug logging and is expected
-  // to be called first from the overriding implementation.
-  virtual bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
-  {
-    MSE_DEBUG("ContainerParser(%p)::IsInitSegmentPresent aLength=%u [%x%x%x%x]",
-              this, aLength,
-              aLength > 0 ? aData[0] : 0,
-              aLength > 1 ? aData[1] : 0,
-              aLength > 2 ? aData[2] : 0,
-              aLength > 3 ? aData[3] : 0);
-    return false;
-  }
-
-  // Return true if aData starts with a media segment.
-  // The base implementation exists only for debug logging and is expected
-  // to be called first from the overriding implementation.
-  virtual bool IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength)
-  {
-    MSE_DEBUG("ContainerParser(%p)::IsMediaSegmentPresent aLength=%u [%x%x%x%x]",
-              this, aLength,
-              aLength > 0 ? aData[0] : 0,
-              aLength > 1 ? aData[1] : 0,
-              aLength > 2 ? aData[2] : 0,
-              aLength > 3 ? aData[3] : 0);
-    return false;
-  }
-
-  // Parse aData to extract the start and end frame times from the media
-  // segment.  aData may not start on a parser sync boundary.  Return true
-  // if aStart and aEnd have been updated.
-  virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
-                                          int64_t& aStart, int64_t& aEnd)
-  {
-    return false;
-  }
-
-  // Compare aLhs and rHs, considering any error that may exist in the
-  // timestamps from the format's base representation.  Return true if aLhs
-  // == aRhs within the error epsilon.
-  virtual bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
-  {
-    NS_WARNING("Using default ContainerParser::TimestampFuzzyEquals implementation");
-    return aLhs == aRhs;
-  }
-
-  virtual const nsTArray<uint8_t>& InitData()
-  {
-    MOZ_ASSERT(mInitData.Length() > 0);
-    return mInitData;
-  }
-
-  static ContainerParser* CreateForMIMEType(const nsACString& aType);
-
-protected:
-  nsTArray<uint8_t> mInitData;
-};
-
-class WebMContainerParser : public ContainerParser {
-public:
-  WebMContainerParser()
-    : mParser(0), mOffset(0)
-  {}
-
-  static const unsigned NS_PER_USEC = 1000;
-
-  bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
-  {
-    ContainerParser::IsInitSegmentPresent(aData, aLength);
-    // XXX: This is overly primitive, needs to collect data as it's appended
-    // to the SB and handle, rather than assuming everything is present in a
-    // single aData segment.
-    // 0x1a45dfa3 // EBML
-    // ...
-    // DocType == "webm"
-    // ...
-    // 0x18538067 // Segment (must be "unknown" size)
-    // 0x1549a966 // -> Segment Info
-    // 0x1654ae6b // -> One or more Tracks
-    if (aLength >= 4 &&
-        aData[0] == 0x1a && aData[1] == 0x45 && aData[2] == 0xdf && aData[3] == 0xa3) {
-      return true;
-    }
-    return false;
-  }
-
-  bool IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength)
-  {
-    ContainerParser::IsMediaSegmentPresent(aData, aLength);
-    // XXX: This is overly primitive, needs to collect data as it's appended
-    // to the SB and handle, rather than assuming everything is present in a
-    // single aData segment.
-    // 0x1a45dfa3 // EBML
-    // ...
-    // DocType == "webm"
-    // ...
-    // 0x18538067 // Segment (must be "unknown" size)
-    // 0x1549a966 // -> Segment Info
-    // 0x1654ae6b // -> One or more Tracks
-    if (aLength >= 4 &&
-        aData[0] == 0x1f && aData[1] == 0x43 && aData[2] == 0xb6 && aData[3] == 0x75) {
-      return true;
-    }
-    return false;
-  }
-
-  bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
-                                  int64_t& aStart, int64_t& aEnd)
-  {
-    bool initSegment = IsInitSegmentPresent(aData, aLength);
-    if (initSegment) {
-      mOffset = 0;
-      mParser = WebMBufferedParser(0);
-      mOverlappedMapping.Clear();
-    }
-
-    // XXX if it only adds new mappings, overlapped but not available
-    // (e.g. overlap < 0) frames are "lost" from the reported mappings here.
-    nsTArray<WebMTimeDataOffset> mapping;
-    mapping.AppendElements(mOverlappedMapping);
-    mOverlappedMapping.Clear();
-    ReentrantMonitor dummy("dummy");
-    mParser.Append(aData, aLength, mapping, dummy);
-
-    // XXX This is a bit of a hack.  Assume if there are no timecodes
-    // present and it's an init segment that it's _just_ an init segment.
-    // We should be more precise.
-    if (initSegment) {
-      uint32_t length = aLength;
-      if (!mapping.IsEmpty()) {
-        length = mapping[0].mSyncOffset;
-        MOZ_ASSERT(length <= aLength);
-      }
-      MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.",
-                this, length);
-
-      mInitData.ReplaceElementsAt(0, mInitData.Length(), aData, length);
-    }
-    mOffset += aLength;
-
-    if (mapping.IsEmpty()) {
-      return false;
-    }
-
-    // Exclude frames that we don't enough data to cover the end of.
-    uint32_t endIdx = mapping.Length() - 1;
-    while (mOffset < mapping[endIdx].mEndOffset && endIdx > 0) {
-      endIdx -= 1;
-    }
-
-    if (endIdx == 0) {
-      return false;
-    }
-
-    uint64_t frameDuration = mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode;
-    aStart = mapping[0].mTimecode / NS_PER_USEC;
-    aEnd = (mapping[endIdx].mTimecode + frameDuration) / NS_PER_USEC;
-
-    MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld] [fso=%lld, leo=%lld, l=%u endIdx=%u]",
-              this, aStart, aEnd, mapping[0].mSyncOffset, mapping[endIdx].mEndOffset, mapping.Length(), endIdx);
-
-    mapping.RemoveElementsAt(0, endIdx + 1);
-    mOverlappedMapping.AppendElements(mapping);
-
-    return true;
-  }
-
-  bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs)
-  {
-    int64_t error = mParser.GetTimecodeScale() / NS_PER_USEC;
-    return llabs(aLhs - aRhs) <= error * 2;
-  }
-
-private:
-  WebMBufferedParser mParser;
-  nsTArray<WebMTimeDataOffset> mOverlappedMapping;
-  int64_t mOffset;
-};
-
-class MP4ContainerParser : public ContainerParser {
-public:
-  MP4ContainerParser() {}
-
-  bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
-  {
-    ContainerParser::IsInitSegmentPresent(aData, aLength);
-    // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
-    // file is the 'ftyp' atom followed by a file type. We just check for a
-    // vaguely valid 'ftyp' atom.
-
-    if (aLength < 8) {
-      return false;
-    }
-
-    uint32_t chunk_size = BigEndian::readUint32(aData);
-    if (chunk_size < 8) {
-      return false;
-    }
-
-    return aData[4] == 'f' && aData[5] == 't' && aData[6] == 'y' &&
-           aData[7] == 'p';
-  }
-
-  bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
-                                  int64_t& aStart, int64_t& aEnd)
-  {
-    bool initSegment = IsInitSegmentPresent(aData, aLength);
-    if (initSegment) {
-      mStream = new mp4_demuxer::BufferStream();
-      mParser = new mp4_demuxer::MoofParser(mStream, 0);
-    } else if (!mStream || !mParser) {
-      return false;
-    }
-
-    mStream->AppendBytes(aData, aLength);
-    nsTArray<MediaByteRange> byteRanges;
-    byteRanges.AppendElement(mStream->GetByteRange());
-    mParser->RebuildFragmentedIndex(byteRanges);
-
-    if (initSegment) {
-      const MediaByteRange& range = mParser->mInitRange;
-      MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: Stashed init of %u bytes.",
-                this, range.mEnd - range.mStart);
-
-      mInitData.ReplaceElementsAt(0, mInitData.Length(),
-                                  aData + range.mStart,
-                                  range.mEnd - range.mStart);
-    }
-
-    mp4_demuxer::Interval<mp4_demuxer::Microseconds> compositionRange =
-      mParser->GetCompositionRange(byteRanges);
-
-    mStream->DiscardBefore(mParser->mOffset);
-
-    if (compositionRange.IsNull()) {
-      return false;
-    }
-    aStart = compositionRange.start;
-    aEnd = compositionRange.end;
-    MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld]",
-              this, aStart, aEnd);
-    return true;
-  }
-
-private:
-  nsRefPtr<mp4_demuxer::BufferStream> mStream;
-  nsAutoPtr<mp4_demuxer::MoofParser> mParser;
-};
-
-
-/*static*/ ContainerParser*
-ContainerParser::CreateForMIMEType(const nsACString& aType)
-{
-  if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) {
-    return new WebMContainerParser();
-  }
-
-  if (aType.LowerCaseEqualsLiteral("video/mp4") || aType.LowerCaseEqualsLiteral("audio/mp4")) {
-    return new MP4ContainerParser();
-  }
-  return new ContainerParser();
-}
-
 namespace dom {
 
 void
 SourceBuffer::SetMode(SourceBufferAppendMode aMode, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_API("SourceBuffer(%p)::SetMode(aMode=%d)", this, aMode);
   if (!IsAttached() || mUpdating) {
@@ -492,31 +221,29 @@ SourceBuffer::Ended()
   MOZ_ASSERT(IsAttached());
   MSE_DEBUG("SourceBuffer(%p)::Ended", this);
   mTrackBuffer->DiscardDecoder();
 }
 
 SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
-  , mType(aType)
   , mAppendWindowStart(0)
   , mAppendWindowEnd(PositiveInfinity<double>())
   , mTimestampOffset(0)
   , mAppendMode(SourceBufferAppendMode::Segments)
   , mUpdating(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aMediaSource);
   mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
                                             75 * (1 << 20));
-  mParser = ContainerParser::CreateForMIMEType(aType);
   mTrackBuffer = new TrackBuffer(aMediaSource->GetDecoder(), aType);
-  MSE_DEBUG("SourceBuffer(%p)::SourceBuffer: Create mParser=%p mTrackBuffer=%p",
-            this, mParser.get(), mTrackBuffer.get());
+  MSE_DEBUG("SourceBuffer(%p)::SourceBuffer: Create mTrackBuffer=%p",
+            this, mTrackBuffer.get());
 }
 
 SourceBuffer::~SourceBuffer()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mMediaSource);
   MSE_DEBUG("SourceBuffer(%p)::~SourceBuffer", this);
 }
@@ -581,73 +308,28 @@ SourceBuffer::AbortUpdating()
 void
 SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv)
 {
   MSE_DEBUG("SourceBuffer(%p)::AppendData(aLength=%u)", this, aLength);
   if (!PrepareAppend(aRv)) {
     return;
   }
   StartUpdating();
-  // TODO: Run more of the buffer append algorithm asynchronously.
-  if (mParser->IsInitSegmentPresent(aData, aLength)) {
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: New initialization segment.", this);
-    mMediaSource->QueueInitializationEvent();
-    mTrackBuffer->DiscardDecoder();
-    if (!mTrackBuffer->NewDecoder()) {
-      aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
-      return;
-    }
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
-  } else if (!mTrackBuffer->HasInitSegment()) {
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
-    Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
-    ErrorResult dummy;
-    mMediaSource->EndOfStream(decodeError, dummy);
-    aRv.Throw(NS_ERROR_FAILURE);
-    return;
-  }
-  int64_t start, end;
-  if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) {
-    int64_t lastStart, lastEnd;
-    mTrackBuffer->LastTimestamp(lastStart, lastEnd);
-    if (mParser->IsMediaSegmentPresent(aData, aLength) &&
-        !mParser->TimestampsFuzzyEqual(start, lastEnd)) {
-      MSE_DEBUG("SourceBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]",
-                this, lastStart, lastEnd, start, end);
 
-      // This data is earlier in the timeline than data we have already
-      // processed, so we must create a new decoder to handle the decoding.
-      mTrackBuffer->DiscardDecoder();
-
-      // If we've got a decoder here, it's not initialized, so we can use it
-      // rather than creating a new one.
-      if (!mTrackBuffer->NewDecoder()) {
-        aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
-        return;
-      }
-      MSE_DEBUG("SourceBuffer(%p)::AppendData: Decoder marked as initialized.", this);
-      const nsTArray<uint8_t>& initData = mParser->InitData();
-      mTrackBuffer->AppendData(initData.Elements(), initData.Length());
-      mTrackBuffer->SetLastStartTimestamp(start);
-    }
-    mTrackBuffer->SetLastEndTimestamp(end);
-    MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment last=[%lld, %lld] [%lld, %lld]",
-              this, lastStart, lastEnd, start, end);
-  }
   if (!mTrackBuffer->AppendData(aData, aLength)) {
     Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
     ErrorResult dummy;
     mMediaSource->EndOfStream(decodeError, dummy);
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
-  // Schedule the state machine thread to ensure playback starts
-  // if required when data is appended.
-  mMediaSource->GetDecoder()->ScheduleStateMachineThread();
+  if (mTrackBuffer->HasInitSegment()) {
+    mMediaSource->QueueInitializationEvent();
+  }
 
   // Run the final step of the buffer append algorithm asynchronously to
   // ensure the SourceBuffer's updating flag transition behaves as required
   // by the spec.
   nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
   NS_DispatchToMainThread(event);
 }
 
--- a/content/media/mediasource/SourceBuffer.h
+++ b/content/media/mediasource/SourceBuffer.h
@@ -23,17 +23,16 @@
 #include "nsString.h"
 #include "nscore.h"
 
 class JSObject;
 struct JSContext;
 
 namespace mozilla {
 
-class ContainerParser;
 class ErrorResult;
 class TrackBuffer;
 template <typename T> class AsyncEventRunner;
 
 namespace dom {
 
 class TimeRanges;
 
@@ -115,43 +114,32 @@ public:
 
 private:
   ~SourceBuffer();
 
   friend class AsyncEventRunner<SourceBuffer>;
   void DispatchSimpleEvent(const char* aName);
   void QueueAsyncSimpleEvent(const char* aName);
 
-  // Create a new decoder for mType, and store the result in mDecoder.
-  // Returns true if mDecoder was set.
-  bool InitNewDecoder();
-
-  // Set mDecoder to null and reset mDecoderInitialized.
-  void DiscardDecoder();
-
   // Update mUpdating and fire the appropriate events.
   void StartUpdating();
   void StopUpdating();
   void AbortUpdating();
 
   // Shared implementation of AppendBuffer overloads.
   void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
 
   // Implements the "Prepare Append Algorithm".  Returns true if the append
   // may continue, or false (with aRv set) on error.
   bool PrepareAppend(ErrorResult& aRv);
 
   nsRefPtr<MediaSource> mMediaSource;
 
-  const nsCString mType;
-
   uint32_t mEvictionThreshold;
 
-  nsAutoPtr<ContainerParser> mParser;
-
   nsRefPtr<TrackBuffer> mTrackBuffer;
 
   double mAppendWindowStart;
   double mAppendWindowEnd;
 
   double mTimestampOffset;
 
   SourceBufferAppendMode mAppendMode;
--- a/content/media/mediasource/TrackBuffer.cpp
+++ b/content/media/mediasource/TrackBuffer.cpp
@@ -1,37 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TrackBuffer.h"
 
+#include "ContainerParser.h"
 #include "MediaSourceDecoder.h"
 #include "SharedThreadPool.h"
 #include "MediaTaskQueue.h"
 #include "SourceBufferDecoder.h"
 #include "SourceBufferResource.h"
 #include "VideoUtils.h"
-#include "mozilla/FloatingPoint.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsError.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
 
-#if defined(DEBUG)
-#include <sys/stat.h>
-#include <sys/types.h>
-#endif
-
-struct JSContext;
-class JSObject;
-
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaSourceLog();
 extern PRLogModuleInfo* GetMediaSourceAPILog();
 
 #define MSE_DEBUG(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
 #define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
@@ -42,19 +34,19 @@ extern PRLogModuleInfo* GetMediaSourceAP
 
 namespace mozilla {
 
 TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType)
   : mParentDecoder(aParentDecoder)
   , mType(aType)
   , mLastStartTimestamp(0)
   , mLastEndTimestamp(0)
-  , mHasInit(false)
 {
   MOZ_COUNT_CTOR(TrackBuffer);
+  mParser = ContainerParser::CreateForMIMEType(aType);
   mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   aParentDecoder->AddTrackBuffer(this);
 }
 
 TrackBuffer::~TrackBuffer()
 {
   MOZ_COUNT_DTOR(TrackBuffer);
 }
@@ -99,16 +91,63 @@ TrackBuffer::Shutdown()
   MOZ_ASSERT(mDecoders.IsEmpty());
   mParentDecoder = nullptr;
 }
 
 bool
 TrackBuffer::AppendData(const uint8_t* aData, uint32_t aLength)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  // TODO: Run more of the buffer append algorithm asynchronously.
+  if (mParser->IsInitSegmentPresent(aData, aLength)) {
+    MSE_DEBUG("TrackBuffer(%p)::AppendData: New initialization segment.", this);
+    if (!NewDecoder()) {
+      return false;
+    }
+  } else if (!mParser->HasInitData()) {
+    MSE_DEBUG("TrackBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
+    return false;
+  }
+
+  int64_t start, end;
+  if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) {
+    if (mParser->IsMediaSegmentPresent(aData, aLength) &&
+        !mParser->TimestampsFuzzyEqual(start, mLastEndTimestamp)) {
+      MSE_DEBUG("TrackBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]",
+                this, mLastStartTimestamp, mLastEndTimestamp, start, end);
+
+      // This data is earlier in the timeline than data we have already
+      // processed, so we must create a new decoder to handle the decoding.
+      if (!NewDecoder()) {
+        return false;
+      }
+      MSE_DEBUG("TrackBuffer(%p)::AppendData: Decoder marked as initialized.", this);
+      const nsTArray<uint8_t>& initData = mParser->InitData();
+      AppendDataToCurrentResource(initData.Elements(), initData.Length());
+      mLastStartTimestamp = start;
+    }
+    mLastEndTimestamp = end;
+    MSE_DEBUG("TrackBuffer(%p)::AppendData: Segment last=[%lld, %lld] [%lld, %lld]",
+              this, mLastStartTimestamp, mLastEndTimestamp, start, end);
+  }
+
+  if (!AppendDataToCurrentResource(aData, aLength)) {
+    return false;
+  }
+
+  // Schedule the state machine thread to ensure playback starts if required
+  // when data is appended.
+  mParentDecoder->ScheduleStateMachineThread();
+  return true;
+}
+
+bool
+TrackBuffer::AppendDataToCurrentResource(const uint8_t* aData, uint32_t aLength)
+{
+  MOZ_ASSERT(NS_IsMainThread());
   if (!mCurrentDecoder) {
     return false;
   }
 
   SourceBufferResource* resource = mCurrentDecoder->GetResource();
   int64_t appendOffset = resource->GetLength();
   resource->AppendData(aData, aLength);
   // XXX: For future reference: NDA call must run on the main thread.
@@ -174,29 +213,30 @@ TrackBuffer::Buffered(dom::TimeRanges* a
 
   return highestEndTime;
 }
 
 bool
 TrackBuffer::NewDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(!mCurrentDecoder && mParentDecoder);
+  MOZ_ASSERT(mParentDecoder);
+
+  DiscardDecoder();
 
   nsRefPtr<SourceBufferDecoder> decoder = mParentDecoder->CreateSubDecoder(mType);
   if (!decoder) {
     return false;
   }
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   mCurrentDecoder = decoder;
   mDecoders.AppendElement(decoder);
 
   mLastStartTimestamp = 0;
   mLastEndTimestamp = 0;
-  mHasInit = true;
 
   return QueueInitializeDecoder(decoder);
 }
 
 bool
 TrackBuffer::QueueInitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder)
 {
   RefPtr<nsIRunnable> task =
@@ -311,47 +351,25 @@ TrackBuffer::Detach()
     DiscardDecoder();
   }
 }
 
 bool
 TrackBuffer::HasInitSegment()
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
-  return mHasInit;
+  return mParser->HasInitData();
 }
 
 bool
 TrackBuffer::IsReady()
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   MOZ_ASSERT((mInfo.HasAudio() || mInfo.HasVideo()) || mInitializedDecoders.IsEmpty());
-  return HasInitSegment() && (mInfo.HasAudio() || mInfo.HasVideo());
-}
-
-void
-TrackBuffer::LastTimestamp(int64_t& aStart, int64_t& aEnd)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  aStart = mLastStartTimestamp;
-  aEnd = mLastEndTimestamp;
-}
-
-void
-TrackBuffer::SetLastStartTimestamp(int64_t aStart)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  mLastStartTimestamp = aStart;
-}
-
-void
-TrackBuffer::SetLastEndTimestamp(int64_t aEnd)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  mLastEndTimestamp = aEnd;
+  return mParser->HasInitData() && (mInfo.HasAudio() || mInfo.HasVideo());
 }
 
 bool
 TrackBuffer::ContainsTime(int64_t aTime)
 {
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
     nsRefPtr<dom::TimeRanges> r = new dom::TimeRanges();
--- a/content/media/mediasource/TrackBuffer.h
+++ b/content/media/mediasource/TrackBuffer.h
@@ -12,16 +12,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/mozalloc.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nscore.h"
 
 namespace mozilla {
 
+class ContainerParser;
 class MediaSourceDecoder;
 
 namespace dom {
 
 class TimeRanges;
 
 } // namespace dom
 
@@ -40,39 +41,29 @@ public:
   bool EvictData(uint32_t aThreshold);
   void EvictBefore(double aTime);
 
   // Returns the highest end time of all of the buffered ranges in the
   // decoders managed by this TrackBuffer, and returns the union of the
   // decoders buffered ranges in aRanges.
   double Buffered(dom::TimeRanges* aRanges);
 
-  // Create a new decoder, set mCurrentDecoder to the new decoder, and queue
-  // the decoder for initialization.  The decoder is not considered
-  // initialized until it is added to mDecoders.
-  bool NewDecoder();
-
   // Mark the current decoder's resource as ended, clear mCurrentDecoder and
   // reset mLast{Start,End}Timestamp.
   void DiscardDecoder();
 
   void Detach();
 
   // Returns true if an init segment has been appended.
   bool HasInitSegment();
 
-  // Returns true iff HasInitSegment() and the decoder using that init
+  // Returns true iff mParser->HasInitData() and the decoder using that init
   // segment has successfully initialized by setting mHas{Audio,Video}..
   bool IsReady();
 
-  // Query and update mLast{Start,End}Timestamp.
-  void LastTimestamp(int64_t& aStart, int64_t& aEnd);
-  void SetLastStartTimestamp(int64_t aStart);
-  void SetLastEndTimestamp(int64_t aEnd);
-
   // Returns true if any of the decoders managed by this track buffer
   // contain aTime in their buffered ranges.
   bool ContainsTime(int64_t aTime);
 
   void BreakCycles();
 
   // Call ResetDecode() on each decoder in mDecoders.
   void ResetDecode();
@@ -84,16 +75,25 @@ public:
 
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~TrackBuffer();
 
+  // Create a new decoder, set mCurrentDecoder to the new decoder, and queue
+  // the decoder for initialization.  The decoder is not considered
+  // initialized until it is added to mDecoders.
+  bool NewDecoder();
+
+  // Helper for AppendData, ensures NotifyDataArrived is called whenever
+  // data is appended to the current decoder's SourceBufferResource.
+  bool AppendDataToCurrentResource(const uint8_t* aData, uint32_t aLength);
+
   // Queue execution of InitializeDecoder on mTaskQueue.
   bool QueueInitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
 
   // Runs decoder initialization including calling ReadMetadata.  Runs as an
   // event on the decode thread pool.
   void InitializeDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
 
   // Adds a successfully initialized decoder to mDecoders and (if it's the
@@ -107,16 +107,18 @@ private:
   bool ValidateTrackFormats(const MediaInfo& aInfo);
 
   // Remove aDecoder from mDecoders and dispatch an event to the main thread
   // to clean up the decoder.  If aDecoder was added to
   // mInitializedDecoders, it must have been removed before calling this
   // function.
   void RemoveDecoder(nsRefPtr<SourceBufferDecoder> aDecoder);
 
+  nsAutoPtr<ContainerParser> mParser;
+
   // A task queue using the shared media thread pool.  Used exclusively to
   // initialize (i.e. call ReadMetadata on) decoders as they are created via
   // NewDecoder.
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   // All of the decoders managed by this TrackBuffer.  Access protected by
   // mParentDecoder's monitor.
   nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
@@ -131,19 +133,15 @@ private:
   nsRefPtr<MediaSourceDecoder> mParentDecoder;
   const nsCString mType;
 
   // The last start and end timestamps added to the TrackBuffer via
   // AppendData.  Accessed on the main thread only.
   int64_t mLastStartTimestamp;
   int64_t mLastEndTimestamp;
 
-  // Set when the initialization segment is first seen and cached (implied
-  // by new decoder creation).  Protected by mParentDecoder's monitor.
-  bool mHasInit;
-
   // Set when the first decoder used by this TrackBuffer is initialized.
   // Protected by mParentDecoder's monitor.
   MediaInfo mInfo;
 };
 
 } // namespace mozilla
 #endif /* MOZILLA_TRACKBUFFER_H_ */
--- a/content/media/mediasource/moz.build
+++ b/content/media/mediasource/moz.build
@@ -12,16 +12,17 @@ EXPORTS += [
 
 EXPORTS.mozilla.dom += [
     'MediaSource.h',
     'SourceBuffer.h',
     'SourceBufferList.h',
 ]
 
 UNIFIED_SOURCES += [
+    'ContainerParser.cpp',
     'MediaSource.cpp',
     'MediaSourceDecoder.cpp',
     'MediaSourceReader.cpp',
     'MediaSourceUtils.cpp',
     'SourceBuffer.cpp',
     'SourceBufferDecoder.cpp',
     'SourceBufferList.cpp',
     'SourceBufferResource.cpp',
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -664,20 +664,22 @@ public:
                    bool strict,
                    JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
   virtual bool keys(JSContext *cx, JS::Handle<JSObject*> proxy,
                     JS::AutoIdVector &props) const MOZ_OVERRIDE;
   virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> proxy,
                        unsigned flags,
                        JS::MutableHandle<JS::Value> vp) const MOZ_OVERRIDE;
 
+  static void ObjectMoved(JSObject *obj, const JSObject *old);
+
   static const nsOuterWindowProxy singleton;
 
 protected:
-  nsGlobalWindow* GetWindow(JSObject *proxy) const
+  static nsGlobalWindow* GetWindow(JSObject *proxy)
   {
     return nsGlobalWindow::FromSupports(
       static_cast<nsISupports*>(js::GetProxyExtra(proxy, 0).toPrivate()));
   }
 
   // False return value means we threw an exception.  True return value
   // but false "found" means we didn't have a subframe at that index.
   bool GetSubframeWindow(JSContext *cx, JS::Handle<JSObject*> proxy,
@@ -699,17 +701,18 @@ const js::Class OuterWindowProxyClass =
     PROXY_CLASS_WITH_EXT(
         "Proxy",
         0, /* additional slots */
         0, /* additional class flags */
         PROXY_MAKE_EXT(
             nullptr, /* outerObject */
             js::proxy_innerObject,
             nullptr, /* iteratorObject */
-            false   /* isWrappedNative */
+            false,   /* isWrappedNative */
+            nsOuterWindowProxy::ObjectMoved
         ));
 
 bool
 nsOuterWindowProxy::isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy,
                                  bool *extensible) const
 {
   // If [[Extensible]] could be false, then navigating a window could navigate
   // to a window that's [[Extensible]] after being at one that wasn't: an
@@ -1019,16 +1022,25 @@ nsOuterWindowProxy::watch(JSContext *cx,
 
 bool
 nsOuterWindowProxy::unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
                             JS::Handle<jsid> id) const
 {
   return js::UnwatchGuts(cx, proxy, id);
 }
 
+void
+nsOuterWindowProxy::ObjectMoved(JSObject *obj, const JSObject *old)
+{
+  nsGlobalWindow* global = GetWindow(obj);
+  if (global) {
+    global->UpdateWrapper(obj, old);
+  }
+}
+
 const nsOuterWindowProxy
 nsOuterWindowProxy::singleton;
 
 class nsChromeOuterWindowProxy : public nsOuterWindowProxy
 {
 public:
   MOZ_CONSTEXPR nsChromeOuterWindowProxy() : nsOuterWindowProxy() { }
 
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsWrapperCache_h___
 #define nsWrapperCache_h___
 
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Assertions.h"
+#include "js/Class.h"
 #include "js/Id.h"          // must come before js/RootingAPI.h
 #include "js/Value.h"       // must come before js/RootingAPI.h
 #include "js/RootingAPI.h"
 #include "js/TracingAPI.h"
 
 class XPCWrappedNativeScope;
 
 #define NS_WRAPPERCACHE_IID \
@@ -39,16 +40,24 @@ class XPCWrappedNativeScope;
  *  If WRAPPER_IS_DOM_BINDING is not set (IsDOMBinding() returns false):
  *    - a slim wrapper or the JSObject of an XPCWrappedNative wrapper
  *
  *  If WRAPPER_IS_DOM_BINDING is set (IsDOMBinding() returns true):
  *    - a DOM binding object (regular JS object or proxy)
  *
  * The finalizer for the wrapper clears the cache.
  *
+ * A compacting GC can move the wrapper object. Pointers to moved objects are
+ * usually found and updated by tracing the heap, however non-preserved wrappers
+ * are weak references and are not traced, so another approach is
+ * necessary. Instead a class hook (objectMovedOp) is provided that is called
+ * when an object is moved and is responsible for ensuring pointers are
+ * updated. It does this by calling UpdateWrapper() on the wrapper
+ * cache. SetWrapper() asserts that the hook is implemented for any wrapper set.
+ *
  * A number of the methods are implemented in nsWrapperCacheInlines.h because we
  * have to include some JS headers that don't play nicely with the rest of the
  * codebase. Include nsWrapperCacheInlines.h if you need to call those methods.
  */
 class nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_WRAPPERCACHE_IID)
@@ -84,31 +93,45 @@ public:
   {
     return GetWrapperJSObject();
   }
 
   void SetWrapper(JSObject* aWrapper)
   {
     MOZ_ASSERT(!PreservingWrapper(), "Clearing a preserved wrapper!");
     MOZ_ASSERT(aWrapper, "Use ClearWrapper!");
+    MOZ_ASSERT(js::HasObjectMovedOp(aWrapper),
+               "Object has not provided the hook to update the wrapper if it is moved");
 
     SetWrapperJSObject(aWrapper);
   }
 
   /**
    * Clear the wrapper. This should be called from the finalizer for the
    * wrapper.
    */
   void ClearWrapper()
   {
     MOZ_ASSERT(!PreservingWrapper(), "Clearing a preserved wrapper!");
 
     SetWrapperJSObject(nullptr);
   }
 
+  /**
+   * Update the wrapper if the object it contains is moved.
+   *
+   * This method must be called from the objectMovedOp class extension hook for
+   * any wrapper cached object.
+   */
+  void UpdateWrapper(JSObject* aNewObject, const JSObject* aOldObject)
+  {
+    MOZ_ASSERT(mWrapper == aOldObject);
+    mWrapper = aNewObject;
+  }
+
   bool PreservingWrapper()
   {
     return HasWrapperFlag(WRAPPER_BIT_PRESERVED);
   }
 
   void SetIsDOMBinding()
   {
     MOZ_ASSERT(!mWrapper && !(GetWrapperFlags() & ~WRAPPER_IS_DOM_BINDING),
@@ -157,17 +180,17 @@ public:
 
   void TraceWrapper(const TraceCallbacks& aCallbacks, void* aClosure)
   {
     if (PreservingWrapper() && mWrapper) {
       aCallbacks.Trace(&mWrapper, "Preserved wrapper", aClosure);
     }
   }
 
-  /* 
+  /*
    * The following methods for getting and manipulating flags allow the unused
    * bits of mFlags to be used by derived classes.
    */
 
   typedef uint32_t FlagsType;
 
   FlagsType GetFlags() const
   {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1208,16 +1208,34 @@ template<class T>
 inline void
 ClearWrapper(T* p, void*)
 {
   nsWrapperCache* cache;
   CallQueryInterface(p, &cache);
   ClearWrapper(p, cache);
 }
 
+template<class T>
+inline void
+UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
+{
+  JS::AutoAssertGCCallback inCallback(obj);
+  cache->UpdateWrapper(obj, old);
+}
+
+template<class T>
+inline void
+UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
+{
+  JS::AutoAssertGCCallback inCallback(obj);
+  nsWrapperCache* cache;
+  CallQueryInterface(p, &cache);
+  UpdateWrapper(p, cache, obj, old);
+}
+
 // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
 // Return true if we successfully preserved the wrapper, or there is no wrapper
 // to preserve. In the latter case we don't need to preserve the wrapper, because
 // the object can only be obtained by JS once, or they cannot be meaningfully
 // owned from the native side.
 //
 // This operation will return false only for non-nsISupports cycle-collected
 // objects, because we cannot determine if they are wrappercached or not.
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -12,16 +12,17 @@ import textwrap
 
 from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue, IDLEmptySequenceValue
 from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
 
 AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
+OBJECT_MOVED_HOOK_NAME = '_objectMoved'
 CONSTRUCT_HOOK_NAME = '_constructor'
 LEGACYCALLER_HOOK_NAME = '_legacycaller'
 HASINSTANCE_HOOK_NAME = '_hasInstance'
 NEWRESOLVE_HOOK_NAME = '_newResolve'
 ENUMERATE_HOOK_NAME = '_enumerate'
 ENUM_ENTRY_VARIABLE_NAME = 'strings'
 INSTANCE_RESERVED_SLOTS = 1
 
@@ -359,58 +360,71 @@ class CGDOMJSClass(CGThing):
         self.descriptor = descriptor
 
     def declare(self):
         return ""
 
     def define(self):
         traceHook = 'nullptr'
         callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
+        objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
         slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots
         classFlags = "JSCLASS_IS_DOMJSCLASS | "
-        classExtensionAndObjectOps = """\
-JS_NULL_CLASS_EXT,
-JS_NULL_OBJECT_OPS
-"""
+        classExtensionAndObjectOps = fill(
+            """
+            {
+              nullptr, /* outerObject */
+              nullptr, /* innerObject */
+              nullptr, /* iteratorObject */
+              false,   /* isWrappedNative */
+              nullptr, /* weakmapKeyDelegateOp */
+              ${objectMoved} /* objectMovedOp */
+            },
+            JS_NULL_OBJECT_OPS
+            """,
+            objectMoved=objectMovedHook)
         if self.descriptor.isGlobal():
             classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
             traceHook = "JS_GlobalObjectTraceHook"
             reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
             if not self.descriptor.workers:
-                classExtensionAndObjectOps = """\
-{
-  nsGlobalWindow::OuterObject, /* outerObject */
-  nullptr, /* innerObject */
-  nullptr, /* iteratorObject */
-  false, /* isWrappedNative */
-  nullptr /* weakmapKeyDelegateOp */
-},
-{
-  nullptr, /* lookupGeneric */
-  nullptr, /* lookupProperty */
-  nullptr, /* lookupElement */
-  nullptr, /* defineGeneric */
-  nullptr, /* defineProperty */
-  nullptr, /* defineElement */
-  nullptr, /* getGeneric  */
-  nullptr, /* getProperty */
-  nullptr, /* getElement */
-  nullptr, /* setGeneric */
-  nullptr, /* setProperty */
-  nullptr, /* setElement */
-  nullptr, /* getGenericAttributes */
-  nullptr, /* setGenericAttributes */
-  nullptr, /* deleteGeneric */
-  nullptr, /* watch */
-  nullptr, /* unwatch */
-  nullptr, /* slice */
-  nullptr, /* enumerate */
-  JS_ObjectToOuterObject /* thisObject */
-}
-"""
+                classExtensionAndObjectOps = fill(
+                    """
+                    {
+                      nsGlobalWindow::OuterObject, /* outerObject */
+                      nullptr, /* innerObject */
+                      nullptr, /* iteratorObject */
+                      false,   /* isWrappedNative */
+                      nullptr, /* weakmapKeyDelegateOp */
+                      ${objectMoved} /* objectMovedOp */
+                    },
+                    {
+                      nullptr, /* lookupGeneric */
+                      nullptr, /* lookupProperty */
+                      nullptr, /* lookupElement */
+                      nullptr, /* defineGeneric */
+                      nullptr, /* defineProperty */
+                      nullptr, /* defineElement */
+                      nullptr, /* getGeneric  */
+                      nullptr, /* getProperty */
+                      nullptr, /* getElement */
+                      nullptr, /* setGeneric */
+                      nullptr, /* setProperty */
+                      nullptr, /* setElement */
+                      nullptr, /* getGenericAttributes */
+                      nullptr, /* setGenericAttributes */
+                      nullptr, /* deleteGeneric */
+                      nullptr, /* watch */
+                      nullptr, /* unwatch */
+                      nullptr, /* slice */
+                      nullptr, /* enumerate */
+                      JS_ObjectToOuterObject /* thisObject */
+                    }
+                    """,
+                    objectMoved=objectMovedHook)
         else:
             classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
             reservedSlots = slotCount
         if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
             newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
             classFlags += " | JSCLASS_NEW_RESOLVE"
             enumerateHook = ENUMERATE_HOOK_NAME
         elif self.descriptor.isGlobal():
@@ -476,27 +490,34 @@ class CGDOMProxyJSClass(CGThing):
 
     def define(self):
         flags = ["JSCLASS_IS_DOMJSCLASS"]
         # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because
         # we don't want people ever adding that to any interface other than
         # HTMLAllCollection.  So just hardcode it here.
         if self.descriptor.interface.identifier.name == "HTMLAllCollection":
             flags.append("JSCLASS_EMULATES_UNDEFINED")
+        objectMovedHook = OBJECT_MOVED_HOOK_NAME if self.descriptor.wrapperCache else 'nullptr'
         return fill(
             """
             static const DOMJSClass Class = {
-              PROXY_CLASS_DEF("${name}",
-                              0, /* extra slots */
-                              ${flags}),
+              PROXY_CLASS_WITH_EXT("${name}",
+                                   0, /* extra slots */
+                                   ${flags},
+                                   PROXY_MAKE_EXT(nullptr, /* outerObject */
+                                                  nullptr, /* innerObject */
+                                                  nullptr, /* iteratorObject */
+                                                  false,   /* isWrappedNative */
+                                                  ${objectMoved})),
               $*{descriptor}
             };
             """,
             name=self.descriptor.interface.identifier.name,
             flags=" | ".join(flags),
+            objectMoved=objectMovedHook,
             descriptor=DOMClass(self.descriptor))
 
 
 def PrototypeIDAndDepth(descriptor):
     prototypeID = "prototypes::id::"
     if descriptor.interface.hasInterfacePrototypeObject():
         prototypeID += descriptor.interface.identifier.name
         if descriptor.workers:
@@ -1544,21 +1565,38 @@ class CGClassFinalizeHook(CGAbstractClas
         args = [Argument('js::FreeOp*', 'fop'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
                                      'void', args)
 
     def generate_code(self):
         return finalizeHook(self.descriptor, self.name, self.args[0].name).define()
 
 
+class CGClassObjectMovedHook(CGAbstractClassHook):
+    """
+    A hook for objectMovedOp, used to update the wrapper cache when an object it
+    is holding moves.
+    """
+    def __init__(self, descriptor):
+        args = [Argument('JSObject*', 'obj'), Argument('const JSObject*', 'old')]
+        CGAbstractClassHook.__init__(self, descriptor, OBJECT_MOVED_HOOK_NAME,
+                                     'void', args)
+
+    def generate_code(self):
+        assert self.descriptor.wrapperCache
+        return CGIfWrapper(CGGeneric("UpdateWrapper(self, self, obj, old);\n"),
+                           "self").define()
+
+
 def JSNativeArguments():
     return [Argument('JSContext*', 'cx'),
             Argument('unsigned', 'argc'),
             Argument('JS::Value*', 'vp')]
 
+
 class CGClassConstructor(CGAbstractStaticMethod):
     """
     JS-visible constructor for our objects
     """
     def __init__(self, descriptor, ctor, name=CONSTRUCT_HOOK_NAME):
         CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool',
                                         JSNativeArguments())
         self._ctor = ctor
@@ -10914,16 +10952,19 @@ class CGDescriptor(CGThing):
         if descriptor.concrete and not descriptor.proxy:
             if wantsAddProperty(descriptor):
                 cgThings.append(CGAddPropertyHook(descriptor))
 
             # Always have a finalize hook, regardless of whether the class
             # wants a custom hook.
             cgThings.append(CGClassFinalizeHook(descriptor))
 
+        if descriptor.concrete and descriptor.wrapperCache:
+            cgThings.append(CGClassObjectMovedHook(descriptor))
+
         if len(descriptor.permissions):
             for (k, v) in sorted(descriptor.permissions.items()):
                 perms = CGList((CGGeneric('"%s",' % p) for p in k), joiner="\n")
                 perms.append(CGGeneric("nullptr"))
                 cgThings.append(CGWrapper(CGIndenter(perms),
                                           pre="static const char* const permissions_%i[] = {\n" % v,
                                           post="\n};\n",
                                           defineOnly=True))
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -336,16 +336,17 @@ struct nsIConsoleService::COMTypeInfo<ns
   static const nsIID kIID;
 };
 const nsIID nsIConsoleService::COMTypeInfo<nsConsoleService, void>::kIID = NS_ICONSOLESERVICE_IID;
 
 namespace mozilla {
 namespace dom {
 
 #ifdef MOZ_NUWA_PROCESS
+int32_t ContentParent::sNuwaPid = 0;
 bool ContentParent::sNuwaReady = false;
 #endif
 
 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 
 class MemoryReportRequestParent : public PMemoryReportRequestParent
 {
 public:
@@ -581,16 +582,17 @@ ContentParent::RunNuwaProcess()
         new ContentParent(/* aApp = */ nullptr,
                           /* aOpener = */ nullptr,
                           /* aIsForBrowser = */ false,
                           /* aIsForPreallocated = */ true,
                           PROCESS_PRIORITY_BACKGROUND,
                           /* aIsNuwaProcess = */ true);
     nuwaProcess->Init();
 #ifdef MOZ_NUWA_PROCESS
+    sNuwaPid = nuwaProcess->Pid();
     sNuwaReady = false;
 #endif
     return nuwaProcess.forget();
 }
 
 // PreallocateAppProcess is called by the PreallocatedProcessManager.
 // ContentParent then takes this process back within
 // GetNewOrPreallocatedAppProcess.
@@ -1982,16 +1984,17 @@ ContentParent::~ContentParent()
         // that sAppContentParents->Get(mAppManifestURL) != this.
         MOZ_ASSERT(!sAppContentParents ||
                    sAppContentParents->Get(mAppManifestURL) != this);
     }
 
 #ifdef MOZ_NUWA_PROCESS
     if (IsNuwaProcess()) {
         sNuwaReady = false;
+        sNuwaPid = 0;
     }
 #endif
 }
 
 void
 ContentParent::InitInternal(ProcessPriority aInitialPriority,
                             bool aSetupOffMainThreadCompositing,
                             bool aSendRegisteredChrome)
@@ -3673,16 +3676,22 @@ ContentParent::DoSendAsyncMessage(JSCont
     ClonedMessageData data;
     if (!BuildClonedMessageDataForParent(this, aData, data)) {
         return false;
     }
     InfallibleTArray<CpowEntry> cpows;
     if (aCpows && !GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
         return false;
     }
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess() && IsNuwaReady()) {
+        // Nuwa won't receive frame messages after it is frozen.
+        return true;
+    }
+#endif
     return SendAsyncMessage(nsString(aMessage), data, cpows, Principal(aPrincipal));
 }
 
 bool
 ContentParent::CheckPermission(const nsAString& aPermission)
 {
     return AssertAppProcessPermission(this, NS_ConvertUTF16toUTF8(aPermission).get());
 }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -74,16 +74,20 @@ class ContentParent MOZ_FINAL : public P
     typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
     typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
     typedef mozilla::ipc::TestShellParent TestShellParent;
     typedef mozilla::ipc::URIParams URIParams;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
 public:
 #ifdef MOZ_NUWA_PROCESS
+    static int32_t NuwaPid() {
+        return sNuwaPid;
+    }
+
     static bool IsNuwaReady() {
         return sNuwaReady;
     }
 #endif
     virtual bool IsContentParent() MOZ_OVERRIDE { return true; }
     /**
      * Start up the content-process machinery.  This might include
      * scheduling pre-launch tasks.
@@ -707,16 +711,17 @@ private:
 
 #ifdef MOZ_X11
     // Dup of child's X socket, used to scope its resources to this
     // object instead of the child process's lifetime.
     ScopedClose mChildXSocketFdDup;
 #endif
 
 #ifdef MOZ_NUWA_PROCESS
+    static int32_t sNuwaPid;
     static bool sNuwaReady;
 #endif
 };
 
 } // namespace dom
 } // namespace mozilla
 
 class ParentIdleListener : public nsIObserver {
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1893,18 +1893,19 @@ TabChild::RecvHandleDoubleTap(const CSSP
     DispatchMessageManagerMessage(NS_LITERAL_STRING("Gesture:DoubleTap"), data);
 
     return true;
 }
 
 bool
 TabChild::RecvHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid)
 {
-  TABC_LOG("Handling single tap at %s with %p %p %d\n",
-    Stringify(aPoint).c_str(), mGlobal.get(), mTabChildGlobal.get(), mTouchEndCancelled);
+  TABC_LOG("Handling single tap at %s on %s with %p %p %d\n",
+    Stringify(aPoint).c_str(), Stringify(aGuid).c_str(), mGlobal.get(),
+    mTabChildGlobal.get(), mTouchEndCancelled);
 
   if (!mGlobal || !mTabChildGlobal) {
     return true;
   }
 
   if (mTouchEndCancelled) {
     return true;
   }
--- a/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveVideo.html
+++ b/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveVideo.html
@@ -15,15 +15,15 @@
     bug: "850275",
     title: "Simple offer media constraint test with video"
   });
 
   runNetworkTest(function() {
     var test = new PeerConnectionTest();
     // TODO: Stop using old constraint-like RTCOptions soon (Bug 1064223).
     // Watch out for case-difference when fixing: { offerToReceiveVideo: true }
-    test.setOfferOptions({ optional: [{ OfferToReceiveAudio: true }] });
+    test.setOfferOptions({ optional: [{ OfferToReceiveVideo: true }] });
     test.run();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/storage/DOMStorageIPC.cpp
+++ b/dom/storage/DOMStorageIPC.cpp
@@ -584,18 +584,25 @@ DOMStorageDBParent::RecvAsyncFlush()
 
 // DOMStorageObserverSink
 
 nsresult
 DOMStorageDBParent::Observe(const char* aTopic,
                             const nsACString& aScopePrefix)
 {
   if (mIPCOpen) {
-    mozilla::unused << SendObserve(nsDependentCString(aTopic),
-                                   nsCString(aScopePrefix));
+#ifdef MOZ_NUWA_PROCESS
+    if (!(static_cast<ContentParent*>(Manager())->IsNuwaProcess() &&
+          ContentParent::IsNuwaReady())) {
+#endif
+      mozilla::unused << SendObserve(nsDependentCString(aTopic),
+                                     nsCString(aScopePrefix));
+#ifdef MOZ_NUWA_PROCESS
+    }
+#endif
   }
 
   return NS_OK;
 }
 
 namespace { // anon
 
 // Results must be sent back on the main thread
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -340,84 +340,84 @@ DOMWifiManager.prototype = {
         this._enabled = true;
         this._macAddress = msg.macAddress;
         this._fireEnabledOrDisabled(true);
         break;
 
       case "WifiManager:onconnecting":
         this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "connecting";
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
 
       case "WifiManager:onassociate":
         this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "associated";
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
 
       case "WifiManager:onconnect":
         this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "connected";
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
 
       case "WifiManager:ondisconnect":
         this._currentNetwork = null;
         this._connectionStatus = "disconnected";
         this._lastConnectionInfo = null;
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
 
       case "WifiManager:onwpstimeout":
         this._currentNetwork = null;
         this._connectionStatus = "wps-timedout";
         this._lastConnectionInfo = null;
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
 
       case "WifiManager:onwpsfail":
         this._currentNetwork = null;
         this._connectionStatus = "wps-failed";
         this._lastConnectionInfo = null;
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
 
       case "WifiManager:onwpsoverlap":
         this._currentNetwork = null;
         this._connectionStatus = "wps-overlapped";
         this._lastConnectionInfo = null;
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
 
       case "WifiManager:connectioninfoupdate":
         this._lastConnectionInfo = this._convertConnectionInfo(msg);
         this._fireConnectionInfoUpdate(msg);
         break;
       case "WifiManager:onconnectingfailed":
         this._currentNetwork = null;
         this._connectionStatus = "connectingfailed";
         this._lastConnectionInfo = null;
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
       case "WifiManager:onauthenticating":
-        this._currentNetwork = msg.network;
+        this._currentNetwork = this._convertWifiNetwork(msg.network);
         this._connectionStatus = "authenticating";
-        this._fireStatusChangeEvent();
+        this._fireStatusChangeEvent(msg.network);
         break;
       case "WifiManager:stationinfoupdate":
         this._stationNumber = msg.station;
         this._fireStationInfoUpdate(msg);
         break;
     }
   },
 
-  _fireStatusChangeEvent: function StatusChangeEvent() {
+  _fireStatusChangeEvent: function StatusChangeEvent(aNetwork) {
     var event = new this._window.MozWifiStatusChangeEvent("statuschange",
-                                                          { network: this._currentNetwork,
+                                                          { network: this._convertWifiNetwork(aNetwork),
                                                             status: this._connectionStatus
                                                           });
     this.__DOM_IMPL__.dispatchEvent(event);
   },
 
   _fireConnectionInfoUpdate: function onConnectionInfoUpdate(info) {
     var evt = new this._window.MozWifiConnectionInfoEvent("connectioninfoupdate",
                                                           { network: this._currentNetwork,
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1837,16 +1837,19 @@ function WifiWorker() {
   }
 
   // A list of requests to turn wifi on or off.
   this._stateRequests = [];
 
   // Given a connection status network, takes a network from
   // self.configuredNetworks and prepares it for the DOM.
   netToDOM = function(net) {
+    if (!net) {
+      return null;
+    }
     var ssid = dequote(net.ssid);
     var security = (net.key_mgmt === "NONE" && net.wep_key0) ? ["WEP"] :
                    (net.key_mgmt && net.key_mgmt !== "NONE") ? [net.key_mgmt.split(" ")[0]] :
                    [];
     var password;
     if (("psk" in net && net.psk) ||
         ("password" in net && net.password) ||
         ("wep_key0" in net && net.wep_key0)) {
@@ -2021,17 +2024,17 @@ function WifiWorker() {
           dequote(self.currentNetwork.ssid) == connectionInfo.ssid &&
           typeof self.currentNetwork.netId !== "undefined") {
         netId = self.currentNetwork.netId;
       }
       if (netId) {
         WifiManager.disableNetwork(netId, function() {});
       }
     });
-    self._fireEvent("onconnectingfailed", {network: self.currentNetwork});
+    self._fireEvent("onconnectingfailed", {network: netToDOM(self.currentNetwork)});
   }
 
   WifiManager.onstatechange = function() {
     debug("State change: " + this.prevState + " -> " + this.state);
 
     if (self._connectionInfoTimer &&
         this.state !== "CONNECTED" &&
         this.state !== "COMPLETED") {
@@ -2064,50 +2067,58 @@ function WifiWorker() {
       case "ASSOCIATED":
         if (!self.currentNetwork) {
           self.currentNetwork =
             { bssid: WifiManager.connectionInfo.bssid,
               ssid: quote(WifiManager.connectionInfo.ssid) };
         }
 
         self.currentNetwork.netId = this.id;
-        WifiManager.getNetworkConfiguration(self.currentNetwork, function (){});
+        WifiManager.getNetworkConfiguration(self.currentNetwork, function (){
+          // Notify again because we get complete network information.
+          self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) });
+        });
         break;
       case "COMPLETED":
         // Now that we've successfully completed the connection, re-enable the
         // rest of our networks.
         // XXX Need to do this eventually if the user entered an incorrect
         // password. For now, we require user interaction to break the loop and
         // select a better network!
         if (self._needToEnableNetworks) {
           self._enableAllNetworks();
           self._needToEnableNetworks = false;
         }
 
+        var _oncompleted = function() {
+          // Update http proxy when connected to network.
+          let netConnect = WifiManager.getHttpProxyNetwork(self.currentNetwork);
+          if (netConnect)
+            WifiManager.setHttpProxy(netConnect);
+
+          // The full authentication process is completed, reset the count.
+          WifiManager.authenticationFailuresCount = 0;
+          WifiManager.loopDetectionCount = 0;
+          self._startConnectionInfoTimer();
+          self._fireEvent("onassociate", { network: netToDOM(self.currentNetwork) });
+        };
+
         // We get the ASSOCIATED event when we've associated but not connected, so
         // wait until the handshake is complete.
         if (this.fromStatus || !self.currentNetwork) {
           // In this case, we connected to an already-connected wpa_supplicant,
           // because of that we need to gather information about the current
           // network here.
-          self.currentNetwork = { ssid: quote(WifiManager.connectionInfo.ssid),
+          self.currentNetwork = { bssid: WifiManager.connectionInfo.bssid,
+                                  ssid: quote(WifiManager.connectionInfo.ssid),
                                   netId: WifiManager.connectionInfo.id };
-          WifiManager.getNetworkConfiguration(self.currentNetwork, function(){});
+          WifiManager.getNetworkConfiguration(self.currentNetwork, _oncompleted);
+        } else {
+          _oncompleted();
         }
-
-        // Update http proxy when connected to network.
-        let netConnect = WifiManager.getHttpProxyNetwork(self.currentNetwork);
-        if (netConnect)
-          WifiManager.setHttpProxy(netConnect);
-
-        // The full authentication process is completed, reset the count.
-        WifiManager.authenticationFailuresCount = 0;
-        WifiManager.loopDetectionCount = 0;
-        self._startConnectionInfoTimer();
-        self._fireEvent("onassociate", { network: netToDOM(self.currentNetwork) });
         break;
       case "CONNECTED":
         // BSSID is read after connected, update it.
         self.currentNetwork.bssid = WifiManager.connectionInfo.bssid;
         break;
       case "DISCONNECTED":
         // wpa_supplicant may give us a "DISCONNECTED" event even if
         // we are already in "DISCONNECTED" state.
@@ -2116,17 +2127,17 @@ function WifiWorker() {
              (this.prevState === "INITIALIZING" ||
               this.prevState === "DISCONNECTED" ||
               this.prevState === "INTERFACE_DISABLED" ||
               this.prevState === "INACTIVE" ||
               this.prevState === "UNINITIALIZED")) {
           return;
         }
 
-        self._fireEvent("ondisconnect", {});
+        self._fireEvent("ondisconnect", {network: netToDOM(self.currentNetwork)});
 
         // When disconnected, clear the http proxy setting if it exists.
         // Temporarily set http proxy to empty and restore user setting after setHttpProxy.
         let netDisconnect = WifiManager.getHttpProxyNetwork(self.currentNetwork);
         if (netDisconnect) {
           let prehttpProxyHostSetting = netDisconnect.httpProxyHost;
           let prehttpProxyPortSetting = netDisconnect.httpProxyPort;
 
--- a/gfx/layers/LayersLogging.cpp
+++ b/gfx/layers/LayersLogging.cpp
@@ -148,16 +148,25 @@ AppendToString(std::stringstream& aStrea
     AppendToString(aStream, m.GetScrollParentId(), " p=");
     aStream << nsPrintfCString(" i=(%ld %lld) }",
             m.GetPresShellId(), m.GetScrollId()).get();
   }
   aStream << sfx;
 }
 
 void
+AppendToString(std::stringstream& aStream, const ScrollableLayerGuid& s,
+               const char* pfx, const char* sfx)
+{
+  aStream << pfx
+          << nsPrintfCString("{ l=%llu, p=%u, v=%llu }", s.mLayersId, s.mPresShellId, s.mScrollId).get()
+          << sfx;
+}
+
+void
 AppendToString(std::stringstream& aStream, const Matrix4x4& m,
                const char* pfx, const char* sfx)
 {
   aStream << pfx;
   if (m.Is2D()) {
     Matrix matrix = m.As2D();
     if (matrix.IsIdentity()) {
       aStream << "[ I ]";
--- a/gfx/layers/LayersLogging.h
+++ b/gfx/layers/LayersLogging.h
@@ -92,16 +92,20 @@ AppendToString(std::stringstream& aStrea
 void
 AppendToString(std::stringstream& aStream, const nsIntSize& sz,
                const char* pfx="", const char* sfx="");
 
 void
 AppendToString(std::stringstream& aStream, const FrameMetrics& m,
                const char* pfx="", const char* sfx="", bool detailed = false);
 
+void
+AppendToString(std::stringstream& aStream, const ScrollableLayerGuid& s,
+               const char* pfx="", const char* sfx="");
+
 template<class T>
 void
 AppendToString(std::stringstream& aStream, const mozilla::gfx::MarginTyped<T>& m,
                const char* pfx="", const char* sfx="")
 {
   aStream << pfx;
   aStream << nsPrintfCString(
     "(l=%f, t=%f, r=%f, b=%f)",
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2745,17 +2745,17 @@ void AsyncPanZoomController::NotifyLayer
 
   if (scrollOffsetUpdated) {
     // Once layout issues a scroll offset update, it becomes impervious to
     // scroll offset updates from APZ until we acknowledge the update it sent.
     // This prevents APZ updates from clobbering scroll updates from other
     // more "legitimate" sources like content scripts.
     nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
     if (controller) {
-      APZC_LOG("%p sending scroll update acknowledgement with gen %lu\n", this, aLayerMetrics.GetScrollGeneration());
+      APZC_LOG("%p sending scroll update acknowledgement with gen %u\n", this, aLayerMetrics.GetScrollGeneration());
       controller->AcknowledgeScrollUpdate(aLayerMetrics.GetScrollId(),
                                           aLayerMetrics.GetScrollGeneration());
     }
   }
 
   if (needContentRepaint) {
     RequestContentRepaint();
   }
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -287,16 +287,25 @@ public:
     NS_IMETHOD Run() {
         MOZ_ASSERT(NS_IsMainThread());
 
         nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId);
         if (sf) {
             sf->ResetScrollInfoIfGeneration(mScrollGeneration);
         }
 
+        // Since the APZ and content are in sync, we need to clear any callback transform
+        // that might have been set on the last repaint request (which might have failed
+        // due to the inflight scroll update that this message is acknowledging).
+        nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(mScrollId);
+        if (content) {
+            content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(),
+                                 nsINode::DeleteProperty<CSSPoint>);
+        }
+
         return NS_OK;
     }
 
 protected:
     ViewID mScrollId;
     uint32_t mScrollGeneration;
 };
 
--- a/gfx/skia/trunk/include/config/SkUserConfig.h
+++ b/gfx/skia/trunk/include/config/SkUserConfig.h
@@ -200,14 +200,13 @@
 #define SK_A32_SHIFT 24
 #define SK_R32_SHIFT 16
 #define SK_G32_SHIFT 8
 #define SK_B32_SHIFT 0
 
 #define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 0
 
 #define SK_SUPPORT_LEGACY_GETDEVICE
-#define SK_SUPPORT_LEGACY_GETTOPDEVICE
 #define SK_IGNORE_ETC1_SUPPORT
 
 #define SK_RASTERIZE_EVEN_ROUNDING
 
 #endif
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -1101,20 +1101,19 @@ void imgLoader::GlobalInit()
   if (NS_SUCCEEDED(rv))
     sCacheTimeWeight = timeweight / 1000.0;
   else
     sCacheTimeWeight = 0.5;
 
   int32_t cachesize;
   rv = Preferences::GetInt("image.cache.size", &cachesize);
   if (NS_SUCCEEDED(rv))
-    sCacheMaxSize = cachesize;
+    sCacheMaxSize = cachesize > 0 ? cachesize : 0;
   else
     sCacheMaxSize = 5 * 1024 * 1024;
-  sCacheMaxSize = sCacheMaxSize > 0 ? sCacheMaxSize : 0;
 
   sMemReporter = new imgMemoryReporter();
   RegisterStrongMemoryReporter(sMemReporter);
   RegisterImagesContentUsedUncompressedDistinguishedAmount(imgMemoryReporter::ImagesContentUsedUncompressedDistinguishedAmount);
 }
 
 nsresult imgLoader::InitCache()
 {
--- a/ipc/glue/FileDescriptor.cpp
+++ b/ipc/glue/FileDescriptor.cpp
@@ -37,17 +37,17 @@ FileDescriptor::FileDescriptor(PlatformH
   mHandleCreatedByOtherProcessWasUsed(false)
 {
   DuplicateInCurrentProcess(aHandle);
 }
 
 void
 FileDescriptor::DuplicateInCurrentProcess(PlatformHandleType aHandle)
 {
-  MOZ_ASSERT_IF(mHandleCreatedByOtherProcess,
+  MOZ_ASSERT_IF(mHandleCreatedByOtherProcess && IsValid(),
                 mHandleCreatedByOtherProcessWasUsed);
 
   if (IsValid(aHandle)) {
     PlatformHandleType newHandle;
 #ifdef XP_WIN
     if (DuplicateHandle(GetCurrentProcess(), aHandle, GetCurrentProcess(),
                         &newHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
 #else // XP_WIN
@@ -60,17 +60,17 @@ FileDescriptor::DuplicateInCurrentProces
   }
 
   mHandle = INVALID_HANDLE;
 }
 
 void
 FileDescriptor::CloseCurrentProcessHandle()
 {
-  MOZ_ASSERT_IF(mHandleCreatedByOtherProcess,
+  MOZ_ASSERT_IF(mHandleCreatedByOtherProcess && IsValid(),
                 mHandleCreatedByOtherProcessWasUsed);
 
   // Don't actually close handles created by another process.
   if (mHandleCreatedByOtherProcess) {
     return;
   }
 
   if (IsValid()) {
--- a/ipc/glue/MessageLink.cpp
+++ b/ipc/glue/MessageLink.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/dom/ContentParent.h"
 #endif
 
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "nsDebug.h"
 #include "nsISupportsImpl.h"
 #include "nsXULAppAPI.h"
 
@@ -65,16 +66,19 @@ MessageLink::~MessageLink()
 #endif
 }
 
 ProcessLink::ProcessLink(MessageChannel *aChan)
   : MessageLink(aChan)
   , mTransport(nullptr)
   , mIOLoop(nullptr)
   , mExistingListener(nullptr)
+#ifdef MOZ_NUWA_PROCESS
+  , mIsToNuwaProcess(false)
+#endif
 {
 }
 
 ProcessLink::~ProcessLink()
 {
 #ifdef DEBUG
     mTransport = nullptr;
     mIOLoop = nullptr;
@@ -163,16 +167,30 @@ ProcessLink::EchoMessage(Message *msg)
 }
 
 void
 ProcessLink::SendMessage(Message *msg)
 {
     mChan->AssertWorkerThread();
     mChan->mMonitor->AssertCurrentThreadOwns();
 
+#ifdef MOZ_NUWA_PROCESS
+    if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
+        switch (msg->type()) {
+        case mozilla::dom::PContent::Msg_NuwaFork__ID:
+        case mozilla::dom::PContent::Reply_AddNewProcess__ID:
+        case mozilla::dom::PContent::Msg_NotifyPhoneStateChange__ID:
+        case GOODBYE_MESSAGE_TYPE:
+            break;
+        default:
+            MOZ_CRASH();
+        }
+    }
+#endif
+
     mIOLoop->PostTask(
         FROM_HERE,
         NewRunnableMethod(mTransport, &Transport::Send, msg));
 }
 
 void
 ProcessLink::SendClose()
 {
@@ -355,16 +373,20 @@ ProcessLink::OnChannelConnected(int32_t 
           mChan->mMonitor->Notify();
           notifyChannel = true;
         }
     }
 
     if (mExistingListener)
         mExistingListener->OnChannelConnected(peer_pid);
 
+#ifdef MOZ_NUWA_PROCESS
+    mIsToNuwaProcess = (peer_pid == mozilla::dom::ContentParent::NuwaPid());
+#endif
+
     if (notifyChannel) {
       mChan->OnChannelConnected(peer_pid);
     }
 }
 
 void
 ProcessLink::OnChannelError()
 {
--- a/ipc/glue/MessageLink.h
+++ b/ipc/glue/MessageLink.h
@@ -165,16 +165,19 @@ class ProcessLink
 
     virtual bool Unsound_IsClosed() const MOZ_OVERRIDE;
     virtual uint32_t Unsound_NumQueuedMessages() const MOZ_OVERRIDE;
 
   protected:
     Transport* mTransport;
     MessageLoop* mIOLoop;       // thread where IO happens
     Transport::Listener* mExistingListener; // channel's previous listener
+#ifdef MOZ_NUWA_PROCESS
+    bool mIsToNuwaProcess;
+#endif
 };
 
 class ThreadLink : public MessageLink
 {
   public:
     ThreadLink(MessageChannel *aChan, MessageChannel *aTargetChan);
     virtual ~ThreadLink();
 
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -388,34 +388,70 @@ class JS_PUBLIC_API(AutoAssertOnGC)
     explicit AutoAssertOnGC(JSRuntime *rt) {}
     ~AutoAssertOnGC() {}
 
     static void VerifyIsSafeToGC(JSRuntime *rt) {}
 #endif
 };
 
 /*
- * Disable the static rooting hazard analysis in the live region, but assert if
- * any GC occurs while this guard object is live. This is most useful to help
- * the exact rooting hazard analysis in complex regions, since it cannot
- * understand dataflow.
+ * Assert if an allocation of a GC thing occurs while this class is live. This
+ * class does not disable the static rooting hazard analysis.
+ */
+class JS_PUBLIC_API(AutoAssertNoAlloc)
+{
+#ifdef JS_DEBUG
+    js::gc::GCRuntime *gc;
+
+  public:
+    AutoAssertNoAlloc() : gc(nullptr) {}
+    explicit AutoAssertNoAlloc(JSRuntime *rt);
+    void disallowAlloc(JSRuntime *rt);
+    ~AutoAssertNoAlloc();
+#else
+  public:
+    AutoAssertNoAlloc() {}
+    explicit AutoAssertNoAlloc(JSRuntime *rt) {}
+    void disallowAlloc(JSRuntime *rt) {}
+#endif
+};
+
+/*
+ * Disable the static rooting hazard analysis in the live region and assert if
+ * any allocation that could potentially trigger a GC occurs while this guard
+ * object is live. This is most useful to help the exact rooting hazard analysis
+ * in complex regions, since it cannot understand dataflow.
  *
  * Note: GC behavior is unpredictable even when deterministice and is generally
  *       non-deterministic in practice. The fact that this guard has not
  *       asserted is not a guarantee that a GC cannot happen in the guarded
  *       region. As a rule, anyone performing a GC unsafe action should
  *       understand the GC properties of all code in that region and ensure
  *       that the hazard analysis is correct for that code, rather than relying
  *       on this class.
  */
-class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertOnGC
+class JS_PUBLIC_API(AutoSuppressGCAnalysis) : public AutoAssertNoAlloc
 {
   public:
-    AutoSuppressGCAnalysis() : AutoAssertOnGC() {}
-    explicit AutoSuppressGCAnalysis(JSRuntime *rt) : AutoAssertOnGC(rt) {}
+    AutoSuppressGCAnalysis() : AutoAssertNoAlloc() {}
+    explicit AutoSuppressGCAnalysis(JSRuntime *rt) : AutoAssertNoAlloc(rt) {}
+};
+
+/*
+ * Assert that code is only ever called from a GC callback, disable the static
+ * rooting hazard analysis and assert if any allocation that could potentially
+ * trigger a GC occurs while this guard object is live.
+ *
+ * This is useful to make the static analysis ignore code that runs in GC
+ * callbacks.
+ */
+class JS_PUBLIC_API(AutoAssertGCCallback) : public AutoSuppressGCAnalysis
+{
+  public:
+    explicit AutoAssertGCCallback(JSObject *obj);
 };
 
 /*
  * Place AutoCheckCannotGC in scopes that you believe can never GC. These
  * annotations will be verified both dynamically via AutoAssertOnGC, and
  * statically with the rooting hazard analysis (implemented by making the
  * analysis consider AutoCheckCannotGC to be a GC pointer, and therefore
  * complain if it is live across a GC call.) It is useful when dealing with
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -355,16 +355,20 @@ ValidateSimdOperation(JSContext *cx, Asm
           case AsmJSSimdOperation_lessThan: native = simd_int32x4_lessThan; break;
           case AsmJSSimdOperation_greaterThan: native = simd_int32x4_greaterThan; break;
           case AsmJSSimdOperation_equal: native = simd_int32x4_equal; break;
           case AsmJSSimdOperation_and: native = simd_int32x4_and; break;
           case AsmJSSimdOperation_or: native = simd_int32x4_or; break;
           case AsmJSSimdOperation_xor: native = simd_int32x4_xor; break;
           case AsmJSSimdOperation_select: native = simd_int32x4_select; break;
           case AsmJSSimdOperation_splat: native = simd_int32x4_splat; break;
+          case AsmJSSimdOperation_withX: native = simd_int32x4_withX; break;
+          case AsmJSSimdOperation_withY: native = simd_int32x4_withY; break;
+          case AsmJSSimdOperation_withZ: native = simd_int32x4_withZ; break;
+          case AsmJSSimdOperation_withW: native = simd_int32x4_withW; break;
           case AsmJSSimdOperation_lessThanOrEqual:
           case AsmJSSimdOperation_greaterThanOrEqual:
           case AsmJSSimdOperation_notEqual:
           case AsmJSSimdOperation_mul:
           case AsmJSSimdOperation_div:
           case AsmJSSimdOperation_max:
           case AsmJSSimdOperation_min:
             MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("shouldn't have been validated in the first "
@@ -385,16 +389,20 @@ ValidateSimdOperation(JSContext *cx, Asm
           case AsmJSSimdOperation_notEqual: native = simd_float32x4_notEqual ; break;
           case AsmJSSimdOperation_greaterThan: native = simd_float32x4_greaterThan; break;
           case AsmJSSimdOperation_greaterThanOrEqual: native = simd_float32x4_greaterThanOrEqual ; break;
           case AsmJSSimdOperation_and: native = simd_float32x4_and; break;
           case AsmJSSimdOperation_or: native = simd_float32x4_or; break;
           case AsmJSSimdOperation_xor: native = simd_float32x4_xor; break;
           case AsmJSSimdOperation_select: native = simd_float32x4_select; break;
           case AsmJSSimdOperation_splat: native = simd_float32x4_splat; break;
+          case AsmJSSimdOperation_withX: native = simd_float32x4_withX; break;
+          case AsmJSSimdOperation_withY: native = simd_float32x4_withY; break;
+          case AsmJSSimdOperation_withZ: native = simd_float32x4_withZ; break;
+          case AsmJSSimdOperation_withW: native = simd_float32x4_withW; break;
         }
         break;
     }
     if (!native || !IsNativeFunction(v, native))
         return LinkFail(cx, "bad SIMD.type.* operation");
     return true;
 }
 
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -87,17 +87,21 @@ enum AsmJSSimdOperation
     AsmJSSimdOperation_equal,
     AsmJSSimdOperation_notEqual,
     AsmJSSimdOperation_greaterThan,
     AsmJSSimdOperation_greaterThanOrEqual,
     AsmJSSimdOperation_and,
     AsmJSSimdOperation_or,
     AsmJSSimdOperation_xor,
     AsmJSSimdOperation_select,
-    AsmJSSimdOperation_splat
+    AsmJSSimdOperation_splat,
+    AsmJSSimdOperation_withX,
+    AsmJSSimdOperation_withY,
+    AsmJSSimdOperation_withZ,
+    AsmJSSimdOperation_withW
 };
 
 // These labels describe positions in the prologue/epilogue of functions while
 // compiling an AsmJSModule.
 struct AsmJSFunctionLabels
 {
     AsmJSFunctionLabels(jit::Label &entry, jit::Label &overflowExit)
       : entry(entry), overflowExit(overflowExit) {}
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -1418,17 +1418,21 @@ class MOZ_STACK_CLASS ModuleCompiler
             !addStandardLibrarySimdOpName("greaterThan", AsmJSSimdOperation_greaterThan) ||
             !addStandardLibrarySimdOpName("greaterThanOrEqual", AsmJSSimdOperation_greaterThanOrEqual) ||
             !addStandardLibrarySimdOpName("and", AsmJSSimdOperation_and) ||
             !addStandardLibrarySimdOpName("or", AsmJSSimdOperation_or) ||
             !addStandardLibrarySimdOpName("xor", AsmJSSimdOperation_xor) ||
             !addStandardLibrarySimdOpName("select", AsmJSSimdOperation_select) ||
             !addStandardLibrarySimdOpName("splat", AsmJSSimdOperation_splat) ||
             !addStandardLibrarySimdOpName("max", AsmJSSimdOperation_max) ||
-            !addStandardLibrarySimdOpName("min", AsmJSSimdOperation_min))
+            !addStandardLibrarySimdOpName("min", AsmJSSimdOperation_min) ||
+            !addStandardLibrarySimdOpName("withX", AsmJSSimdOperation_withX) ||
+            !addStandardLibrarySimdOpName("withY", AsmJSSimdOperation_withY) ||
+            !addStandardLibrarySimdOpName("withZ", AsmJSSimdOperation_withZ) ||
+            !addStandardLibrarySimdOpName("withW", AsmJSSimdOperation_withW))
         {
             return false;
         }
 
         uint32_t srcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin;
         uint32_t srcBodyStart = tokenStream().currentToken().pos.end;
 
         // "use strict" should be added to the source if we are in an implicit
@@ -2473,16 +2477,28 @@ class FunctionCompiler
             return nullptr;
 
         JS_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
         MSimdBinaryComp *ins = MSimdBinaryComp::NewAsmJS(alloc(), lhs, rhs, op);
         curBlock_->add(ins);
         return ins;
     }
 
+    MDefinition *insertElementSimd(MDefinition *vec, MDefinition *val, SimdLane lane, MIRType type)
+    {
+        if (inDeadCode())
+            return nullptr;
+
+        MOZ_ASSERT(IsSimdType(vec->type()) && vec->type() == type);
+        MOZ_ASSERT(!IsSimdType(val->type()));
+        MSimdInsertElement *ins = MSimdInsertElement::NewAsmJS(alloc(), vec, val, type, lane);
+        curBlock_->add(ins);
+        return ins;
+    }
+
     MDefinition *ternarySimd(MDefinition *mask, MDefinition *lhs, MDefinition *rhs,
                              MSimdTernaryBitwise::Operation op, MIRType type)
     {
         if (inDeadCode())
             return nullptr;
 
         MOZ_ASSERT(IsSimdType(mask->type()));
         MOZ_ASSERT(mask->type() == MIRType_Int32x4);
@@ -3562,16 +3578,20 @@ IsSimdValidOperationType(AsmJSSimdType t
       case AsmJSSimdOperation_lessThan:
       case AsmJSSimdOperation_equal:
       case AsmJSSimdOperation_greaterThan:
       case AsmJSSimdOperation_and:
       case AsmJSSimdOperation_or:
       case AsmJSSimdOperation_xor:
       case AsmJSSimdOperation_select:
       case AsmJSSimdOperation_splat:
+      case AsmJSSimdOperation_withX:
+      case AsmJSSimdOperation_withY:
+      case AsmJSSimdOperation_withZ:
+      case AsmJSSimdOperation_withW:
         return true;
       case AsmJSSimdOperation_mul:
       case AsmJSSimdOperation_div:
       case AsmJSSimdOperation_max:
       case AsmJSSimdOperation_min:
       case AsmJSSimdOperation_lessThanOrEqual:
       case AsmJSSimdOperation_notEqual:
       case AsmJSSimdOperation_greaterThanOrEqual:
@@ -4348,40 +4368,45 @@ CheckMathMinMax(FunctionCompiler &f, Par
         return f.fail(callNode, "Math.min/max must be passed at least 2 arguments");
 
     ParseNode *firstArg = CallArgList(callNode);
     MDefinition *firstDef;
     Type firstType;
     if (!CheckExpr(f, firstArg, &firstDef, &firstType))
         return false;
 
-    bool opIsDouble = firstType.isMaybeDouble();
-    bool opIsInteger = firstType.isInt();
+    if (firstType.isMaybeDouble()) {
+        *type = MathRetType::Double;
+        firstType = Type::MaybeDouble;
+    } else if (firstType.isMaybeFloat()) {
+        *type = MathRetType::Float;
+        firstType = Type::MaybeFloat;
+    } else if (firstType.isInt()) {
+        *type = MathRetType::Signed;
+        firstType = Type::Int;
+    } else {
+        return f.failf(firstArg, "%s is not a subtype of double?, float? or int",
+                       firstType.toChars());
+    }
+
     MIRType opType = firstType.toMIRType();
-
-    if (!opIsDouble && !opIsInteger)
-        return f.failf(firstArg, "%s is not a subtype of double? or int", firstType.toChars());
-
     MDefinition *lastDef = firstDef;
     ParseNode *nextArg = NextNode(firstArg);
     for (unsigned i = 1; i < CallArgListLength(callNode); i++, nextArg = NextNode(nextArg)) {
         MDefinition *nextDef;
         Type nextType;
         if (!CheckExpr(f, nextArg, &nextDef, &nextType))
             return false;
 
-        if (opIsDouble && !nextType.isMaybeDouble())
-            return f.failf(nextArg, "%s is not a subtype of double?", nextType.toChars());
-        if (opIsInteger && !nextType.isInt())
-            return f.failf(nextArg, "%s is not a subtype of int", nextType.toChars());
+        if (!(nextType <= firstType))
+            return f.failf(nextArg, "%s is not a subtype of %s", nextType.toChars(), firstType.toChars());
 
         lastDef = f.minMax(lastDef, nextDef, opType, isMax);
     }
 
-    *type = MathRetType(opIsDouble ? MathRetType::Double : MathRetType::Signed);
     *def = lastDef;
     return true;
 }
 
 typedef bool (*CheckArgType)(FunctionCompiler &f, ParseNode *argNode, Type type);
 
 static bool
 CheckCallArgs(FunctionCompiler &f, ParseNode *callNode, CheckArgType checkArg,
@@ -4813,16 +4838,45 @@ class CheckSimdSelectArgs
         if (!(actualType <= formalType_)) {
             return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
                            formalType_.toChars());
         }
         return true;
     }
 };
 
+class CheckSimdVectorScalarArgs
+{
+    Type formalType_;
+
+  public:
+    explicit CheckSimdVectorScalarArgs(Type t) : formalType_(t) {}
+
+    bool operator()(FunctionCompiler &f, ParseNode *arg, unsigned argIndex, Type actualType) const
+    {
+        MOZ_ASSERT(argIndex < 2);
+        if (argIndex == 0) {
+            // First argument is the vector
+            if (!(actualType <= formalType_)) {
+                return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
+                               formalType_.toChars());
+            }
+            return true;
+        }
+
+        // Second argument is the scalar
+        Type coercedFormalType = formalType_.simdToCoercedScalarType();
+        if (!(actualType <= coercedFormalType)) {
+            return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
+                           coercedFormalType.toChars());
+        }
+        return true;
+    }
+};
+
 } // anonymous namespace
 
 template<class OpEnum>
 static inline bool
 CheckSimdBinary(FunctionCompiler &f, ParseNode *call, Type retType, OpEnum op, MDefinition **def,
                 Type *type)
 {
     DefinitionVector argDefs;
@@ -4843,16 +4897,28 @@ CheckSimdBinary<MSimdBinaryComp::Operati
     if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(retType), &argDefs))
         return false;
     *def = f.binarySimd(argDefs[0], argDefs[1], op);
     *type = Type::Int32x4;
     return true;
 }
 
 static bool
+CheckSimdWith(FunctionCompiler &f, ParseNode *call, Type retType, SimdLane lane, MDefinition **def,
+              Type *type)
+{
+    DefinitionVector defs;
+    if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(retType), &defs))
+        return false;
+    *def = f.insertElementSimd(defs[0], defs[1], lane, retType.toMIRType());
+    *type = retType;
+    return true;
+}
+
+static bool
 CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
                        MDefinition **def, Type *type)
 {
     MOZ_ASSERT(global->isSimdOperation());
 
     Type retType = global->simdOperationType();
 
     switch (global->simdOperation()) {
@@ -4884,16 +4950,25 @@ CheckSimdOperationCall(FunctionCompiler 
 
       case AsmJSSimdOperation_and:
         return CheckSimdBinary(f, call, retType, MSimdBinaryBitwise::and_, def, type);
       case AsmJSSimdOperation_or:
         return CheckSimdBinary(f, call, retType, MSimdBinaryBitwise::or_, def, type);
       case AsmJSSimdOperation_xor:
         return CheckSimdBinary(f, call, retType, MSimdBinaryBitwise::xor_, def, type);
 
+      case AsmJSSimdOperation_withX:
+        return CheckSimdWith(f, call, retType, SimdLane::LaneX, def, type);
+      case AsmJSSimdOperation_withY:
+        return CheckSimdWith(f, call, retType, SimdLane::LaneY, def, type);
+      case AsmJSSimdOperation_withZ:
+        return CheckSimdWith(f, call, retType, SimdLane::LaneZ, def, type);
+      case AsmJSSimdOperation_withW:
+        return CheckSimdWith(f, call, retType, SimdLane::LaneW, def, type);
+
       case AsmJSSimdOperation_splat: {
         DefinitionVector defs;
         Type formalType = retType.simdToCoercedScalarType();
         if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(formalType), &defs))
             return false;
         *def = f.splatSimd(defs[0], retType.toMIRType());
         *type = retType;
         return true;
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -217,36 +217,49 @@ GC(JSContext *cx, unsigned argc, jsval *
 
     /*
      * If the first argument is 'compartment', we collect any compartments
      * previously scheduled for GC via schedulegc. If the first argument is an
      * object, we collect the object's compartment (and any other compartments
      * scheduled for GC). Otherwise, we collect all compartments.
      */
     bool compartment = false;
-    if (args.length() == 1) {
+    if (args.length() >= 1) {
         Value arg = args[0];
         if (arg.isString()) {
             if (!JS_StringEqualsAscii(cx, arg.toString(), "compartment", &compartment))
                 return false;
         } else if (arg.isObject()) {
             PrepareZoneForGC(UncheckedUnwrap(&arg.toObject())->zone());
             compartment = true;
         }
     }
 
+    bool shrinking = false;
+    if (args.length() >= 2) {
+        Value arg = args[1];
+        if (arg.isString()) {
+            if (!JS_StringEqualsAscii(cx, arg.toString(), "shrinking", &shrinking))
+                return false;
+        }
+    }
+
 #ifndef JS_MORE_DETERMINISTIC
     size_t preBytes = cx->runtime()->gc.usage.gcBytes();
 #endif
 
     if (compartment)
         PrepareForDebugGC(cx->runtime());
     else
         PrepareForFullGC(cx->runtime());
-    GCForReason(cx->runtime(), gcreason::API);
+
+    if (shrinking)
+        ShrinkingGC(cx->runtime(), gcreason::API);
+    else
+        GCForReason(cx->runtime(), gcreason::API);
 
     char buf[256] = { '\0' };
 #ifndef JS_MORE_DETERMINISTIC
     JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n",
                 (unsigned long)preBytes, (unsigned long)cx->runtime()->gc.usage.gcBytes());
 #endif
     JSString *str = JS_NewStringCopyZ(cx, buf);
     if (!str)
@@ -1996,20 +2009,22 @@ IsSimdAvailable(JSContext *cx, unsigned 
     bool available = cx->jitSupportsSimd();
 #endif
     args.rval().set(BooleanValue(available));
     return true;
 }
 
 static const JSFunctionSpecWithHelp TestingFunctions[] = {
     JS_FN_HELP("gc", ::GC, 0, 0,
-"gc([obj] | 'compartment')",
+"gc([obj] | 'compartment' [, 'shrinking'])",
 "  Run the garbage collector. When obj is given, GC only its compartment.\n"
 "  If 'compartment' is given, GC any compartments that were scheduled for\n"
-"  GC via schedulegc."),
+"  GC via schedulegc.\n"
+"  If 'shrinking' is passes as the optional second argument, perform a\n"
+"  shrinking GC rather than a normal GC."),
 
     JS_FN_HELP("minorgc", ::MinorGC, 0, 0,
 "minorgc([aboutToOverflow])",
 "  Run a minor collector on the Nursery. When aboutToOverflow is true, marks\n"
 "  the store buffer as about-to-overflow before collecting."),
 
     JS_FN_HELP("gcparam", GCParameter, 2, 0,
 "gcparam(name [, value])",
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2885,48 +2885,16 @@ js::ClampToUint8(ThreadSafeContext *, un
     args.rval().setNumber(ClampDoubleToUint8(args[0].toNumber()));
     return true;
 }
 
 JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::ClampToUint8JitInfo, ClampToUint8JitInfo,
                                       js::ClampToUint8);
 
 bool
-js::Memcpy(ThreadSafeContext *, unsigned argc, Value *vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    JS_ASSERT(args.length() == 5);
-    JS_ASSERT(args[0].isObject() && args[0].toObject().is<TypedObject>());
-    JS_ASSERT(args[1].isInt32());
-    JS_ASSERT(args[2].isObject() && args[2].toObject().is<TypedObject>());
-    JS_ASSERT(args[3].isInt32());
-    JS_ASSERT(args[4].isInt32());
-
-    TypedObject &targetTypedObj = args[0].toObject().as<TypedObject>();
-    int32_t targetOffset = args[1].toInt32();
-    TypedObject &sourceTypedObj = args[2].toObject().as<TypedObject>();
-    int32_t sourceOffset = args[3].toInt32();
-    int32_t size = args[4].toInt32();
-
-    JS_ASSERT(targetOffset >= 0);
-    JS_ASSERT(sourceOffset >= 0);
-    JS_ASSERT(size >= 0);
-    JS_ASSERT(size + targetOffset <= targetTypedObj.size());
-    JS_ASSERT(size + sourceOffset <= sourceTypedObj.size());
-
-    uint8_t *target = targetTypedObj.typedMem(targetOffset);
-    uint8_t *source = sourceTypedObj.typedMem(sourceOffset);
-    memcpy(target, source, size);
-    args.rval().setUndefined();
-    return true;
-}
-
-JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::MemcpyJitInfo, MemcpyJitInfo, js::Memcpy);
-
-bool
 js::GetTypedObjectModule(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     Rooted<GlobalObject*> global(cx, cx->global());
     JS_ASSERT(global);
     args.rval().setObject(global->getTypedObjectModule());
     return true;
 }
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -847,30 +847,16 @@ extern const JSJitInfo TypedObjectIsAtta
  * Usage: ClampToUint8(v)
  *
  * Same as the C function ClampDoubleToUint8. `v` must be a number.
  */
 bool ClampToUint8(ThreadSafeContext *cx, unsigned argc, Value *vp);
 extern const JSJitInfo ClampToUint8JitInfo;
 
 /*
- * Usage: Memcpy(targetDatum, targetOffset,
- *               sourceDatum, sourceOffset,
- *               size)
- *
- * Intrinsic function. Copies size bytes from the data for
- * `sourceDatum` at `sourceOffset` into the data for
- * `targetDatum` at `targetOffset`.
- *
- * Both `sourceDatum` and `targetDatum` must be attached.
- */
-bool Memcpy(ThreadSafeContext *cx, unsigned argc, Value *vp);
-extern const JSJitInfo MemcpyJitInfo;
-
-/*
  * Usage: GetTypedObjectModule()
  *
  * Returns the global "typed object" module, which provides access
  * to the various builtin type descriptors. These are currently
  * exported as immutable properties so it is safe for self-hosted code
  * to access them; eventually this should be linked into the module
  * system.
  */
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -190,30 +190,16 @@ function TypedObjectGetSimd(descr, typed
 
 // Writes `fromValue` into the `typedObj` at offset `offset`, adapting
 // it to `descr` as needed. This is the most general entry point
 // and works for any type.
 function TypedObjectSet(descr, typedObj, offset, fromValue) {
   if (!TypedObjectIsAttached(typedObj))
     ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
 
-  // Fast path: `fromValue` is a typed object with same type
-  // representation as the destination. In that case, we can just do a
-  // memcpy.
-  if (IsObject(fromValue) && ObjectIsTypedObject(fromValue)) {
-    if (!descr.variable && DescrsEquiv(descr, TypedObjectTypeDescr(fromValue))) {
-      if (!TypedObjectIsAttached(fromValue))
-        ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
-
-      var size = DESCR_SIZE(descr);
-      Memcpy(typedObj, offset, fromValue, 0, size);
-      return;
-    }
-  }
-
   switch (DESCR_KIND(descr)) {
   case JS_TYPEREPR_SCALAR_KIND:
     TypedObjectSetScalar(descr, typedObj, offset, fromValue);
     return;
 
   case JS_TYPEREPR_REFERENCE_KIND:
     TypedObjectSetReference(descr, typedObj, offset, fromValue);
     return;
@@ -338,23 +324,43 @@ function TypedObjectSetReference(descr, 
   }
 
   assert(false, "Unhandled scalar type: " + type);
   return undefined;
 }
 
 // Sets `fromValue` to `this` assuming that `this` is a scalar type.
 function TypedObjectSetSimd(descr, typedObj, offset, fromValue) {
-  // It is only permitted to set a float32x4/int32x4 value from another
-  // float32x4/int32x4; in that case, the "fast path" that uses memcopy will
-  // have already matched. So if we get to this point, we're supposed
-  // to "adapt" fromValue, but there are no legal adaptions.
-  ThrowError(JSMSG_CANT_CONVERT_TO,
-             typeof(fromValue),
-             DESCR_STRING_REPR(descr));
+  if (!IsObject(fromValue) || !ObjectIsTypedObject(fromValue))
+    ThrowError(JSMSG_CANT_CONVERT_TO,
+               typeof(fromValue),
+               DESCR_STRING_REPR(descr));
+
+  if (!DescrsEquiv(descr, TypedObjectTypeDescr(fromValue)))
+    ThrowError(JSMSG_CANT_CONVERT_TO,
+               typeof(fromValue),
+               DESCR_STRING_REPR(descr));
+
+  var type = DESCR_TYPE(descr);
+  switch (type) {
+    case JS_SIMDTYPEREPR_FLOAT32:
+      Store_float32(typedObj, offset + 0, Load_float32(fromValue, 0));
+      Store_float32(typedObj, offset + 4, Load_float32(fromValue, 4));
+      Store_float32(typedObj, offset + 8, Load_float32(fromValue, 8));
+      Store_float32(typedObj, offset + 12, Load_float32(fromValue, 12));
+      break;
+    case JS_SIMDTYPEREPR_INT32:
+      Store_int32(typedObj, offset + 0, Load_int32(fromValue, 0));
+      Store_int32(typedObj, offset + 4, Load_int32(fromValue, 4));
+      Store_int32(typedObj, offset + 8, Load_int32(fromValue, 8));
+      Store_int32(typedObj, offset + 12, Load_int32(fromValue, 12));
+      break;
+    default:
+      assert(false, "Unhandled Simd type: " + type);
+  }
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // C++ Wrappers
 //
 // These helpers are invoked by C++ code or used as method bodies.
 
 // Wrapper for use from C++ code.
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -217,16 +217,17 @@ function isRootedPointerTypeName(name)
         return /\(js::AllowGC\)1u>::RootType/.test(name);
 
     return name.startsWith('Rooted') || name.startsWith('PersistentRooted');
 }
 
 function isSuppressConstructor(name)
 {
     return name.indexOf("::AutoSuppressGC") != -1
+        || name.indexOf("::AutoAssertGCCallback") != -1
         || name.indexOf("::AutoEnterAnalysis") != -1
         || name.indexOf("::AutoSuppressGCAnalysis") != -1
         || name.indexOf("::AutoIgnoreRootingHazards") != -1;
 }
 
 // nsISupports subclasses' methods may be scriptable (or overridden
 // via binary XPCOM), and so may GC. But some fields just aren't going
 // to get overridden with something that can GC.
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -133,17 +133,17 @@ struct AutoStopVerifyingBarriers
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 void
 CheckHashTablesAfterMovingGC(JSRuntime *rt);
 #endif
 
 #ifdef JSGC_COMPACTING
 struct MovingTracer : JSTracer {
-    MovingTracer(JSRuntime *rt) : JSTracer(rt, Visit, TraceWeakMapValues) {}
+    MovingTracer(JSRuntime *rt) : JSTracer(rt, Visit, TraceWeakMapKeysValues) {}
 
     static void Visit(JSTracer *jstrc, void **thingp, JSGCTraceKind kind);
     static void Sweep(JSTracer *jstrc);
     static bool IsMovingTracer(JSTracer *trc) {
         return trc->callback == Visit;
     }
 };
 #endif
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -619,16 +619,18 @@ struct ArenaHeader : public JS::shadow::
 
     inline ArenaHeader *getNextDelayedMarking() const;
     inline void setNextDelayedMarking(ArenaHeader *aheader);
     inline void unsetDelayedMarking();
 
     inline ArenaHeader *getNextAllocDuringSweep() const;
     inline void setNextAllocDuringSweep(ArenaHeader *aheader);
     inline void unsetAllocDuringSweep();
+
+    void unmarkAll();
 };
 
 struct Arena
 {
     /*
      * Layout of an arena:
      * An arena is 4K in size and 4K-aligned. It starts with the ArenaHeader
      * descriptor followed by some pad bytes. The remainder of the arena is
--- a/js/src/jit-test/tests/asm.js/testMathLib.js
+++ b/js/src/jit-test/tests/asm.js/testMathLib.js
@@ -61,62 +61,68 @@ var f = asmLink(asmCompile('glob', USE_A
 for (n of [-Math.pow(2,31)-1, -Math.pow(2,31), -Math.pow(2,31)+1, -1, 0, 1, Math.pow(2,31)-2, Math.pow(2,31)-1, Math.pow(2,31)])
     assertEq(f(n), Math.abs(n|0)|0);
 
 var f = asmLink(asmCompile('glob', USE_ASM + 'var clz32=glob.Math.clz32; function f(i) { i=i|0; return clz32(i)|0 } return f'), this);
 for (n of [0, 1, 2, 15, 16, Math.pow(2,31)-1, Math.pow(2,31), Math.pow(2,31)+1, Math.pow(2,32)-1, Math.pow(2,32), Math.pow(2,32)+1])
     assertEq(f(n), Math.clz32(n|0));
 
 var doubleNumbers = [NaN, Infinity, -Infinity, -10000, -3.4, -0, 0, 3.4, 10000];
+var floatNumbers = [];
+for (var x of doubleNumbers) floatNumbers.push(Math.fround(x));
 var intNumbers = [-10000, -3, -1, 0, 3, 10000];
+
 function testBinary(f, g, numbers) {
     for (n of numbers)
         for (o of numbers)
             assertEq(f(n,o), g(n,o));
 }
 
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var po=glob.Math.pow; function f(d,e) { d=+d;e=+e; return +po(d,e) } return f'), {Math:{pow:Math.sin}});
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var po=glob.Math.pow; function f(d,e) { d=+d;e=+e; return +po(d,e) } return f'), {Math:{pow:null}});
 testBinary(asmLink(asmCompile('glob', USE_ASM + 'var po=glob.Math.pow; function f(d,e) { d=+d;e=+e; return +po(d,e) } return f'), {Math:{pow:Math.pow}}), Math.pow, doubleNumbers);
 
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var at=glob.Math.atan2; function f(d,e) { d=+d;e=+e; return +at(d,e) } return f'), {Math:{atan2:Math.sin}});
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var at=glob.Math.atan2; function f(d,e) { d=+d;e=+e; return +at(d,e) } return f'), {Math:{atan2:null}});
 testBinary(asmLink(asmCompile('glob', USE_ASM + 'var at=glob.Math.atan2; function f(d,e) { d=+d;e=+e; return +at(d,e) } return f'), {Math:{atan2:Math.atan2}}), Math.atan2, doubleNumbers);
 
 assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(d) { d=+d; return +min(d) } return f');
-assertAsmTypeFail('glob', USE_ASM + 'var f32=glob.Math.fround; var min=glob.Math.min; function f(d) { d=f32(d); return +min(d, f32(5)) } return f');
 assertAsmTypeFail('glob', 'ffi', 'heap', USE_ASM + 'var i32=new glob.Int32Array(heap); var min=glob.Math.min; function f() { return min(i32[0], 5)|0 } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(x) { x=x|0; return min(3 + x, 5)|0 } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(x) { x=x|0; return min(5, 3 + x)|0 } return f');
 
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=+d;e=+e; return +min(d,e) } return f'), {Math:{min:Math.sin}});
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=+d;e=+e; return +min(d,e) } return f'), {Math:{min:null}});
 testBinary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=+d;e=+e; return +min(d,e) } return f'), {Math:{min:Math.min}}), Math.min, doubleNumbers);
+testBinary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; var f32=glob.Math.fround; function f(d,e) { d=f32(d);e=f32(e); return f32(min(d,e)) } return f'), this), Math.min, floatNumbers);
 testBinary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e) { d=d|0;e=e|0; return min(d,e)|0} return f'), {Math:{min:Math.min}}), Math.min, intNumbers);
 
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=+d;e=+e; return +max(d,e) } return f'), {Math:{max:Math.sin}});
 assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=+d;e=+e; return +max(d,e) } return f'), {Math:{max:null}});
 testBinary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=+d;e=+e; return +max(d,e) } return f'), {Math:{max:Math.max}}), Math.max, doubleNumbers);
+testBinary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; var f32=glob.Math.fround; function f(d,e) { d=f32(d);e=f32(e); return f32(max(d,e)) } return f'), this), Math.max, floatNumbers);
 testBinary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e) { d=d|0;e=e|0; return max(d,e)|0} return f'), {Math:{max:Math.max}}), Math.max, intNumbers);
 
 function testTernary(f, g, numbers) {
     for (n of numbers)
         for (o of numbers)
             for (p of numbers)
                 assertEq(f(n,o,p), g(n,o,p));
 }
 
 assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=+d;e=+e;g=g|0; return +min(d,e,g) } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=d|0;e=e|0;g=+g; return max(d,e,g)|0 } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=+d;e=+e;g=+g; return min(d,e,g)|0 } return f');
 testTernary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=d|0;e=e|0;g=g|0; return +max(d,e,g) } return f'), {Math:{max:Math.max}}), Math.max, intNumbers);
 testTernary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=d|0;e=e|0;g=g|0; return max(d,e,g)|0 } return f'), {Math:{max:Math.max}}), Math.max, intNumbers);
 testTernary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d,e,g) { d=+d;e=+e;g=+g; return +max(d,e,g) } return f'), {Math:{max:Math.max}}), Math.max, doubleNumbers);
+testTernary(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; var _=glob.Math.fround; function f(d,e,g) { d=_(d);e=_(e);g=_(g); return _(max(d,e,g)) } return f'), this), Math.max, floatNumbers);
 testTernary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=d|0;e=e|0;g=g|0; return min(d,e,g)|0 } return f'), {Math:{min:Math.min}}), Math.min, intNumbers);
 testTernary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d,e,g) { d=+d;e=+e;g=+g; return +min(d,e,g) } return f'), {Math:{min:Math.min}}), Math.min, doubleNumbers);
+testTernary(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; var _=glob.Math.fround; function f(d,e,g) { d=_(d);e=_(e);g=_(g); return _(min(d,e,g)) } return f'), this), Math.min, floatNumbers);
 
 // Implicit return coercions of math functions
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var im=glob.Math.imul; function f(i) { i=i|0; i = im(i,i); return i|0 } return f'), this)(3), 9);
 assertAsmTypeFail('glob', USE_ASM + 'var im=glob.Math.imul; function f(d) { d=+d; d = im(d, d) } return f');
 assertAsmTypeFail('glob', USE_ASM + FROUND + 'var im=glob.Math.imul; function f(d) { d=fround(d); d = im(d, d) } return f');
 
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var abs=glob.Math.abs; function f(d) { d=d|0; d = abs(d|0); return +(d>>>0) } return f'), this)(-1), 1);
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var abs=glob.Math.abs; function f(d) { d=d|0; var m = 0; m = (-1)>>>0; return (abs(d|0) < (m>>>0))|0 } return f'), this)(42), 1);
@@ -129,17 +135,17 @@ assertEq(asmLink(asmCompile('glob', USE_
 assertEq(asmLink(asmCompile('glob', USE_ASM + FROUND + 'var sqrt=glob.Math.sqrt; function f(d) { d=fround(d); d = fround(sqrt(d)); return +d } return f'), this)(13.37), Math.fround(Math.sqrt(Math.fround(13.37))));
 assertAsmTypeFail('glob', USE_ASM + FROUND + 'var sqrt=glob.Math.sqrt; function f(d) { d=fround(d); d = sqrt(d); return fround(d) } return f');
 assertAsmTypeFail('glob', USE_ASM + FROUND + 'var sqrt=glob.Math.sqrt; function f(d) { d=fround(d); d = sqrt(d); return d } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var sqrt=glob.Math.sqrt; function f(n) { n=n|0; var d=0.; d = sqrt(n|0) } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var sqrt=glob.Math.sqrt; function f(n) { n=n|0; var d=3.; n = sqrt(d)|0 } return f');
 
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d) { d=+d; d = min(d, 13.); return +d } return f'), this)(12), 12);
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d) { d=d|0; d = min(d, 11); return d|0 } return f'), this)(12), 11);
-assertAsmTypeFail('glob', USE_ASM + FROUND + 'var max=glob.Math.max; function f(d) { d=fround(d); d = max(d) } return f');
+assertEq(asmLink(asmCompile('glob', USE_ASM + FROUND + 'var min=glob.Math.min; function f(d) { d=fround(d); d = min(d, fround(13.37)); return fround(d) } return f'), this)(14), Math.fround(13.37));
 
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var sin=glob.Math.sin; function f(d) { d=+d; d = sin(d); return +d } return f'), this)(Math.PI), Math.sin(Math.PI));
 assertAsmTypeFail('glob', USE_ASM + FROUND + 'var sin=glob.Math.sin; function f(d) { d=fround(d); d = sin(d) } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var sin=glob.Math.sin; function f(d) { d=d|0; d = sin(d) } return f');
 
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var pow=glob.Math.pow; function f(d) { d=+d; d = pow(d,d); return +d } return f'), this)(3), 27);
 assertAsmTypeFail('glob', USE_ASM + FROUND + 'var pow=glob.Math.pow; function f(d) { d=fround(d); d = pow(d, d) } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var pow=glob.Math.pow; function f(d) { d=d|0; d = pow(d, d) } return f');
@@ -148,19 +154,23 @@ assertAsmTypeFail('glob', USE_ASM + 'var
 assertAsmTypeFail('glob', USE_ASM + 'var pow=glob.Math.pow; function f(d) { d=+d; var i=0; i = pow(d,d)|0; } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var atan2=glob.Math.atan2; function f(d) { d=+d; var i=0; i = atan2(d,d)|0; } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var sqrt=glob.Math.sqrt; function f(d) { d=+d; sqrt(d)|0; } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var abs=glob.Math.abs; function f(d) { d=+d; abs(d)|0; } return f');
 
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var im=glob.Math.imul; function f(i) { i=i|0; var d=0.0; d = +im(i,i); return +d } return f'), this)(42), Math.imul(42, 42));
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var abs=glob.Math.abs; function f(i) { i=i|0; var d=0.0; d = +abs(i|0); return +d } return f'), this)(-42), 42);
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(i) { i=i|0; var d=0.0; d = +min(i, 0); return +d } return f'), this)(-42), -42);
+assertEq(asmLink(asmCompile('glob', USE_ASM + FROUND + 'var min=glob.Math.min; function f(i) { i=i|0; var d=fround(0); d = fround(min(i, 0)); return +d } return f'), this)(-42), -42);
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(i) { i=i|0; var d=0.0; d = +max(i, 0); return +d } return f'), this)(-42), 0);
+assertEq(asmLink(asmCompile('glob', USE_ASM + FROUND + 'var max=glob.Math.max; function f(i) { i=i|0; var d=fround(0); d = fround(max(i, 0)); return +d } return f'), this)(-42), 0);
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var min=glob.Math.min; function f(d) { d=+d; var i=0; i = ~~min(d, 0.)|0; return i|0 } return f'), this)(-42), -42);
+assertEq(asmLink(asmCompile('glob', USE_ASM + FROUND + 'var min=glob.Math.min; function f(d) { d=fround(d); var i=0; i = ~~min(d, fround(0))|0; return i|0 } return f'), this)(-42), -42);
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var max=glob.Math.max; function f(d) { d=+d; var i=0; i = ~~max(d, 0.)|0; return i|0 } return f'), this)(-42), 0);
+assertEq(asmLink(asmCompile('glob', USE_ASM + FROUND + 'var max=glob.Math.max; function f(d) { d=fround(d); var i=0; i = ~~max(d, fround(0))|0; return i|0 } return f'), this)(-42), 0);
 
 assertEq(asmLink(asmCompile('glob', USE_ASM + 'var abs=glob.Math.abs; function f(i) { i=i|0; var d=0.0; return +d; +abs(i|0); return 3.0;} return f'), this)(-42), 0);
 
 assertAsmTypeFail('glob', USE_ASM + 'var tau=glob.Math.TAU; function f() {} return f');
 assertAsmTypeFail('glob', USE_ASM + 'var pi=glob.Math.PI; function f() { return pi | 0 } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var pi=glob.Math.PI; function f() { return +pi() } return f');
 assertAsmTypeFail('glob', USE_ASM + 'var pi=glob.Math.PI; function f() { pi = +3; } return f');
 assertAsmLinkAlwaysFail(asmCompile('glob', USE_ASM + 'var pi=glob.Math.PI; function f() {} return f'), {});
--- a/js/src/jit-test/tests/asm.js/testSIMD.js
+++ b/js/src/jit-test/tests/asm.js/testSIMD.js
@@ -472,16 +472,45 @@ CheckF4(F32D, 'var x=f4(1,2,3,4); x=f4d(
 CheckF4(F32D, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4d(x,y)', [1/4,2/3,3/5,2]);
 CheckF4(F32D, 'var x=f4(13.37,1,1,4); var y=f4(4,0,-0.,2); x=f4d(x,y)', [Math.fround(13.37) / 4,+Infinity,-Infinity,2]);
 
 // Test NaN
 var f32x4 = SIMD.float32x4(0, 0, -0, NaN);
 var another = SIMD.float32x4(0, -0, 0, 0);
 assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32D + "function f(x,y) {x=f4(x); y=f4(y); x=f4d(x,y); return f4(x);} return f"), this)(f32x4, another), [NaN, NaN, NaN, NaN]);
 
+// With
+const WXF = 'var w = f4.withX;';
+const WYF = 'var w = f4.withY;';
+const WZF = 'var w = f4.withZ;';
+const WWF = 'var w = f4.withW;';
+
+assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, 1);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, 1.0);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, x);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1, f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1., f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(f32(1), f32(1));} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); var y = i4(1,2,3,4); x = w(y, f32(1));} return f");
+
+CheckF4(WXF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [Math.fround(13.37), 2, 3, 4]);
+CheckF4(WYF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, Math.fround(13.37), 3, 4]);
+CheckF4(WZF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, Math.fround(13.37), 4]);
+CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, 3, Math.fround(13.37)]);
+CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37) + f32(6.63));', [1, 2, 3, Math.fround(Math.fround(13.37) + Math.fround(6.63))]);
+
+const WXI = 'var w = i4.withX;';
+const WYI = 'var w = i4.withY;';
+const WZI = 'var w = i4.withZ;';
+const WWI = 'var w = i4.withW;';
+CheckI4(WXI, 'var x = i4(1,2,3,4); x = w(x, 42);', [42, 2, 3, 4]);
+CheckI4(WYI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 42, 3, 4]);
+CheckI4(WZI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 2, 42, 4]);
+CheckI4(WWI, 'var x = i4(1,2,3,4); x = w(x, 42);', [1, 2, 3, 42]);
+
 // Comparisons
 // True yields all bits set to 1 (i.e as an int32, 0xFFFFFFFF === -1), false
 // yields all bits set to 0 (i.e 0).
 const T = -1;
 const F = 0;
 assertAsmTypeFail('glob', USE_ASM + I32 + "var lt=i4.lessThanOrEqual; function f() {} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "var ge=i4.greaterThanOrEqual; function f() {} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "var ne=i4.notEqual; function f() {} return f");
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -456,16 +456,24 @@ function rpowhalf_object(i) {
 var uceFault_min_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_min_number'));
 function rmin_number(i) {
     var x = Math.min(i, i-1, i-2.1);
     if (uceFault_min_number(i) || uceFault_min_number(i))
         assertEq(x, i-2.1);
     return i;
 }
 
+var uceFault_min_float = eval(uneval(uceFault).replace('uceFault', 'uceFault_min_float'));
+function rmin_float(i) {
+    var x = Math.fround(Math.min(Math.fround(20), Math.fround(13.37)));
+    if (uceFault_min_number(i) || uceFault_min_number(i))
+        assertEq(x, Math.fround(13.37));
+    return i;
+}
+
 var uceFault_min_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_min_object'));
 function rmin_object(i) {
     var t = i;
     var o = { valueOf: function () { return t; } };
     var x = Math.min(o, o-1, o-2.1)
     t = 1000;
     if (uceFault_min_object(i) || uceFault_min_object(i))
         assertEq(x, i-2.1);
@@ -475,16 +483,24 @@ function rmin_object(i) {
 var uceFault_max_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_max_number'));
 function rmax_number(i) {
     var x = Math.max(i, i-1, i-2.1);
     if (uceFault_max_number(i) || uceFault_max_number(i))
         assertEq(x, i);
     return i;
 }
 
+var uceFault_max_float = eval(uneval(uceFault).replace('uceFault', 'uceFault_max_float'));
+function rmax_float(i) {
+    var x = Math.fround(Math.max(Math.fround(2), Math.fround(13.37)));
+    if (uceFault_max_number(i) || uceFault_max_number(i))
+        assertEq(x, Math.fround(13.37));
+    return i;
+}
+
 var uceFault_max_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_max_object'));
 function rmax_object(i) {
     var t = i;
     var o = { valueOf: function () { return t; } };
     var x = Math.max(o, o-1, o-2.1)
     t = 1000;
     if (uceFault_max_object(i) || uceFault_max_object(i))
         assertEq(x, i);
@@ -970,18 +986,20 @@ for (i = 0; i < 100; i++) {
     rcharCodeAt(i);
     rfrom_char_code(i);
     rfrom_char_code_non_ascii(i);
     rpow_number(i);
     rpow_object(i);
     rpowhalf_number(i);
     rpowhalf_object(i);
     rmin_number(i);
+    rmin_float(i);
     rmin_object(i);
     rmax_number(i);
+    rmax_float(i);
     rmax_object(i);
     rabs_number(i);
     rabs_object(i);
     rsqrt_number(i);
     rsqrt_float(i);
     rsqrt_object(i);
     ratan2_number(i);
     ratan2_object(i);
--- a/js/src/jit-test/tests/ion/testFloat32-correctness.js
+++ b/js/src/jit-test/tests/ion/testFloat32-correctness.js
@@ -84,16 +84,48 @@ function sqrt() {
     for(var i = 0; i < 7; ++i) {
         var sqrtf = Math.fround(Math.sqrt(f32[i]));
         var sqrtd = 1 + Math.sqrt(f32[i]) - 1; // force no float32 by chaining arith ops
         assertEq( sqrtf, Math.fround(sqrtd) );
     }
 }
 test(setupSqrt, sqrt);
 
+// MMinMax
+function setupMinMax() {
+    f32[0] = -0;
+    f32[1] = 0;
+    f32[2] = 1;
+    f32[3] = 4;
+    f32[4] = -1;
+    f32[5] = Infinity;
+    f32[6] = NaN;
+    f32[7] = 13.37;
+    f32[8] = -Infinity;
+    f32[9] = Math.pow(2,31) - 1;
+}
+function minMax() {
+    for(var i = 0; i < 9; ++i) {
+        for(var j = 0; j < 9; j++) {
+            var minf = Math.fround(Math.min(f32[i], f32[j]));
+            var mind = 1 / (1 / Math.min(f32[i], f32[j])); // force no float32 by chaining arith ops
+            assertFloat32(minf, true);
+            assertFloat32(mind, false);
+            assertEq( minf, Math.fround(mind) );
+
+            var maxf = Math.fround(Math.max(f32[i], f32[j]));
+            var maxd = 1 / (1 / Math.max(f32[i], f32[j])); // force no float32 by chaining arith ops
+            assertFloat32(maxf, true);
+            assertFloat32(maxd, false);
+            assertEq( maxf, Math.fround(maxd) );
+        }
+    }
+}
+test(setupMinMax, minMax);
+
 // MTruncateToInt32
 // The only way to get a MTruncateToInt32 with a Float32 input is to use Math.imul
 function setupTruncateToInt32() {
     f32[0] = -1;
     f32[1] = 4;
     f32[2] = 5.13;
 }
 function truncateToInt32() {
--- a/js/src/jit-test/tests/ion/testFloat32.js
+++ b/js/src/jit-test/tests/ion/testFloat32.js
@@ -56,18 +56,18 @@
 setJitCompilerOption("ion.warmup.trigger", 50);
 
 function test(f) {
     f32[0] = .5;
     for(var n = 110; n; n--)
         f();
 }
 
-var f32 = new Float32Array(2);
-var f64 = new Float64Array(2);
+var f32 = new Float32Array(4);
+var f64 = new Float64Array(4);
 
 function acceptAdd() {
     var use = f32[0] + 1;
     assertFloat32(use, true);
     f32[0] = use;
 }
 test(acceptAdd);
 
@@ -146,16 +146,89 @@ test(acceptSqrt);
 
 function refuseSqrt() {
     var res = Math.sqrt(f32[0]);
     assertFloat32(res, false);
     f32[0] = res + 1;
 }
 test(refuseSqrt);
 
+function acceptMin() {
+    var res = Math.min(f32[0], f32[1]);
+    assertFloat32(res, true);
+    f64[0] = res;
+}
+test(acceptMin);
+
+// In theory, we could do it, as Math.min/max actually behave as a Phi (it's a
+// float32 producer iff its inputs are producers, it's a consumer iff its uses
+// are consumers). In practice, this would involve some overhead for big chains
+// of min/max.
+function refuseMinAdd() {
+    var res = Math.min(f32[0], f32[1]) + f32[2];
+    assertFloat32(res, false);
+    f32[3] = res;
+}
+test(refuseMinAdd);
+
+function acceptSeveralMinMax() {
+    var x = Math.min(f32[0], f32[1]);
+    var y = Math.max(f32[2], f32[3]);
+    var res = Math.min(x, y);
+    assertFloat32(res, true);
+    f64[0] = res;
+}
+test(acceptSeveralMinMax);
+
+function acceptSeveralMinMax2() {
+    var res = Math.min(f32[0], f32[1], f32[2], f32[3]);
+    assertFloat32(res, true);
+    f64[0] = res;
+}
+test(acceptSeveralMinMax2);
+
+function partialMinMax() {
+    var x = Math.min(f32[0], f32[1]);
+    var y = Math.min(f64[0], f32[1]);
+    var res  = Math.min(x, y);
+    assertFloat32(x, true);
+    assertFloat32(y, false);
+    assertFloat32(res, false);
+    f64[0] = res;
+}
+test(partialMinMax);
+
+function refuseSeveralMinMax() {
+    var res = Math.min(f32[0], f32[1] + f32[2], f32[2], f32[3]);
+    assertFloat32(res, false);
+    f64[0] = res;
+}
+test(refuseSeveralMinMax);
+
+function refuseMin() {
+    var res = Math.min(f32[0], 42.13 + f32[1]);
+    assertFloat32(res, false);
+    f64[0] = res;
+}
+test(refuseMin);
+
+function acceptMax() {
+    var res = Math.max(f32[0], f32[1]);
+    assertFloat32(res, true);
+    f64[0] = res;
+}
+test(acceptMax);
+
+function refuseMax() {
+    var res = Math.max(f32[0], 42.13 + f32[1]);
+    assertFloat32(res, false);
+    f64[0] = res;
+}
+test(refuseMax);
+
 function acceptAbs() {
     var res = Math.abs(f32[0]);
     assertFloat32(res, true);
     f32[0] = res;
 }
 test(acceptAbs);
 
 function refuseAbs() {
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -1,118 +1,148 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/JitOptions.h"
+#include "mozilla/TypeTraits.h"
 
+#include <cstdlib>
 #include "jsfun.h"
-
 using namespace js;
 using namespace js::jit;
 
 namespace js {
 namespace jit {
 
 JitOptions js_JitOptions;
 
+template<typename T> struct IsBool : mozilla::FalseType {};
+template<> struct IsBool<bool> : mozilla::TrueType {};
+
+template<typename T>
+T overrideDefault(const char *param, T dflt) {
+    char *str = getenv(param);
+    if (!str)
+        return dflt;
+    if (IsBool<T>::value) {
+        if (strcmp(str, "true") == 0 ||
+            strcmp(str, "yes")) {
+            return true;
+        }
+        if (strcmp(str, "false") == 0 ||
+            strcmp(str, "no")) {
+            return false;
+        }
+        fprintf(stderr, "Warning: I didn't understand %s=\"%s\"", param, str);
+    } else {
+        char *endp;
+        int retval = strtol(str, &endp, 0);
+        if (*endp == '\0')
+            return retval;
+
+        fprintf(stderr, "Warning: I didn't understand %s=\"%s\"", param, str);
+    }
+    return dflt;
+}
+#define SET_DEFAULT(var, dflt) var = overrideDefault("JIT_OPTION_" #var, dflt)
 JitOptions::JitOptions()
 {
     // Whether to perform expensive graph-consistency DEBUG-only assertions.
     // It can be useful to disable this to reduce DEBUG-compile time of large
     // asm.js programs.
-    checkGraphConsistency = true;
+    SET_DEFAULT(checkGraphConsistency, true);
 
 #ifdef CHECK_OSIPOINT_REGISTERS
     // Emit extra code to verify live regs at the start of a VM call
     // are not modified before its OsiPoint.
-    checkOsiPointRegisters = false;
+    SET_DEFAULT(checkOsiPointRegisters, false);
 #endif
 
     // Whether to enable extra code to perform dynamic validation of
     // RangeAnalysis results.
-    checkRangeAnalysis = false;
+    SET_DEFAULT(checkRangeAnalysis, false);
 
     // Whether Ion should compile try-catch statements.
-    compileTryCatch = true;
+    SET_DEFAULT(compileTryCatch, true);
 
     // Toggle whether eager scalar replacement is globally disabled.
-    disableScalarReplacement = true; // experimental
+    SET_DEFAULT(disableScalarReplacement, true); // experimental
 
     // Toggle whether global value numbering is globally disabled.
-    disableGvn = false;
+    SET_DEFAULT(disableGvn, false);
 
     // Toggles whether loop invariant code motion is globally disabled.
-    disableLicm = false;
+    SET_DEFAULT(disableLicm, false);
 
     // Toggles whether inlining is globally disabled.
-    disableInlining = false;
+    SET_DEFAULT(disableInlining, false);
 
     // Toggles whether Edge Case Analysis is gobally disabled.
-    disableEdgeCaseAnalysis = false;
+    SET_DEFAULT(disableEdgeCaseAnalysis, false);
 
     // Toggles whether Range Analysis is globally disabled.
-    disableRangeAnalysis = false;
+    SET_DEFAULT(disableRangeAnalysis, false);
 
     // Toggles whether Loop Unrolling is globally disabled.
-    disableLoopUnrolling = true;
+    SET_DEFAULT(disableLoopUnrolling, true);
 
     // Toggles whether Effective Address Analysis is globally disabled.
-    disableEaa = false;
+    SET_DEFAULT(disableEaa, false);
 
     // Whether functions are compiled immediately.
-    eagerCompilation = false;
+    SET_DEFAULT(eagerCompilation, false);
 
     // Force how many invocation or loop iterations are needed before compiling
     // a function with the highest ionmonkey optimization level.
     // (i.e. OptimizationLevel_Normal)
-    forceDefaultIonWarmUpThreshold = false;
-    forcedDefaultIonWarmUpThreshold = 1000;
+    SET_DEFAULT(forceDefaultIonWarmUpThreshold, false);
+    SET_DEFAULT(forcedDefaultIonWarmUpThreshold, 1000);
 
     // Force the used register allocator instead of letting the
     // optimization pass decide.
     forceRegisterAllocator = false;
     forcedRegisterAllocator = RegisterAllocator_LSRA;
 
     // Toggles whether large scripts are rejected.
-    limitScriptSize = true;
+    SET_DEFAULT(limitScriptSize, true);
 
     // Toggles whether functions may be entered at loop headers.
-    osr = true;
+    SET_DEFAULT(osr, true);
 
     // How many invocations or loop iterations are needed before functions
     // are compiled with the baseline compiler.
-    baselineWarmUpThreshold = 10;
+    SET_DEFAULT(baselineWarmUpThreshold, 10);
 
     // Number of exception bailouts (resuming into catch/finally block) before
     // we invalidate and forbid Ion compilation.
-    exceptionBailoutThreshold = 10;
+    SET_DEFAULT(exceptionBailoutThreshold, 10);
 
     // Number of bailouts without invalidation before we set
     // JSScript::hadFrequentBailouts and invalidate.
-    frequentBailoutThreshold = 10;
+    SET_DEFAULT(frequentBailoutThreshold, 10);
 
     // How many actual arguments are accepted on the C stack.
-    maxStackArgs = 4096;
+    SET_DEFAULT(maxStackArgs, 4096);
 
     // How many times we will try to enter a script via OSR before
     // invalidating the script.
-    osrPcMismatchesBeforeRecompile = 6000;
+    SET_DEFAULT(osrPcMismatchesBeforeRecompile, 6000);
 
     // The bytecode length limit for small function.
     //
     // The default for this was arrived at empirically via benchmarking.
     // We may want to tune it further after other optimizations have gone
     // in.
-    smallFunctionMaxBytecodeLength_ = 100;
+    SET_DEFAULT(smallFunctionMaxBytecodeLength_, 100);
 
     // How many uses of a parallel kernel before we attempt compilation.
-    compilerWarmUpThresholdPar = 1;
+    SET_DEFAULT(compilerWarmUpThresholdPar, 1);
 }
 
 bool
 JitOptions::isSmallFunction(JSScript *script) const
 {
     return script->length() <= smallFunctionMaxBytecodeLength_;
 }
 
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -138,52 +138,90 @@ class LSimdSplatX4 : public LInstruction
         setOperand(0, v);
     }
 
     MSimdSplatX4 *mir() const {
         return mir_->toSimdSplatX4();
     }
 };
 
-// Extracts an element from a given SIMD int32x4 lane.
-class LSimdExtractElementI : public LInstructionHelper<1, 1, 0>
-{
-    SimdLane lane_;
-
-  public:
-    LIR_HEADER(SimdExtractElementI);
-
-    LSimdExtractElementI(const LAllocation &base, SimdLane lane) : lane_(lane) {
+class LSimdExtractElementBase : public LInstructionHelper<1, 1, 0>
+{
+  protected:
+    LSimdExtractElementBase(const LAllocation &base) {
         setOperand(0, base);
     }
+
+  public:
     const LAllocation *getBase() {
         return getOperand(0);
     }
     SimdLane lane() const {
-        return lane_;
-    }
-};
-
+        return mir_->toSimdExtractElement()->lane();
+    }
+};
+
+// Extracts an element from a given SIMD int32x4 lane.
+class LSimdExtractElementI : public LSimdExtractElementBase
+{
+  public:
+    LIR_HEADER(SimdExtractElementI);
+    LSimdExtractElementI(const LAllocation &base)
+      : LSimdExtractElementBase(base)
+    {}
+};
 // Extracts an element from a given SIMD float32x4 lane.
-class LSimdExtractElementF : public LInstructionHelper<1, 1, 0>
-{
-    SimdLane lane_;
-
+class LSimdExtractElementF : public LSimdExtractElementBase
+{
   public:
     LIR_HEADER(SimdExtractElementF);
-
-    LSimdExtractElementF(const LAllocation &base, SimdLane lane) : lane_(lane) {
-        setOperand(0, base);
-    }
-    const LAllocation *getBase() {
+    LSimdExtractElementF(const LAllocation &base)
+      : LSimdExtractElementBase(base)
+    {}
+};
+
+class LSimdInsertElementBase : public LInstructionHelper<1, 2, 0>
+{
+  protected:
+    LSimdInsertElementBase(const LAllocation &vec, const LAllocation &val)
+    {
+        setOperand(0, vec);
+        setOperand(1, val);
+    }
+
+  public:
+    const LAllocation *vector() {
         return getOperand(0);
     }
-    SimdLane lane() const {
-        return lane_;
-    }
+    const LAllocation *value() {
+        return getOperand(1);
+    }
+    const SimdLane lane() const {
+        return mir_->toSimdInsertElement()->lane();
+    }
+};
+
+// Replace an element from a given SIMD int32x4 lane with a given value.
+class LSimdInsertElementI : public LSimdInsertElementBase
+{
+  public:
+    LIR_HEADER(SimdInsertElementI);
+    LSimdInsertElementI(const LAllocation &vec, const LAllocation &val)
+      : LSimdInsertElementBase(vec, val)
+    {}
+};
+
+// Replace an element from a given SIMD float32x4 lane with a given value.
+class LSimdInsertElementF : public LSimdInsertElementBase
+{
+  public:
+    LIR_HEADER(SimdInsertElementF);
+    LSimdInsertElementF(const LAllocation &vec, const LAllocation &val)
+      : LSimdInsertElementBase(vec, val)
+    {}
 };
 
 class LSimdSignMaskX4 : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(SimdSignMaskX4);
 
     explicit LSimdSignMaskX4(const LAllocation &input) {
@@ -2651,26 +2689,26 @@ class LReturn : public LInstructionHelpe
 class LThrow : public LCallInstructionHelper<0, BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(Throw)
 
     static const size_t Value = 0;
 };
 
-class LMinMaxI : public LInstructionHelper<1, 2, 0>
-{
-  public:
-    LIR_HEADER(MinMaxI)
-    LMinMaxI(const LAllocation &first, const LAllocation &second)
+class LMinMaxBase : public LInstructionHelper<1, 2, 0>
+{
+  protected:
+    LMinMaxBase(const LAllocation &first, const LAllocation &second)
     {
         setOperand(0, first);
         setOperand(1, second);
     }
 
+  public:
     const LAllocation *first() {
         return this->getOperand(0);
     }
     const LAllocation *second() {
         return this->getOperand(1);
     }
     const LDefinition *output() {
         return this->getDef(0);
@@ -2678,41 +2716,38 @@ class LMinMaxI : public LInstructionHelp
     MMinMax *mir() const {
         return mir_->toMinMax();
     }
     const char *extraName() const {
         return mir()->isMax() ? "Max" : "Min";
     }
 };
 
-class LMinMaxD : public LInstructionHelper<1, 2, 0>
+class LMinMaxI : public LMinMaxBase
+{
+  public:
+    LIR_HEADER(MinMaxI)
+    LMinMaxI(const LAllocation &first, const LAllocation &second) : LMinMaxBase(first, second)
+    {}
+};
+
+class LMinMaxD : public LMinMaxBase
 {
   public:
     LIR_HEADER(MinMaxD)
-    LMinMaxD(const LAllocation &first, const LAllocation &second)
-    {
-        setOperand(0, first);
-        setOperand(1, second);
-    }
-
-    const LAllocation *first() {
-        return this->getOperand(0);
-    }
-    const LAllocation *second() {
-        return this->getOperand(1);
-    }
-    const LDefinition *output() {
-        return this->getDef(0);
-    }
-    MMinMax *mir() const {
-        return mir_->toMinMax();
-    }
-    const char *extraName() const {
-        return mir()->isMax() ? "Max" : "Min";
-    }
+    LMinMaxD(const LAllocation &first, const LAllocation &second) : LMinMaxBase(first, second)
+    {}
+};
+
+class LMinMaxF : public LMinMaxBase
+{
+  public:
+    LIR_HEADER(MinMaxF)
+    LMinMaxF(const LAllocation &first, const LAllocation &second) : LMinMaxBase(first, second)
+    {}
 };
 
 // Negative of an integer
 class LNegI : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(NegI);
     explicit LNegI(const LAllocation &num) {
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -16,16 +16,18 @@
     _(Pointer)                      \
     _(Double)                       \
     _(Float32)                      \
     _(SimdSplatX4)                  \
     _(Int32x4)                      \
     _(Float32x4)                    \
     _(SimdExtractElementI)          \
     _(SimdExtractElementF)          \
+    _(SimdInsertElementI)           \
+    _(SimdInsertElementF)           \
     _(SimdSignMaskX4)               \
     _(SimdBinaryCompIx4)            \
     _(SimdBinaryCompFx4)            \
     _(SimdBinaryArithIx4)           \
     _(SimdBinaryArithFx4)           \
     _(SimdBinaryBitwiseX4)          \
     _(SimdSelect)                   \
     _(Value)                        \
@@ -110,16 +112,17 @@
     _(CompareVM)                    \
     _(BitAndAndBranch)              \
     _(IsNullOrLikeUndefined)        \
     _(IsNullOrLikeUndefinedAndBranch)\
     _(EmulatesUndefined)            \
     _(EmulatesUndefinedAndBranch)   \
     _(MinMaxI)                      \
     _(MinMaxD)                      \
+    _(MinMaxF)                      \
     _(NegI)                         \
     _(NegD)                         \
     _(NegF)                         \
     _(AbsI)                         \
     _(AbsD)                         \
     _(AbsF)                         \
     _(ClzI)                         \
     _(SqrtD)                        \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1283,16 +1283,22 @@ LIRGenerator::visitMinMax(MMinMax *ins)
 
     ReorderCommutative(&first, &second, ins);
 
     if (ins->specialization() == MIRType_Int32) {
         LMinMaxI *lir = new(alloc()) LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
         return defineReuseInput(lir, ins, 0);
     }
 
+    if (ins->specialization() == MIRType_Float32) {
+        LMinMaxF *lir = new(alloc()) LMinMaxF(useRegisterAtStart(first), useRegister(second));
+        return defineReuseInput(lir, ins, 0);
+    }
+
+    MOZ_ASSERT(ins->specialization() == MIRType_Double);
     LMinMaxD *lir = new(alloc()) LMinMaxD(useRegisterAtStart(first), useRegister(second));
     return defineReuseInput(lir, ins, 0);
 }
 
 bool
 LIRGenerator::visitAbs(MAbs *ins)
 {
     MDefinition *num = ins->input();
@@ -3716,28 +3722,43 @@ LIRGenerator::visitSimdExtractElement(MS
 {
     JS_ASSERT(IsSimdType(ins->input()->type()));
     JS_ASSERT(!IsSimdType(ins->type()));
 
     if (ins->input()->type() == MIRType_Int32x4) {
         // Note: there could be int16x8 in the future, which doesn't use the
         // same instruction. We either need to pass the arity or create new LIns.
         LUse use = useRegisterAtStart(ins->input());
-        return define(new(alloc()) LSimdExtractElementI(use, ins->lane()), ins);
+        return define(new(alloc()) LSimdExtractElementI(use), ins);
     }
 
     if (ins->input()->type() == MIRType_Float32x4) {
         LUse use = useRegisterAtStart(ins->input());
-        return define(new(alloc()) LSimdExtractElementF(use, ins->lane()), ins);
+        return define(new(alloc()) LSimdExtractElementF(use), ins);
     }
 
     MOZ_CRASH("Unknown SIMD kind when extracting element");
 }
 
 bool
+LIRGenerator::visitSimdInsertElement(MSimdInsertElement *ins)
+{
+    JS_ASSERT(IsSimdType(ins->type()));
+
+    LUse vec = useRegisterAtStart(ins->vector());
+    LUse val = useRegister(ins->value());
+    if (ins->type() == MIRType_Int32x4)
+        return defineReuseInput(new(alloc()) LSimdInsertElementI(vec, val), ins, 0);
+    if (ins->type() == MIRType_Float32x4)
+        return defineReuseInput(new(alloc()) LSimdInsertElementF(vec, val), ins, 0);
+
+    MOZ_CRASH("Unknown SIMD kind when generating constant");
+}
+
+bool
 LIRGenerator::visitSimdSignMask(MSimdSignMask *ins)
 {
     MDefinition *input = ins->input();
     MOZ_ASSERT(IsSimdType(input->type()));
     MOZ_ASSERT(ins->type() == MIRType_Int32);
 
     LUse use = useRegisterAtStart(input);
 
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -264,16 +264,17 @@ class LIRGenerator : public LIRGenerator
     bool visitAsmJSVoidReturn(MAsmJSVoidReturn *ins);
     bool visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
     bool visitAsmJSCall(MAsmJSCall *ins);
     bool visitSetDOMProperty(MSetDOMProperty *ins);
     bool visitGetDOMProperty(MGetDOMProperty *ins);
     bool visitGetDOMMember(MGetDOMMember *ins);
     bool visitRecompileCheck(MRecompileCheck *ins);
     bool visitSimdExtractElement(MSimdExtractElement *ins);
+    bool visitSimdInsertElement(MSimdInsertElement *ins);
     bool visitSimdSignMask(MSimdSignMask *ins);
     bool visitSimdBinaryComp(MSimdBinaryComp *ins);
     bool visitSimdBinaryArith(MSimdBinaryArith *ins);
     bool visitSimdBinaryBitwise(MSimdBinaryBitwise *ins);
     bool visitSimdConstant(MSimdConstant *ins);
     bool visitPhi(MPhi *ins);
     bool visitBeta(MBeta *ins);
     bool visitObjectState(MObjectState *ins);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1693,18 +1693,41 @@ MBinaryArithInstruction::trySpecializeFl
 {
     // Do not use Float32 if we can use int32.
     if (specialization_ == MIRType_Int32)
         return;
 
     MDefinition *left = lhs();
     MDefinition *right = rhs();
 
-    if (!left->canProduceFloat32() || !right->canProduceFloat32()
-        || !CheckUsesAreFloat32Consumers(this))
+    if (!left->canProduceFloat32() || !right->canProduceFloat32() ||
+        !CheckUsesAreFloat32Consumers(this))
+    {
+        if (left->type() == MIRType_Float32)
+            ConvertDefinitionToDouble<0>(alloc, left, this);
+        if (right->type() == MIRType_Float32)
+            ConvertDefinitionToDouble<1>(alloc, right, this);
+        return;
+    }
+
+    specialization_ = MIRType_Float32;
+    setResultType(MIRType_Float32);
+}
+
+void
+MMinMax::trySpecializeFloat32(TempAllocator &alloc)
+{
+    if (specialization_ == MIRType_Int32)
+        return;
+
+    MDefinition *left = lhs();
+    MDefinition *right = rhs();
+
+    if (!(left->canProduceFloat32() || (left->isMinMax() && left->type() == MIRType_Float32)) ||
+        !(right->canProduceFloat32() || (right->isMinMax() && right->type() == MIRType_Float32)))
     {
         if (left->type() == MIRType_Float32)
             ConvertDefinitionToDouble<0>(alloc, left, this);
         if (right->type() == MIRType_Float32)
             ConvertDefinitionToDouble<1>(alloc, right, this);
         return;
     }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1397,16 +1397,60 @@ class MSimdExtractElement : public MUnar
             return false;
         const MSimdExtractElement *other = ins->toSimdExtractElement();
         if (other->lane_ != lane_)
             return false;
         return congruentIfOperandsEqual(other);
     }
 };
 
+// Replaces the datum in the given lane by a scalar value of the same type.
+class MSimdInsertElement : public MBinaryInstruction
+{
+  private:
+    SimdLane lane_;
+
+    MSimdInsertElement(MDefinition *vec, MDefinition *val, MIRType type, SimdLane lane)
+      : MBinaryInstruction(vec, val), lane_(lane)
+    {
+        MOZ_ASSERT(IsSimdType(type) && vec->type() == type);
+        MOZ_ASSERT(SimdTypeToScalarType(type) == val->type());
+
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdInsertElement)
+
+    static MSimdInsertElement *NewAsmJS(TempAllocator &alloc, MDefinition *vec, MDefinition *val,
+                                         MIRType type, SimdLane lane)
+    {
+        return new(alloc) MSimdInsertElement(vec, val, type, lane);
+    }
+
+    MDefinition *vector() {
+        return getOperand(0);
+    }
+    MDefinition *value() {
+        return getOperand(1);
+    }
+    SimdLane lane() const {
+        return lane_;
+    }
+
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+
+    bool congruentTo(const MDefinition *ins) const {
+        return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
+    }
+};
+
 // Extracts the sign bits from a given vector, returning an MIRType_Int32.
 class MSimdSignMask : public MUnaryInstruction
 {
   protected:
     explicit MSimdSignMask(MDefinition *obj)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(obj->type()));
@@ -4534,17 +4578,17 @@ class MMinMax
     public ArithPolicy::Data
 {
     bool isMax_;
 
     MMinMax(MDefinition *left, MDefinition *right, MIRType type, bool isMax)
       : MBinaryInstruction(left, right),
         isMax_(isMax)
     {
-        JS_ASSERT(type == MIRType_Double || type == MIRType_Int32);
+        JS_ASSERT(IsNumberType(type));
         setResultType(type);
         setMovable();
         specialization_ = type;
     }
 
   public:
     INSTRUCTION_HEADER(MinMax)
     static MMinMax *New(TempAllocator &alloc, MDefinition *left, MDefinition *right, MIRType type,
@@ -4569,16 +4613,19 @@ class MMinMax
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
     bool writeRecoverData(CompactBufferWriter &writer) const;
     bool canRecoverOnBailout() const {
         return true;
     }
 
+    bool isFloat32Commutative() const { return true; }
+    void trySpecializeFloat32(TempAllocator &alloc);
+
     ALLOW_CLONE(MMinMax)
 };
 
 class MAbs
   : public MUnaryInstruction,
     public ArithPolicy::Data
 {
     bool implicitTruncate_;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -11,16 +11,17 @@ namespace js {
 namespace jit {
 
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
     _(SimdValueX4)                                                          \
     _(SimdSplatX4)                                                          \
     _(SimdConstant)                                                         \
     _(SimdExtractElement)                                                   \
+    _(SimdInsertElement)                                                    \
     _(SimdSignMask)                                                         \
     _(SimdBinaryComp)                                                       \
     _(SimdBinaryArith)                                                      \
     _(SimdBinaryBitwise)                                                    \
     _(SimdTernaryBitwise)                                                   \
     _(CloneLiteral)                                                         \
     _(Parameter)                                                            \
     _(Callee)                                                               \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -110,16 +110,17 @@ class ParallelSafetyVisitor : public MDe
     // I am taking the policy of blacklisting everything that's not
     // obviously safe for now.  We can loosen as we need.
 
     SAFE_OP(Constant)
     SAFE_OP(SimdValueX4)
     SAFE_OP(SimdSplatX4)
     SAFE_OP(SimdConstant)
     SAFE_OP(SimdExtractElement)
+    SAFE_OP(SimdInsertElement)
     SAFE_OP(SimdSignMask)
     SAFE_OP(SimdBinaryComp)
     SAFE_OP(SimdBinaryArith)
     SAFE_OP(SimdBinaryBitwise)
     SAFE_OP(SimdTernaryBitwise)
     UNSAFE_OP(CloneLiteral)
     SAFE_OP(Parameter)
     SAFE_OP(Callee)
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -286,16 +286,65 @@ CodeGeneratorARM::visitMinMaxD(LMinMaxD 
     masm.bind(&returnSecond);
     masm.ma_vmov(second, output);
 
     masm.bind(&done);
     return true;
 }
 
 bool
+CodeGeneratorARM::visitMinMaxF(LMinMaxF *ins)
+{
+    FloatRegister first = ToFloatRegister(ins->first());
+    FloatRegister second = ToFloatRegister(ins->second());
+    FloatRegister output = ToFloatRegister(ins->output());
+
+    JS_ASSERT(first == output);
+
+    Assembler::Condition cond = ins->mir()->isMax()
+        ? Assembler::VFP_LessThanOrEqual
+        : Assembler::VFP_GreaterThanOrEqual;
+    Label nan, equal, returnSecond, done;
+
+    masm.compareFloat(first, second);
+    // First or second is NaN, result is NaN.
+    masm.ma_b(&nan, Assembler::VFP_Unordered);
+    // Make sure we handle -0 and 0 right.
+    masm.ma_b(&equal, Assembler::VFP_Equal);
+    masm.ma_b(&returnSecond, cond);
+    masm.ma_b(&done);
+
+    // Check for zero.
+    masm.bind(&equal);
+    masm.compareFloat(first, NoVFPRegister);
+    // First wasn't 0 or -0, so just return it.
+    masm.ma_b(&done, Assembler::VFP_NotEqualOrUnordered);
+    // So now both operands are either -0 or 0.
+    if (ins->mir()->isMax()) {
+        // -0 + -0 = -0 and -0 + 0 = 0.
+        masm.ma_vadd_f32(second, first, first);
+    } else {
+        masm.ma_vneg_f32(first, first);
+        masm.ma_vsub_f32(first, second, first);
+        masm.ma_vneg_f32(first, first);
+    }
+    masm.ma_b(&done);
+
+    masm.bind(&nan);
+    masm.loadConstantFloat32(GenericNaN(), output);
+    masm.ma_b(&done);
+
+    masm.bind(&returnSecond);
+    masm.ma_vmov_f32(second, output);
+
+    masm.bind(&done);
+    return true;
+}
+
+bool
 CodeGeneratorARM::visitAbsD(LAbsD *ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     JS_ASSERT(input == ToFloatRegister(ins->output()));
     masm.ma_vabs(input, input);
     return true;
 }
 
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -97,16 +97,17 @@ class CodeGeneratorARM : public CodeGene
         emitBranch(cond, ifTrue, ifFalse);
     }
 
     bool emitTableSwitchDispatch(MTableSwitch *mir, Register index, Register base);
 
   public:
     // Instruction visitors.
     virtual bool visitMinMaxD(LMinMaxD *ins);
+    virtual bool visitMinMaxF(LMinMaxF *ins);
     virtual bool visitAbsD(LAbsD *ins);
     virtual bool visitAbsF(LAbsF *ins);
     virtual bool visitSqrtD(LSqrtD *ins);
     virtual bool visitSqrtF(LSqrtF *ins);
     virtual bool visitAddI(LAddI *ins);
     virtual bool visitSubI(LSubI *ins);
     virtual bool visitBitNotI(LBitNotI *ins);
     virtual bool visitBitOpI(LBitOpI *ins);
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -520,43 +520,50 @@ class AssemblerX86Shared : public Assemb
           case Operand::MEM_SCALE:
             masm.movups_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
 
-    // movsd and movss are only provided in load/store form since the
+    // movsd is only provided in load/store form since the
     // register-to-register form has different semantics (it doesn't clobber
     // the whole output register) and isn't needed currently.
     void movsd(const Address &src, FloatRegister dest) {
         masm.movsd_mr(src.offset, src.base.code(), dest.code());
     }
     void movsd(const BaseIndex &src, FloatRegister dest) {
         masm.movsd_mr(src.offset, src.base.code(), src.index.code(), src.scale, dest.code());
     }
     void movsd(FloatRegister src, const Address &dest) {
         masm.movsd_rm(src.code(), dest.offset, dest.base.code());
     }
     void movsd(FloatRegister src, const BaseIndex &dest) {
         masm.movsd_rm(src.code(), dest.offset, dest.base.code(), dest.index.code(), dest.scale);
     }
+    // Although movss is not only provided in load/store form (for the same
+    // reasons as movsd above), the register to register form should be only
+    // used in contexts where we care about not clearing the higher lanes of
+    // the FloatRegister.
     void movss(const Address &src, FloatRegister dest) {
         masm.movss_mr(src.offset, src.base.code(), dest.code());
     }
     void movss(const BaseIndex &src, FloatRegister dest) {
         masm.movss_mr(src.offset, src.base.code(), src.index.code(), src.scale, dest.code());
     }
     void movss(FloatRegister src, const Address &dest) {
         masm.movss_rm(src.code(), dest.offset, dest.base.code());
     }
     void movss(FloatRegister src, const BaseIndex &dest) {
         masm.movss_rm(src.code(), dest.offset, dest.base.code(), dest.index.code(), dest.scale);
     }
+    void movss(FloatRegister src, const FloatRegister &dest) {
+        masm.movss_rr(src.code(), dest.code());
+    }
     void movdqu(const Operand &src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         switch (src.kind()) {
           case Operand::MEM_REG_DISP:
             masm.movdqu_mr(src.disp(), src.base(), dest.code());
             break;
           case Operand::MEM_SCALE:
             masm.movdqu_mr(src.disp(), src.base(), src.index(), src.scale(), dest.code());
@@ -1407,21 +1414,21 @@ class AssemblerX86Shared : public Assemb
         masm.divl_r(divisor.code());
     }
 
     void unpcklps(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.unpcklps_rr(src.code(), dest.code());
     }
     void pinsrd(unsigned lane, Register src, FloatRegister dest) {
-        JS_ASSERT(HasSSE2());
+        JS_ASSERT(HasSSE41());
         masm.pinsrd_irr(lane, src.code(), dest.code());
     }
     void pinsrd(unsigned lane, const Operand &src, FloatRegister dest) {
-        JS_ASSERT(HasSSE2());
+        JS_ASSERT(HasSSE41());
         switch (src.kind()) {
           case Operand::REG:
             masm.pinsrd_irr(lane, src.reg(), dest.code());
             break;
           case Operand::MEM_REG_DISP:
             masm.pinsrd_imr(lane, src.disp(), src.base(), dest.code());
             break;
           default:
@@ -1926,44 +1933,59 @@ class AssemblerX86Shared : public Assemb
     void xorps(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.xorps_rr(src.code(), dest.code());
     }
     void orpd(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.orpd_rr(src.code(), dest.code());
     }
+    void orps(FloatRegister src, FloatRegister dest) {
+        JS_ASSERT(HasSSE2());
+        masm.orps_rr(src.code(), dest.code());
+    }
     void andpd(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.andpd_rr(src.code(), dest.code());
     }
     void andps(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.andps_rr(src.code(), dest.code());
     }
     void sqrtsd(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.sqrtsd_rr(src.code(), dest.code());
     }
     void sqrtss(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.sqrtss_rr(src.code(), dest.code());
     }
-    void roundsd(FloatRegister src, FloatRegister dest,
-                 X86Assembler::RoundingMode mode)
-    {
+    void roundsd(FloatRegister src, FloatRegister dest, X86Assembler::RoundingMode mode) {
         JS_ASSERT(HasSSE41());
         masm.roundsd_rr(src.code(), dest.code(), mode);
     }
-    void roundss(FloatRegister src, FloatRegister dest,
-                 X86Assembler::RoundingMode mode)
-    {
+    void roundss(FloatRegister src, FloatRegister dest, X86Assembler::RoundingMode mode) {
         JS_ASSERT(HasSSE41());
         masm.roundss_rr(src.code(), dest.code(), mode);
     }
+    unsigned insertpsMask(SimdLane sourceLane, SimdLane destLane, unsigned zeroMask = 0)
+    {
+        // Note that the sourceLane bits are ignored in the case of a source
+        // memory operand, and the source is the given 32-bits memory location.
+        MOZ_ASSERT(zeroMask < 16);
+        unsigned ret = zeroMask ;
+        ret |= unsigned(destLane) << 4;
+        ret |= unsigned(sourceLane) << 6;
+        MOZ_ASSERT(ret < 256);
+        return ret;
+    }
+    void insertps(FloatRegister src, FloatRegister dest, unsigned mask) {
+        JS_ASSERT(HasSSE41());
+        masm.insertps_irr(mask, src.code(), dest.code());
+    }
     void minsd(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.minsd_rr(src.code(), dest.code());
     }
     void minsd(const Operand &src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         switch (src.kind()) {
           case Operand::FPREG:
@@ -1971,16 +1993,20 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_REG_DISP:
             masm.minsd_mr(src.disp(), src.base(), dest.code());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void minss(FloatRegister src, FloatRegister dest) {
+        JS_ASSERT(HasSSE2());
+        masm.minss_rr(src.code(), dest.code());
+    }
     void maxsd(FloatRegister src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         masm.maxsd_rr(src.code(), dest.code());
     }
     void maxsd(const Operand &src, FloatRegister dest) {
         JS_ASSERT(HasSSE2());
         switch (src.kind()) {
           case Operand::FPREG:
@@ -1988,16 +2014,20 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_REG_DISP:
             masm.maxsd_mr(src.disp(), src.base(), dest.code());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void maxss(FloatRegister src, FloatRegister dest) {
+        JS_ASSERT(HasSSE2());
+        masm.maxss_rr(src.code(), dest.code());
+    }
     void fisttp(const Operand &dest) {
         JS_ASSERT(HasSSE3());
         switch (dest.kind()) {
           case Operand::MEM_REG_DISP:
             masm.fisttp_m(dest.disp(), dest.base());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
--- a/js/src/jit/shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/shared/BaseAssembler-x86-shared.h
@@ -303,20 +303,22 @@ private:
         OP2_ADDPS_VpsWps    = 0x58,
         OP2_MULSD_VsdWsd    = 0x59,
         OP2_MULPS_VpsWps    = 0x59,
         OP2_CVTSS2SD_VsdEd  = 0x5A,
         OP2_CVTSD2SS_VsdEd  = 0x5A,
         OP2_SUBSD_VsdWsd    = 0x5C,
         OP2_SUBPS_VpsWps    = 0x5C,
         OP2_MINSD_VsdWsd    = 0x5D,
+        OP2_MINSS_VssWss    = 0x5D,
         OP2_MINPS_VpsWps    = 0x5D,
         OP2_DIVSD_VsdWsd    = 0x5E,
         OP2_DIVPS_VpsWps    = 0x5E,
         OP2_MAXSD_VsdWsd    = 0x5F,
+        OP2_MAXSS_VssWss    = 0x5F,
         OP2_MAXPS_VpsWps    = 0x5F,
         OP2_SQRTSD_VsdWsd   = 0x51,
         OP2_SQRTSS_VssWss   = 0x51,
         OP2_ANDPD_VpdWpd    = 0x54,
         OP2_ORPD_VpdWpd     = 0x56,
         OP2_XORPD_VpdWpd    = 0x57,
         OP2_PCMPGTD_VdqWdq  = 0x66,
         OP2_MOVD_VdEd       = 0x6E,
@@ -345,23 +347,25 @@ private:
         OP2_PSUBD_VdqWdq    = 0xFA,
         OP2_PADDD_VdqWdq    = 0xFE
     } TwoByteOpcodeID;
 
     typedef enum {
         OP3_ROUNDSS_VsdWsd  = 0x0A,
         OP3_ROUNDSD_VsdWsd  = 0x0B,
         OP3_PTEST_VdVd      = 0x17,
+        OP3_INSERTPS_VpsUps = 0x21,
         OP3_PINSRD_VdqEdIb  = 0x22
     } ThreeByteOpcodeID;
 
     typedef enum {
         ESCAPE_PTEST        = 0x38,
         ESCAPE_PINSRD       = 0x3A,
-        ESCAPE_ROUNDSD      = 0x3A
+        ESCAPE_ROUNDSD      = 0x3A,
+        ESCAPE_INSERTPS     = 0x3A
     } ThreeByteEscape;
 
     TwoByteOpcodeID jccRel32(Condition cond)
     {
         return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond);
     }
 
     TwoByteOpcodeID setccOpcode(Condition cond)
@@ -3597,16 +3601,26 @@ public:
     {
         spew("roundss    %s, %s, %d",
              nameFPReg(src), nameFPReg(dst), (int)mode);
         m_formatter.prefix(PRE_SSE_66);
         m_formatter.threeByteOp(OP3_ROUNDSS_VsdWsd, ESCAPE_ROUNDSD, (RegisterID)dst, (RegisterID)src);
         m_formatter.immediate8(mode); // modes are the same for roundsd and roundss
     }
 
+    void insertps_irr(unsigned mask, XMMRegisterID src, XMMRegisterID dst)
+    {
+        MOZ_ASSERT(mask < 256);
+        spew("insertps     $%u, %s, %s",
+             mask, nameFPReg(src), nameFPReg(dst));
+        m_formatter.prefix(PRE_SSE_66);
+        m_formatter.threeByteOp(OP3_INSERTPS_VpsUps, ESCAPE_INSERTPS, (RegisterID)dst, (RegisterID)src);
+        m_formatter.immediate8(uint8_t(mask));
+    }
+
     void pinsrd_irr(unsigned lane, RegisterID src, XMMRegisterID dst)
     {
         MOZ_ASSERT(lane < 4);
         spew("pinsrd     $%u, %s, %s",
              lane, nameIReg(src), nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_66);
         m_formatter.threeByteOp(OP3_PINSRD_VdqEdIb, ESCAPE_PINSRD, (RegisterID)dst, (RegisterID)src);
         m_formatter.immediate8(uint8_t(lane));
@@ -3634,32 +3648,48 @@ public:
     void minsd_mr(int offset, RegisterID base, XMMRegisterID dst)
     {
         spew("minsd      %s0x%x(%s), %s",
              PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteOp(OP2_MINSD_VsdWsd, (RegisterID)dst, base, offset);
     }
 
+    void minss_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        spew("minss      %s, %s",
+             nameFPReg(src), nameFPReg(dst));
+        m_formatter.prefix(PRE_SSE_F3);
+        m_formatter.twoByteOp(OP2_MINSS_VssWss, (RegisterID)dst, (RegisterID)src);
+    }
+
     void maxsd_rr(XMMRegisterID src, XMMRegisterID dst)
     {
         spew("maxsd      %s, %s",
              nameFPReg(src), nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteOp(OP2_MAXSD_VsdWsd, (RegisterID)dst, (RegisterID)src);
     }
 
     void maxsd_mr(int offset, RegisterID base, XMMRegisterID dst)
     {
         spew("maxsd      %s0x%x(%s), %s",
              PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteOp(OP2_MAXSD_VsdWsd, (RegisterID)dst, base, offset);
     }
 
+    void maxss_rr(XMMRegisterID src, XMMRegisterID dst)
+    {
+        spew("maxss      %s, %s",
+             nameFPReg(src), nameFPReg(dst));
+        m_formatter.prefix(PRE_SSE_F3);
+        m_formatter.twoByteOp(OP2_MAXSS_VssWss, (RegisterID)dst, (RegisterID)src);
+    }
+
     // Misc instructions:
 
     void int3()
     {
         spew("int3");
         m_formatter.oneByteOp(OP_INT3);
     }
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -532,16 +532,68 @@ CodeGeneratorX86Shared::visitMinMaxD(LMi
     else
         masm.minsd(second, first);
 
     masm.bind(&done);
     return true;
 }
 
 bool
+CodeGeneratorX86Shared::visitMinMaxF(LMinMaxF *ins)
+{
+    FloatRegister first = ToFloatRegister(ins->first());
+    FloatRegister second = ToFloatRegister(ins->second());
+#ifdef DEBUG
+    FloatRegister output = ToFloatRegister(ins->output());
+    JS_ASSERT(first == output);
+#endif
+
+    Label done, nan, minMaxInst;
+
+    // Do a ucomiss to catch equality and NaNs, which both require special
+    // handling. If the operands are ordered and inequal, we branch straight to
+    // the min/max instruction. If we wanted, we could also branch for less-than
+    // or greater-than here instead of using min/max, however these conditions
+    // will sometimes be hard on the branch predictor.
+    masm.ucomiss(first, second);
+    masm.j(Assembler::NotEqual, &minMaxInst);
+    if (!ins->mir()->range() || ins->mir()->range()->canBeNaN())
+        masm.j(Assembler::Parity, &nan);
+
+    // Ordered and equal. The operands are bit-identical unless they are zero
+    // and negative zero. These instructions merge the sign bits in that
+    // case, and are no-ops otherwise.
+    if (ins->mir()->isMax())
+        masm.andps(second, first);
+    else
+        masm.orps(second, first);
+    masm.jump(&done);
+
+    // x86's min/max are not symmetric; if either operand is a NaN, they return
+    // the read-only operand. We need to return a NaN if either operand is a
+    // NaN, so we explicitly check for a NaN in the read-write operand.
+    if (!ins->mir()->range() || ins->mir()->range()->canBeNaN()) {
+        masm.bind(&nan);
+        masm.ucomiss(first, first);
+        masm.j(Assembler::Parity, &done);
+    }
+
+    // When the values are inequal, or second is NaN, x86's min and max will
+    // return the value we need.
+    masm.bind(&minMaxInst);
+    if (ins->mir()->isMax())
+        masm.maxss(second, first);
+    else
+        masm.minss(second, first);
+
+    masm.bind(&done);
+    return true;
+}
+
+bool
 CodeGeneratorX86Shared::visitAbsD(LAbsD *ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     JS_ASSERT(input == ToFloatRegister(ins->output()));
     // Load a value which is all ones except for the sign bit.
     masm.loadConstantDouble(SpecificNaN<double>(0, FloatingPoint<double>::kSignificandBits),
                             ScratchDoubleReg);
     masm.andpd(ScratchDoubleReg, input);
@@ -2228,16 +2280,73 @@ CodeGeneratorX86Shared::visitSimdExtract
         uint32_t mask = MacroAssembler::ComputeShuffleMask(lane);
         masm.shuffleFloat32(mask, input, output);
     }
     masm.canonicalizeFloat(output);
     return true;
 }
 
 bool
+CodeGeneratorX86Shared::visitSimdInsertElementI(LSimdInsertElementI *ins)
+{
+    FloatRegister vector = ToFloatRegister(ins->vector());
+    Register value = ToRegister(ins->value());
+    FloatRegister output = ToFloatRegister(ins->output());
+    MOZ_ASSERT(vector == output); // defineReuseInput(0)
+
+    unsigned component = unsigned(ins->lane());
+
+    // Note that, contrarily to float32x4, we cannot use movd if the inserted
+    // value goes into the first component, as movd clears out the higher lanes
+    // of the output.
+    if (AssemblerX86Shared::HasSSE41()) {
+        masm.pinsrd(component, value, output);
+        return true;
+    }
+
+    masm.reserveStack(Simd128DataSize);
+    masm.storeAlignedInt32x4(vector, Address(StackPointer, 0));
+    masm.store32(value, Address(StackPointer, component * sizeof(int32_t)));
+    masm.loadAlignedInt32x4(Address(StackPointer, 0), output);
+    masm.freeStack(Simd128DataSize);
+    return true;
+}
+
+bool
+CodeGeneratorX86Shared::visitSimdInsertElementF(LSimdInsertElementF *ins)
+{
+    FloatRegister vector = ToFloatRegister(ins->vector());
+    FloatRegister value = ToFloatRegister(ins->value());
+    FloatRegister output = ToFloatRegister(ins->output());
+    MOZ_ASSERT(vector == output); // defineReuseInput(0)
+
+    if (ins->lane() == SimdLane::LaneX) {
+        // As both operands are registers, movss doesn't modify the upper bits
+        // of the destination operand.
+        if (value != output)
+            masm.movss(value, output);
+        return true;
+    }
+
+    if (AssemblerX86Shared::HasSSE41()) {
+        // The input value is in the low float32 of the 'value' FloatRegister.
+        masm.insertps(value, output, masm.insertpsMask(SimdLane::LaneX, ins->lane()));
+        return true;
+    }
+
+    unsigned component = unsigned(ins->lane());
+    masm.reserveStack(Simd128DataSize);
+    masm.storeAlignedFloat32x4(vector, Address(StackPointer, 0));
+    masm.storeFloat32(value, Address(StackPointer, component * sizeof(int32_t)));
+    masm.loadAlignedFloat32x4(Address(StackPointer, 0), output);
+    masm.freeStack(Simd128DataSize);
+    return true;
+}
+
+bool
 CodeGeneratorX86Shared::visitSimdSignMaskX4(LSimdSignMaskX4 *ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     // For Float32x4 and Int32x4.
     masm.movmskps(input, output);
     return true;
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -146,16 +146,17 @@ class CodeGeneratorX86Shared : public Co
   public:
     CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm);
 
   public:
     // Instruction visitors.
     virtual bool visitDouble(LDouble *ins);
     virtual bool visitFloat32(LFloat32 *ins);
     virtual bool visitMinMaxD(LMinMaxD *ins);
+    virtual bool visitMinMaxF(LMinMaxF *ins);
     virtual bool visitAbsD(LAbsD *ins);
     virtual bool visitAbsF(LAbsF *ins);
     virtual bool visitClzI(LClzI *ins);
     virtual bool visitSqrtD(LSqrtD *ins);
     virtual bool visitSqrtF(LSqrtF *ins);
     virtual bool visitPowHalfD(LPowHalfD *ins);
     virtual bool visitAddI(LAddI *ins);
     virtual bool visitSubI(LSubI *ins);
@@ -208,16 +209,18 @@ class CodeGeneratorX86Shared : public Co
     // SIMD operators
     bool visitSimdValueInt32x4(LSimdValueInt32x4 *lir);
     bool visitSimdValueFloat32x4(LSimdValueFloat32x4 *lir);
     bool visitSimdSplatX4(LSimdSplatX4 *lir);
     bool visitInt32x4(LInt32x4 *ins);
     bool visitFloat32x4(LFloat32x4 *ins);
     bool visitSimdExtractElementI(LSimdExtractElementI *lir);
     bool visitSimdExtractElementF(LSimdExtractElementF *lir);
+    bool visitSimdInsertElementI(LSimdInsertElementI *lir);
+    bool visitSimdInsertElementF(LSimdInsertElementF *lir);
     bool visitSimdSignMaskX4(LSimdSignMaskX4 *ins);
     bool visitSimdBinaryCompIx4(LSimdBinaryCompIx4 *lir);
     bool visitSimdBinaryCompFx4(LSimdBinaryCompFx4 *lir);
     bool visitSimdBinaryArithIx4(LSimdBinaryArithIx4 *lir);
     bool visitSimdBinaryArithFx4(LSimdBinaryArithFx4 *lir);
     bool visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4 *lir);
     bool visitSimdSelect(LSimdSelect *ins);
 
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -18,17 +18,18 @@ const js::Class OuterWrapperClass =
     PROXY_CLASS_WITH_EXT(
         "Proxy",
         0, /* additional slots */
         0, /* additional class flags */
         PROXY_MAKE_EXT(
             nullptr, /* outerObject */
             js::proxy_innerObject,
             nullptr, /* iteratorObject */
-            false   /* isWrappedNative */
+            false,   /* isWrappedNative */
+            nullptr  /* objectMoved */
         ));
 
 static JSObject *
 wrap(JSContext *cx, JS::HandleObject toWrap, JS::HandleObject target)
 {
     JSAutoCompartment ac(cx, target);
     JS::RootedObject wrapper(cx, toWrap);
     if (!JS_WrapObject(cx, &wrapper))
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -247,24 +247,24 @@ namespace js {
 
 /*
  * Helper Macros for creating JSClasses that function as proxies.
  *
  * NB: The macro invocation must be surrounded by braces, so as to
  *     allow for potention JSClass extensions.
  */
 #define PROXY_MAKE_EXT(outerObject, innerObject, iteratorObject,        \
-                       isWrappedNative)                                 \
+                       isWrappedNative, objectMoved)                    \
     {                                                                   \
         outerObject,                                                    \
         innerObject,                                                    \
         iteratorObject,                                                 \
         isWrappedNative,                                                \
         js::proxy_WeakmapKeyDelegate,                                   \
-        js::proxy_ObjectMoved                                           \
+        objectMoved                                                     \
     }
 
 #define PROXY_CLASS_WITH_EXT(name, extraSlots, flags, ext)                              \
     {                                                                                   \
         name,                                                                           \
         js::Class::NON_NATIVE |                                                         \
             JSCLASS_IS_PROXY |                                                          \
             JSCLASS_IMPLEMENTS_BARRIERS |                                               \
@@ -308,17 +308,18 @@ namespace js {
     }
 
 #define PROXY_CLASS_DEF(name, extraSlots, flags)                        \
   PROXY_CLASS_WITH_EXT(name, extraSlots, flags,                         \
                        PROXY_MAKE_EXT(                                  \
                          nullptr, /* outerObject */                     \
                          nullptr, /* innerObject */                     \
                          nullptr, /* iteratorObject */                  \
-                         false    /* isWrappedNative */                 \
+                         false,   /* isWrappedNative */                 \
+                         js::proxy_ObjectMoved                          \
                        ))
 
 /*
  * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions.
  *
  * NB: Should not be called directly.
  */
 
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -450,16 +450,23 @@ ArenaHeader::checkSynchronizedWithFreeLi
     /*
      * Here this arena has free things, FreeList::lists[thingKind] is not
      * empty and also points to this arena. Thus they must be the same.
      */
     JS_ASSERT(freeList->isSameNonEmptySpan(firstSpan));
 }
 #endif
 
+void
+ArenaHeader::unmarkAll()
+{
+    uintptr_t *word = chunk()->bitmap.arenaBits(this);
+    memset(word, 0, ArenaBitmapWords * sizeof(uintptr_t));
+}
+
 /* static */ void
 Arena::staticAsserts()
 {
     static_assert(JS_ARRAY_LENGTH(ThingSizes) == FINALIZE_LIMIT, "We have defined all thing sizes.");
     static_assert(JS_ARRAY_LENGTH(FirstThingOffsets) == FINALIZE_LIMIT, "We have defined all offsets.");
 }
 
 void
@@ -2487,16 +2494,19 @@ GCRuntime::releaseRelocatedArenas(ArenaH
     }
 #endif
 
     unsigned count = 0;
     while (relocatedList) {
         ArenaHeader *aheader = relocatedList;
         relocatedList = relocatedList->next;
 
+        // Clear the mark bits
+        aheader->unmarkAll();
+
         // Mark arena as empty
         AllocKind thingKind = aheader->getAllocKind();
         size_t thingSize = aheader->getThingSize();
         Arena *arena = aheader->getArena();
         FreeSpan fullSpan;
         fullSpan.initFinal(arena->thingsStart(thingKind), arena->thingsEnd() - thingSize, thingSize);
         aheader->setFirstFreeSpan(&fullSpan);
 
@@ -5637,22 +5647,22 @@ GCRuntime::scanZonesBeforeGC()
     return zoneStats;
 }
 
 void
 GCRuntime::collect(bool incremental, int64_t budget, JSGCInvocationKind gckind,
                    JS::gcreason::Reason reason)
 {
     /* GC shouldn't be running in parallel execution mode */
-    MOZ_ASSERT(!InParallelSection());
+    MOZ_ALWAYS_TRUE(!InParallelSection());
 
     JS_AbortIfWrongThread(rt);
 
     /* If we attempt to invoke the GC while we are running in the GC, assert. */
-    MOZ_ASSERT(!rt->isHeapBusy());
+    MOZ_ALWAYS_TRUE(!rt->isHeapBusy());
 
     /* The engine never locks across anything that could GC. */
     MOZ_ASSERT(!rt->currentThreadHasExclusiveAccess());
 
     if (rt->mainThread.suppressGC)
         return;
 
     TraceLogger *logger = TraceLoggerForMainThread(rt);
@@ -6354,18 +6364,43 @@ JS::AutoAssertOnGC::~AutoAssertOnGC()
 }
 
 /* static */ void
 JS::AutoAssertOnGC::VerifyIsSafeToGC(JSRuntime *rt)
 {
     if (rt->gc.isInsideUnsafeRegion())
         MOZ_CRASH("[AutoAssertOnGC] possible GC in GC-unsafe region");
 }
+
+JS::AutoAssertNoAlloc::AutoAssertNoAlloc(JSRuntime *rt)
+  : gc(nullptr)
+{
+    disallowAlloc(rt);
+}
+
+void JS::AutoAssertNoAlloc::disallowAlloc(JSRuntime *rt)
+{
+    JS_ASSERT(!gc);
+    gc = &rt->gc;
+    gc->disallowAlloc();
+}
+
+JS::AutoAssertNoAlloc::~AutoAssertNoAlloc()
+{
+    if (gc)
+        gc->allowAlloc();
+}
 #endif
 
+JS::AutoAssertGCCallback::AutoAssertGCCallback(JSObject *obj)
+  : AutoSuppressGCAnalysis()
+{
+    MOZ_ASSERT(obj->runtimeFromMainThread()->isHeapMajorCollecting());
+}
+
 #ifdef JSGC_HASH_TABLE_CHECKS
 void
 js::gc::CheckHashTablesAfterMovingGC(JSRuntime *rt)
 {
     /*
      * Check that internal hash tables no longer have any pointers to things
      * that have been moved.
      */
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -690,20 +690,18 @@ class ArenaLists
         return true;
     }
 
     void unmarkAll() {
         for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
             /* The background finalization must have stopped at this point. */
             JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE ||
                       backgroundFinalizeState[i] == BFS_JUST_FINISHED);
-            for (ArenaHeader *aheader = arenaLists[i].head(); aheader; aheader = aheader->next) {
-                uintptr_t *word = aheader->chunk()->bitmap.arenaBits(aheader);
-                memset(word, 0, ArenaBitmapWords * sizeof(uintptr_t));
-            }
+            for (ArenaHeader *aheader = arenaLists[i].head(); aheader; aheader = aheader->next)
+                aheader->unmarkAll();
         }
     }
 
     bool doneBackgroundFinalize(AllocKind kind) const {
         return backgroundFinalizeState[kind] == BFS_DONE ||
                backgroundFinalizeState[kind] == BFS_JUST_FINISHED;
     }
 
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -320,47 +320,19 @@ class ZoneCellIterUnderGC : public ZoneC
 #ifdef JSGC_GENERATIONAL
         JS_ASSERT(zone->runtimeFromAnyThread()->gc.nursery.isEmpty());
 #endif
         JS_ASSERT(zone->runtimeFromAnyThread()->isHeapBusy());
         init(zone, kind);
     }
 };
 
-/* In debug builds, assert that no allocation occurs. */
-class AutoAssertNoAlloc
-{
-#ifdef JS_DEBUG
-    GCRuntime *gc;
-
-  public:
-    AutoAssertNoAlloc() : gc(nullptr) {}
-    explicit AutoAssertNoAlloc(JSRuntime *rt) : gc(nullptr) {
-        disallowAlloc(rt);
-    }
-    void disallowAlloc(JSRuntime *rt) {
-        JS_ASSERT(!gc);
-        gc = &rt->gc;
-        gc->disallowAlloc();
-    }
-    ~AutoAssertNoAlloc() {
-        if (gc)
-            gc->allowAlloc();
-    }
-#else
-  public:
-    AutoAssertNoAlloc() {}
-    explicit AutoAssertNoAlloc(JSRuntime *) {}
-    void disallowAlloc(JSRuntime *rt) {}
-#endif
-};
-
 class ZoneCellIter : public ZoneCellIterImpl
 {
-    AutoAssertNoAlloc noAlloc;
+    JS::AutoAssertNoAlloc noAlloc;
     ArenaLists *lists;
     AllocKind kind;
 
   public:
     ZoneCellIter(JS::Zone *zone, AllocKind kind)
       : lists(&zone->allocator.arenas),
         kind(kind)
     {
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -658,16 +658,22 @@ JSObject::finish(js::FreeOp *fop)
                 // so that other objects can access these elements while they
                 // are themselves finalized.
                 fop->freeLater(elements);
             }
         } else {
             fop->free_(elements);
         }
     }
+
+    // It's possible that unreachable shapes may be marked whose listp points
+    // into this object. In case this happens, null out the shape's pointer here
+    // so that a moving GC will not try to access the dead object.
+    if (shape_->listp == &shape_)
+        shape_->listp = nullptr;
 }
 
 /* static */ inline bool
 JSObject::hasProperty(JSContext *cx, js::HandleObject obj,
                       js::HandleId id, bool *foundp)
 {
     JS::RootedObject pobj(cx);
     js::RootedShape prop(cx);
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -66,18 +66,22 @@ WeakMapBase::unmarkCompartment(JSCompart
 {
     for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next)
         m->marked = false;
 }
 
 void
 WeakMapBase::markAll(JSCompartment *c, JSTracer *tracer)
 {
-    for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next)
-        m->markIteratively(tracer);
+    JS_ASSERT(tracer->eagerlyTraceWeakMaps() != DoNotTraceWeakMaps);
+    for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next) {
+        m->trace(tracer);
+        if (m->memberOf)
+            gc::MarkObject(tracer, &m->memberOf, "memberOf");
+    }
 }
 
 bool
 WeakMapBase::markCompartmentIteratively(JSCompartment *c, JSTracer *tracer)
 {
     bool markedAny = false;
     for (WeakMapBase *m = c->gcWeakMapList; m; m = m->next) {
         if (m->marked && m->markIteratively(tracer))
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -86,17 +86,17 @@ class WeakMapBase {
     virtual void nonMarkingTraceValues(JSTracer *tracer) = 0;
     virtual bool markIteratively(JSTracer *tracer) = 0;
     virtual bool findZoneEdges() = 0;
     virtual void sweep() = 0;
     virtual void traceMappings(WeakMapTracer *tracer) = 0;
     virtual void finish() = 0;
 
     // Object that this weak map is part of, if any.
-    JSObject *memberOf;
+    HeapPtrObject memberOf;
 
     // Compartment that this weak map is part of.
     JSCompartment *compartment;
 
     // Link in a list of all WeakMaps in a compartment, headed by
     // JSCompartment::gcWeakMapList. The last element of the list has nullptr as
     // its next. Maps not in the list have WeakMapNotInList as their next.
     WeakMapBase *next;
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -767,20 +767,23 @@ RegExpCompartment::sweep(JSRuntime *rt)
         // stack is traced but is not in a zone being collected.
         //
         // Because of this we only treat the marked_ bit as a hint, and destroy
         // the RegExpShared if it was accidentally marked earlier but wasn't
         // marked by the current trace.
         bool keep = shared->marked() && !IsStringAboutToBeFinalized(shared->source.unsafeGet());
         for (size_t i = 0; i < ArrayLength(shared->compilationArray); i++) {
             RegExpShared::RegExpCompilation &compilation = shared->compilationArray[i];
-            if (keep && compilation.jitCode)
-                keep = !IsJitCodeAboutToBeFinalized(compilation.jitCode.unsafeGet());
+            if (compilation.jitCode &&
+                IsJitCodeAboutToBeFinalized(compilation.jitCode.unsafeGet()))
+            {
+                keep = false;
+            }
         }
-        if (keep) {
+        if (keep || rt->isHeapCompacting()) {
             shared->clearMarked();
         } else {
             js_delete(shared);
             e.removeFront();
         }
     }
 
     if (matchResultTemplateObject_ &&
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -194,17 +194,17 @@ class RegExpShared
     bool isCompiled() const {
         return isCompiled(Normal, true) || isCompiled(Normal, false)
             || isCompiled(MatchOnly, true) || isCompiled(MatchOnly, false);
     }
 
     void trace(JSTracer *trc);
 
     bool marked() const { return marked_; }
-    void clearMarked() { JS_ASSERT(marked_); marked_ = false; }
+    void clearMarked() { marked_ = false; }
 
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 /*
  * Extend the lifetime of a given RegExpShared to at least the lifetime of
  * the guard object. See Regular Expression comment at the top.
  */
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -892,19 +892,16 @@ static const JSFunctionSpec intrinsic_fu
               intrinsic_TypeDescrIsSizedArrayType,
               &js::TypeDescrIsSizedArrayTypeJitInfo, 1, 0),
     JS_FNINFO("TypeDescrIsSimpleType",
               intrinsic_TypeDescrIsSimpleType,
               &js::TypeDescrIsSimpleTypeJitInfo, 1, 0),
     JS_FNINFO("ClampToUint8",
               JSNativeThreadSafeWrapper<js::ClampToUint8>,
               &js::ClampToUint8JitInfo, 1, 0),
-    JS_FNINFO("Memcpy",
-              JSNativeThreadSafeWrapper<js::Memcpy>,
-              &js::MemcpyJitInfo, 5, 0),
     JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
     JS_FN("GetFloat32x4TypeDescr", js::GetFloat32x4TypeDescr, 0, 0),
     JS_FN("GetInt32x4TypeDescr", js::GetInt32x4TypeDescr, 0, 0),
 
 #define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name)               \
     JS_FNINFO("Store_" #_name,                                                \
               JSNativeThreadSafeWrapper<js::StoreScalar##_type::Func>,        \
               &js::StoreScalar##_type::JitInfo, 3, 0),                        \
--- a/js/xpconnect/public/SandboxPrivate.h
+++ b/js/xpconnect/public/SandboxPrivate.h
@@ -44,15 +44,20 @@ public:
         return GetWrapper();
     }
 
     void ForgetGlobalObject()
     {
         ClearWrapper();
     }
 
+    void ObjectMoved(JSObject *obj, const JSObject *old)
+    {
+        UpdateWrapper(obj, old);
+    }
+
 private:
     virtual ~SandboxPrivate() { }
 
     nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 #endif // __SANDBOXPRIVATE_H__
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -305,30 +305,39 @@ sandbox_enumerate(JSContext *cx, HandleO
 static bool
 sandbox_resolve(JSContext *cx, HandleObject obj, HandleId id)
 {
     bool resolved;
     return JS_ResolveStandardClass(cx, obj, id, &resolved);
 }
 
 static void
-sandbox_finalize(JSFreeOp *fop, JSObject *obj)
+sandbox_finalize(js::FreeOp *fop, JSObject *obj)
 {
     nsIScriptObjectPrincipal *sop =
         static_cast<nsIScriptObjectPrincipal *>(xpc_GetJSPrivate(obj));
     if (!sop) {
         // sop can be null if CreateSandboxObject fails in the middle.
         return;
     }
 
     static_cast<SandboxPrivate *>(sop)->ForgetGlobalObject();
     NS_RELEASE(sop);
     DestroyProtoAndIfaceCache(obj);
 }
 
+static void
+sandbox_moved(JSObject *obj, const JSObject *old)
+{
+    nsIScriptObjectPrincipal *sop =
+        static_cast<nsIScriptObjectPrincipal *>(xpc_GetJSPrivate(obj));
+    MOZ_ASSERT(sop);
+    static_cast<SandboxPrivate *>(sop)->ObjectMoved(obj, old);
+}
+
 static bool
 sandbox_convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp)
 {
     if (type == JSTYPE_OBJECT) {
         vp.set(OBJECT_TO_JSVAL(obj));
         return true;
     }
 
@@ -438,45 +447,65 @@ sandbox_addProperty(JSContext *cx, Handl
                                writeToProto_getProperty, writeToProto_setProperty))
         return false;
 
     return true;
 }
 
 #define XPCONNECT_SANDBOX_CLASS_METADATA_SLOT (XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET)
 
-static const JSClass SandboxClass = {
+static const js::Class SandboxClass = {
     "Sandbox",
     XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
     JS_PropertyStub,   JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     sandbox_enumerate, sandbox_resolve, sandbox_convert,  sandbox_finalize,
-    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook
+    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
+    JS_NULL_CLASS_SPEC,
+    {
+      nullptr,      /* outerObject */
+      nullptr,      /* innerObject */
+      nullptr,      /* iteratorObject */
+      false,        /* isWrappedNative */
+      nullptr,      /* weakmapKeyDelegateOp */
+      sandbox_moved /* objectMovedOp */
+    },
+    JS_NULL_OBJECT_OPS
 };
 
 // Note to whomever comes here to remove addProperty hooks: billm has promised
 // to do the work for this class.
-static const JSClass SandboxWriteToProtoClass = {
+static const js::Class SandboxWriteToProtoClass = {
     "Sandbox",
     XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1),
     sandbox_addProperty,   JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     sandbox_enumerate, sandbox_resolve, sandbox_convert,  sandbox_finalize,
-    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook
+    nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook,
+    JS_NULL_CLASS_SPEC,
+    {
+      nullptr,      /* outerObject */
+      nullptr,      /* innerObject */
+      nullptr,      /* iteratorObject */
+      false,        /* isWrappedNative */
+      nullptr,      /* weakmapKeyDelegateOp */
+      sandbox_moved /* objectMovedOp */
+    },
+    JS_NULL_OBJECT_OPS
 };
 
 static const JSFunctionSpec SandboxFunctions[] = {
     JS_FS("dump",    SandboxDump,    1,0),
     JS_FS("debug",   SandboxDebug,   1,0),
     JS_FS("importFunction", SandboxImport, 1,0),
     JS_FS_END
 };
 
 bool
 xpc::IsSandbox(JSObject *obj)
 {
-    const JSClass *clasp = GetObjectJSClass(obj);
+    const Class *clasp = GetObjectClass(obj);
     return clasp == &SandboxClass || clasp == &SandboxWriteToProtoClass;
 }
 
 /***************************************************************************/
 nsXPCComponents_utils_Sandbox::nsXPCComponents_utils_Sandbox()
 {
 }
 
@@ -856,21 +885,21 @@ xpc::CreateSandboxObject(JSContext *cx, 
         NS_ENSURE_TRUE(addonId, NS_ERROR_FAILURE);
     } else if (JSObject *obj = JS::CurrentGlobalOrNull(cx)) {
         if (JSAddonId *id = JS::AddonIdOfObject(obj))
             addonId = id;
     }
 
     compartmentOptions.setAddonId(addonId);
 
-    const JSClass *clasp = options.writeToGlobalPrototype
-                         ? &SandboxWriteToProtoClass
-                         : &SandboxClass;
+    const Class *clasp = options.writeToGlobalPrototype
+                       ? &SandboxWriteToProtoClass
+                       : &SandboxClass;
 
-    RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, clasp,
+    RootedObject sandbox(cx, xpc::CreateGlobalObject(cx, js::Jsvalify(clasp),
                                                      principal, compartmentOptions));
     if (!sandbox)
         return NS_ERROR_FAILURE;
 
     CompartmentPrivate::Get(sandbox)->writeToGlobalPrototype =
       options.writeToGlobalPrototype;
 
     // Set up the wantXrays flag, which indicates whether xrays are desired even
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -987,16 +987,30 @@ XPCWrappedNative::FlatJSObjectFinalized(
 
     // Note that it's not safe to touch mNativeWrapper here since it's
     // likely that it has already been finalized.
 
     Release();
 }
 
 void
+XPCWrappedNative::FlatJSObjectMoved(JSObject *obj, const JSObject *old)
+{
+    JS::AutoAssertGCCallback inCallback(obj);
+    MOZ_ASSERT(mFlatJSObject == old);
+
+    nsWrapperCache *cache = nullptr;
+    CallQueryInterface(mIdentity, &cache);
+    if (cache)
+        cache->UpdateWrapper(obj, old);
+
+    mFlatJSObject = obj;
+}
+
+void
 XPCWrappedNative::SystemIsBeingShutDown()
 {
     if (!IsValid())
         return;
 
     // The long standing strategy is to leak some objects still held at shutdown.
     // The general problem is that propagating release out of xpconnect at
     // shutdown time causes a world of problems.
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -568,16 +568,27 @@ WrappedNativeFinalize(js::FreeOp *fop, J
 
     XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
     if (helperType == WN_HELPER)
         wrapper->GetScriptableCallback()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj);
     wrapper->FlatJSObjectFinalized();
 }
 
 static void
+WrappedNativeObjectMoved(JSObject *obj, const JSObject *old)
+{
+    nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj));
+    if (!p)
+        return;
+
+    XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p);
+    wrapper->FlatJSObjectMoved(obj, old);
+}
+
+static void
 XPC_WN_NoHelper_Finalize(js::FreeOp *fop, JSObject *obj)
 {
     WrappedNativeFinalize(fop, obj, WN_NOHELPER);
 }
 
 /*
  * General comment about XPConnect tracing: Given a C++ object |wrapper| and its
  * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS
@@ -653,17 +664,19 @@ const XPCWrappedNativeJSClass XPC_WN_NoH
     XPCWrappedNative::Trace,         // trace
     JS_NULL_CLASS_SPEC,
 
     // ClassExtension
     {
         nullptr, // outerObject
         nullptr, // innerObject
         nullptr, // iteratorObject
-        true,   // isWrappedNative
+        true,    // isWrappedNative
+        nullptr, // weakmapKeyDelegateOp
+        WrappedNativeObjectMoved
     },
 
     // ObjectOps
     {
         nullptr, // lookupGeneric
         nullptr, // lookupProperty
         nullptr, // lookupElement
         nullptr, // defineGeneric
@@ -1160,16 +1173,17 @@ XPCNativeScriptableShared::PopulateJSCla
         mJSClass.base.hasInstance = XPC_WN_Helper_HasInstance;
 
     if (mFlags.IsGlobalObject())
         mJSClass.base.trace = JS_GlobalObjectTraceHook;
     else
         mJSClass.base.trace = XPCWrappedNative::Trace;
 
     mJSClass.base.ext.isWrappedNative = true;
+    mJSClass.base.ext.objectMovedOp = WrappedNativeObjectMoved;
 }
 
 /***************************************************************************/
 /***************************************************************************/
 
 // Compatibility hack.
 //
 // XPConnect used to do all sorts of funny tricks to find the "correct"
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2136,16 +2136,17 @@ public:
     ReparentWrapperIfFound(XPCWrappedNativeScope* aOldScope,
                            XPCWrappedNativeScope* aNewScope,
                            JS::HandleObject aNewParent,
                            nsISupports* aCOMObj);
 
     nsresult RescueOrphans();
 
     void FlatJSObjectFinalized();
+    void FlatJSObjectMoved(JSObject *obj, const JSObject *old);
 
     void SystemIsBeingShutDown();
 
     enum CallMode {CALL_METHOD, CALL_GETTER, CALL_SETTER};
 
     static bool CallMethod(XPCCallContext& ccx,
                            CallMode mode = CALL_METHOD);
 
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -1397,17 +1397,17 @@ nsBidiPresUtils::RepositionFrame(nsIFram
   // bidiUtils->ReorderFrames, so this is guaranteed to be after the inlines
   // have been reflowed, which is required for GetUsedMargin/Border/Padding
   LogicalMargin margin(aLineWM, aFrame->GetUsedMargin());
   if (isFirst) {
     aStart += margin.IStart(aLineWM);
   }
 
   nscoord start = aStart;
-  nscoord frameWidth = aFrame->GetSize().width;
+  nscoord frameISize = aFrame->ISize(aLineWM);
 
   if (!IsBidiLeaf(aFrame))
   {
     nscoord iCoord = 0;
     LogicalMargin borderPadding(frameWM, aFrame->GetUsedBorderAndPadding());
     if (isFirst) {
       iCoord += borderPadding.IStart(frameWM);
     }
@@ -1431,29 +1431,29 @@ nsBidiPresUtils::RepositionFrame(nsIFram
     // Reposition the child frames
     int32_t index = 0;
     while (frame) {
       RepositionFrame(frame,
                       aIsEvenLevel,
                       iCoord,
                       aContinuationStates,
                       frameWM,
-                      frameWidth);
+                      frameISize);
       index++;
       frame = reverseOrder ?
                 childList[childList.Length() - index - 1] :
                 frame->GetNextSibling();
     }
 
     if (isLast) {
       iCoord += borderPadding.IEnd(frameWM);
     }
     aStart += iCoord;
   } else {
-    aStart += frameWidth;
+    aStart += frameISize;
   }
 
   LogicalRect logicalRect(aLineWM, aFrame->GetRect(), aLineWidth);
   logicalRect.IStart(aLineWM) = start;
   logicalRect.ISize(aLineWM) = aStart - start;
   aFrame->SetRect(aLineWM, logicalRect, aLineWidth);
 
   if (isLast) {
--- a/layout/generic/test/test_backspace_delete.xul
+++ b/layout/generic/test/test_backspace_delete.xul
@@ -28,33 +28,50 @@ function execTests() {
     var n = editor.firstChild;
     if (node) {
       n = node();
     }
     sel.collapse(n, firstChildOffsetForCaret);
   }
 
   var eatSpace;
+  var deleteImmediately;
 
-  function getPrefs() {
+  function getPrefs(branch) {
     const prefSvcContractID = "@mozilla.org/preferences-service;1";
     const prefSvcIID = Components.interfaces.nsIPrefService;
     return Components.classes[prefSvcContractID].getService(prefSvcIID)
-                                                 .getBranch("layout.word_select.");
+                                                 .getBranch(branch);
+  }
+
+  function setPref(branch, pref, newValue) {
+    getPrefs(branch).setBoolPref(pref, newValue);
+    return newValue;
+  }
+
+  function restorePref(branch, pref, newValue) {
+    try {
+      getPrefs(branch).clearUserPref(pref);
+    } catch(ex) {}
   }
 
   function setEatSpace(newValue) {
-    getPrefs().setBoolPref("eat_space_to_next_word", newValue);
-    eatSpace = newValue;
+    eatSpace = setPref("layout.word_select.", "eat_space_to_next_word", newValue);
   }
 
   function restoreEatSpace() {
-    try {
-      getPrefs().clearUserPref("eat_space_to_next_word");
-    } catch(ex) {}
+    restorePref("layout.word_select.", "eat_space_to_next_word");
+  }
+
+  function setDeleteImmediately(newValue) {
+    deleteImmediately = setPref("bidi.edit.", "delete_immediately", newValue);
+  }
+
+  function restoreDeleteImmediately() {
+    restorePref("bidi.edit.", "delete_immediately");
   }
 
   function doCommand(cmd) {
     var controller = document.commandDispatcher.getControllerForCommand(cmd);
     if (controller) {
       try {
         controller.doCommand(cmd);
         ok(true, 'doCommand(' + cmd + ') succeeded');
@@ -81,30 +98,30 @@ function execTests() {
     is(selRange.startContainer, startNode, selErrString("Word right"));
     is(selRange.startOffset, startOffset, selErrString("Word right"));
     is(selRange.endContainer, endNode, selErrString("Word right"));
     is(selRange.endOffset, endOffset, selErrString("Word right"));
   }
 
   function testDelete(node, offset, text, richtext) {
     doCommand("cmd_deleteCharForward");
-    var msg = "Delete broken in \"" + editor.innerHTML + "\", offset " + offset;
+    var msg = "Delete broken in \"" + editor.innerHTML + "\", offset " + offset + " with deleteImmediately=" + deleteImmediately;
     if(typeof node == 'function'){
       node = node();
     }
     is(sel.anchorNode, node, msg);
 
     is(sel.anchorOffset, offset, msg);
     let text_result = richtext ? editor.innerHTML : editor.textContent;
     is(text_result, text, msg);
   }
 
   function testBackspace(node, offset, text) {
     doCommand("cmd_deleteCharBackward");
-    var msg = "Backspace broken in \"" + editor.innerHTML + "\", offset " + offset;
+    var msg = "Backspace broken in \"" + editor.innerHTML + "\", offset " + offset + " with deleteImmediately=" + deleteImmediately;
     is(sel.anchorNode, node, msg);
 
     is(sel.anchorOffset, offset, msg);
     is(editor.textContent, text, msg);
   }
 
   function testDeletePrevWord(node, offset, text) {
     doCommand("cmd_deleteWordBackward");
@@ -190,20 +207,48 @@ function execTests() {
 
   // Tests for Bug 419217
 
   setupTest("foo<div>bar</div>", 3);
   testDelete(function(){return editor.firstChild;}, 3, "foobar", true);
 
   // Tests for Bug 419406
   var s = "helloשלום";
+
+  setDeleteImmediately(true);
+
+  setupTest(s, 4);
+  testRight(editor.firstChild, 5);
+  testDelete(editor.firstChild, 5, "helloלום");
+
+  setDeleteImmediately(false);
+
   setupTest(s, 4);
   testRight(editor.firstChild, 5);
   testDelete(editor.firstChild, 5, "helloשלום");
 
+  // Tests for bug 1034337
+  s = "اهلاhello";
+
+  setDeleteImmediately(true);
+
+  setupTest(s, 4);
+  // first delete an ltr character to make sure that the caret is ltr
+  testDelete(editor.firstChild, 4, "اهلاello");
+  testBackspace(editor.firstChild, 3, "اهلello");
+
+  setDeleteImmediately(false);
+
+  setupTest(s, 4);
+  // first delete an ltr character to make sure that the caret is ltr
+  testDelete(editor.firstChild, 4, "اهلاello");
+  testBackspace(editor.firstChild, 4, "اهلاello");
+
+  restoreDeleteImmediately();
+
   // Tests for Bug 462188
   setupTest("You should not see this text.", 29);
   testDeletePrevWord(editor.firstChild, 24, "You should not see this ");
   testDeletePrevWord(editor.firstChild, 19, "You should not see ");
   testDeletePrevWord(editor.firstChild, 15, "You should not ");
   testDeletePrevWord(editor.firstChild, 11, "You should ");
   testDeletePrevWord(editor.firstChild,  4, "You ");
   testDeletePrevWord(editor,  0, "");
--- a/mfbt/tests/TestJSONWriter.cpp
+++ b/mfbt/tests/TestJSONWriter.cpp
@@ -289,26 +289,28 @@ void TestBasicElements()
   w.EndArray();
   w.End();
 
   Check(w.WriteFunc(), expected);
 }
 
 void TestStringEscaping()
 {
+  // This test uses hexadecimal character escapes because UTF8 literals cause
+  // problems for some compilers (see bug 1069726).
   const char* expected = "\
 {\n\
- \"ascii\": \"~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\\\"! \\u001f\\u001e\\u001d\\u001c\\u001b\\u001a\\u0019\\u0018\\u0017\\u0016\\u0015\\u0014\\u0013\\u0012\\u0011\\u0010\\u000f\\u000e\\r\\f\\u000b\\n\\t\\b\\u0007\\u0006\\u0005\\u0004\\u0003\\u0002\\u0001\",\n\
- \"مرحبا هناك\": true,\n\
- \"բարեւ չկա\": -123,\n\
- \"你好\": 1.234,\n\
- \"γεια εκεί\": \"سلام\",\n\
- \"halló þarna\": \"0x1234\",\n\
- \"こんにちは\": {\n\
-  \"привет\": [\n\
+ \"ascii\": \"\x7F~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\\\"! \\u001f\\u001e\\u001d\\u001c\\u001b\\u001a\\u0019\\u0018\\u0017\\u0016\\u0015\\u0014\\u0013\\u0012\\u0011\\u0010\\u000f\\u000e\\r\\f\\u000b\\n\\t\\b\\u0007\\u0006\\u0005\\u0004\\u0003\\u0002\\u0001\",\n\
+ \"\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 \xD9\x87\xD9\x86\xD8\xA7\xD9\x83\": true,\n\
+ \"\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1\": -123,\n\
+ \"\xE4\xBD\xA0\xE5\xA5\xBD\": 1.234,\n\
+ \"\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF\": \"\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85\",\n\
+ \"hall\xC3\xB3 \xC3\xBE" "arna\": \"0x1234\",\n\
+ \"\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF\": {\n\
+  \"\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82\": [\n\
   ]\n\
  }\n\
 }\n\
 ";
 
   JSONWriter w(MakeUnique<StringWriteFunc>());
 
   // Test the string escaping behaviour.
@@ -318,24 +320,24 @@ void TestStringEscaping()
     // at the end serves as the null char.
     char buf[128];
     for (int i = 0; i < 128; i++) {
       buf[i] = 127 - i;
     }
     w.StringProperty("ascii", buf);
 
     // Test lots of unicode stuff. Note that this file is encoded as UTF-8.
-    w.BoolProperty("مرحبا هناك", true);
-    w.IntProperty("բարեւ չկա", -123);
-    w.DoubleProperty("你好", 1.234);
-    w.StringProperty("γεια εκεί", "سلام");
-    w.PointerProperty("halló þarna", (void*)0x1234);
-    w.StartObjectProperty("こんにちは");
+    w.BoolProperty("\xD9\x85\xD8\xB1\xD8\xAD\xD8\xA8\xD8\xA7 \xD9\x87\xD9\x86\xD8\xA7\xD9\x83", true);
+    w.IntProperty("\xD5\xA2\xD5\xA1\xD6\x80\xD5\xA5\xD6\x82 \xD5\xB9\xD5\xAF\xD5\xA1", -123);
+    w.DoubleProperty("\xE4\xBD\xA0\xE5\xA5\xBD", 1.234);
+    w.StringProperty("\xCE\xB3\xCE\xB5\xCE\xB9\xCE\xB1 \xCE\xB5\xCE\xBA\xCE\xB5\xCE\xAF", "\xD8\xB3\xD9\x84\xD8\xA7\xD9\x85");
+    w.PointerProperty("hall\xC3\xB3 \xC3\xBE" "arna", (void*)0x1234);
+    w.StartObjectProperty("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1\xE3\x81\xAF");
     {
-      w.StartArrayProperty("привет");
+      w.StartArrayProperty("\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82");
       w.EndArray();
     }
     w.EndObject();
   }
   w.End();
 
   Check(w.WriteFunc(), expected);
 }
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -314,17 +314,17 @@ nsJARChannel::CreateJarInput(nsIZipReade
     // Make GetContentLength meaningful
     mContentLength = input->GetContentLength();
 
     input.forget(resultInput);
     return NS_OK;
 }
 
 nsresult
-nsJARChannel::LookupFile()
+nsJARChannel::LookupFile(bool aAllowAsync)
 {
     LOG(("nsJARChannel::LookupFile [this=%x %s]\n", this, mSpec.get()));
 
     if (mJarFile)
         return NS_OK;
 
     nsresult rv;
     nsCOMPtr<nsIURI> uri;
@@ -382,16 +382,21 @@ nsJARChannel::LookupFile()
                     jarCache->GetFd(mJarFile, &fd);
                     if (fd) {
                         return SetRemoteNSPRFileDesc(fd);
                     }
                     #endif
                 }
             }
 
+            if (!aAllowAsync) {
+                mJarFile = nullptr;
+                return NS_OK;
+            }
+
             mOpeningRemote = true;
 
             #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
             #else
             if (mEnsureChildFd && jarCache) {
                 jarCache->SetMustCacheFd(remoteFile, true);
             }
             #endif
@@ -793,17 +798,17 @@ nsJARChannel::Open(nsIInputStream **stre
     LOG(("nsJARChannel::Open [this=%x]\n", this));
 
     NS_ENSURE_TRUE(!mOpened, NS_ERROR_IN_PROGRESS);
     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
 
     mJarFile = nullptr;
     mIsUnsafe = true;
 
-    nsresult rv = LookupFile();
+    nsresult rv = LookupFile(false);
     if (NS_FAILED(rv))
         return rv;
 
     // If mJarInput was not set by LookupFile, the JAR is a remote jar.
     if (!mJarFile) {
         NS_NOTREACHED("need sync downloader");
         return NS_ERROR_NOT_IMPLEMENTED;
     }
@@ -830,17 +835,17 @@ nsJARChannel::AsyncOpen(nsIStreamListene
     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
 
     mJarFile = nullptr;
     mIsUnsafe = true;
 
     // Initialize mProgressSink
     NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, mProgressSink);
 
-    nsresult rv = LookupFile();
+    nsresult rv = LookupFile(true);
     if (NS_FAILED(rv))
         return rv;
 
     // These variables must only be set if we're going to trigger an
     // OnStartRequest, either from AsyncRead or OnDownloadComplete.
     // 
     // That means: Do not add early return statements beyond this point!
     mListener = listener;
@@ -905,17 +910,17 @@ nsJARChannel::GetJarFile(nsIFile **aFile
 {
     NS_IF_ADDREF(*aFile = mJarFile);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsJARChannel::GetZipEntry(nsIZipEntry **aZipEntry)
 {
-    nsresult rv = LookupFile();
+    nsresult rv = LookupFile(false);
     if (NS_FAILED(rv))
         return rv;
 
     if (!mJarFile)
         return NS_ERROR_NOT_AVAILABLE;
 
     nsCOMPtr<nsIZipReader> reader;
     rv = gJarHandler->JarCache()->GetZip(mJarFile, getter_AddRefs(reader));
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -53,17 +53,17 @@ public:
     nsJARChannel();
 
     nsresult Init(nsIURI *uri);
 
 private:
     virtual ~nsJARChannel();
 
     nsresult CreateJarInput(nsIZipReaderCache *, nsJARInputThunk **);
-    nsresult LookupFile();
+    nsresult LookupFile(bool aAllowAsync);
     nsresult OpenLocalFile();
     void NotifyError(nsresult aError);
     void FireOnProgress(uint64_t aProgress);
     nsresult SetRemoteNSPRFileDesc(PRFileDesc *fd);
 
 #if defined(PR_LOGGING)
     nsCString                       mSpec;
 #endif
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1919,17 +1919,17 @@ pref("bidi.numeral", 0);
 // ------------------
 // 1 = mozillaBidisupport *
 // 2 = OsBidisupport
 // 3 = disableBidisupport
 pref("bidi.support", 1);
 // Whether delete and backspace should immediately delete characters not
 // visually adjacent to the caret, or adjust the visual position of the caret
 // on the first keypress and delete the character on a second keypress
-pref("bidi.edit.delete_immediately", false);
+pref("bidi.edit.delete_immediately", true);
 
 // Bidi caret movement style:
 // 0 = logical
 // 1 = visual
 // 2 = visual, but logical during selection
 pref("bidi.edit.caret_movement_style", 2);
 
 // Setting this pref to |true| forces Bidi UI menu items and keyboard shortcuts
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -1555,8 +1555,15 @@ class Marionette(object):
         An error will be returned if the requested window size would result
         in the window being in the maximised state.
 
         :param width: The width to resize the window to.
         :param height: The height to resize the window to.
 
         """
         self._send_message("setWindowSize", "ok", width=width, height=height)
+
+    def maximize_window(self):
+        """ Resize the browser window currently receiving commands. The action
+        should be equivalent to the user pressing the the maximize button
+        """
+
+        return self._send_message("maximizeWindow", "ok")
--- a/testing/marionette/client/marionette/tests/unit/test_set_window_size.py
+++ b/testing/marionette/client/marionette/tests/unit/test_set_window_size.py
@@ -48,8 +48,28 @@ class TestSetWindowSize(MarionetteTestCa
         height = self.max_height - 100
         self.marionette.set_window_size(width, height)
         # invalid size (cannot maximize)
         with self.assertRaisesRegexp(MarionetteException, "Invalid requested size"):
             self.marionette.set_window_size(self.max_width, self.max_height)
         size = self.marionette.window_size
         self.assertEqual(size['width'], width, "Window width should not have changed")
         self.assertEqual(size['height'], height, "Window height should not have changed")
+
+    def test_that_we_can_maximise_the_window(self):
+        # valid size
+        width = self.max_width - 100
+        height = self.max_height - 100
+        self.marionette.set_window_size(width, height)
+
+        # event handler
+        self.marionette.execute_script("""
+        window.wrappedJSObject.rcvd_event = false;
+        window.onresize = function() {
+            window.wrappedJSObject.rcvd_event = true;
+        };
+        """)
+        self.marionette.maximize_window()
+        self.wait_for_condition(lambda m: m.execute_script("return window.wrappedJSObject.rcvd_event;"))
+
+        size = self.marionette.window_size
+        self.assertEqual(size['width'], self.max_width, "Window width does not use availWidth")
+        self.assertEqual(size['height'], self.max_height, "Window height does not use availHeight")
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -2440,16 +2440,35 @@ MarionetteServerConnection.prototype = {
       return;
     }
 
     curWindow.resizeTo(width, height);
     this.sendOk(this.command_id);
   },
 
   /**
+   * Maximizes the Browser Window as if the user pressed the maximise button
+   *
+   * Not Supported on B2G or Fennec
+   */
+  maximizeWindow: function MDA_maximizeWindow (aRequest) {
+    this.command_id = this.getCommandId();
+
+    if (appName !== "Firefox") {
+      this.sendError("Not supported for mobile", 405, null, this.command_id);
+      return;
+    }
+
+    let curWindow = this.getCurrentWindow();
+    curWindow.moveTo(0,0);
+    curWindow.resizeTo(curWindow.screen.availWidth, curWindow.screen.availHeight);
+    this.sendOk(this.command_id);
+  },
+
+  /**
    * Helper function to convert an outerWindowID into a UID that Marionette
    * tracks.
    */
   generateFrameId: function MDA_generateFrameId(id) {
     let uid = id + (appName == "B2G" ? "-b2g" : "");
     return uid;
   },
 
@@ -2648,17 +2667,18 @@ MarionetteServerConnection.prototype.req
   "getCookies": MarionetteServerConnection.prototype.getCookies,
   "getAllCookies": MarionetteServerConnection.prototype.getCookies,  // deprecated
   "deleteAllCookies": MarionetteServerConnection.prototype.deleteAllCookies,
   "deleteCookie": MarionetteServerConnection.prototype.deleteCookie,
   "getActiveElement": MarionetteServerConnection.prototype.getActiveElement,
   "getScreenOrientation": MarionetteServerConnection.prototype.getScreenOrientation,
   "setScreenOrientation": MarionetteServerConnection.prototype.setScreenOrientation,
   "getWindowSize": MarionetteServerConnection.prototype.getWindowSize,
-  "setWindowSize": MarionetteServerConnection.prototype.setWindowSize
+  "setWindowSize": MarionetteServerConnection.prototype.setWindowSize,
+  "maximizeWindow": MarionetteServerConnection.prototype.maximizeWindow
 };
 
 /**
  * Creates a BrowserObj. BrowserObjs handle interactions with the
  * browser, according to the current environment (desktop, b2g, etc.)
  *
  * @param nsIDOMWindow win
  *        The window whose browser needs to be accessed
--- a/toolkit/content/tests/chrome/findbar_window.xul
+++ b/toolkit/content/tests/chrome/findbar_window.xul
@@ -387,34 +387,16 @@
          "testQuickFindText: find field is not focused");
 
       enterStringIntoFindField(SEARCH_TEXT);
       ok(gBrowser.contentWindow.getSelection() == SEARCH_TEXT,
          "testQuickFindText: failed to find '" + SEARCH_TEXT + "'");
       testClipboardSearchString(SEARCH_TEXT);
     }
 
-    // Perform an async function in serial on each of the list items.
-    function asyncForEach(list, async, callback) {
-      let i = 0;
-      let len = list.length;
-
-      if (!len)
-        return callback();
-
-      async(list[i], function handler() {
-          i++;
-          if (i < len) {
-            async(list[i], handler, i);
-          } else {
-            callback();
-          }
-      }, i);
-    }
-
     function testFindCountUI(callback) {
       clearFocus();
       document.getElementById("cmd_find").doCommand();
 
       ok(!gFindBar.hidden, "testFindCountUI: failed to open findbar");
       ok(document.commandDispatcher.focusedElement == gFindBar._findField.inputField,
          "testFindCountUI: find field is not focused");
 
@@ -439,56 +421,55 @@
         text: "texxx",
         current: 0,
         total: 0
       }];
       let regex = /([\d]*)\sof\s([\d]*)/;
       let timeout = gFindBar._matchesCountTimeoutLength + 20;
 
       function assertMatches(aTest, aMatches) {
-        window.opener.wrappedJSObject.SimpleTest.is(aTest.current, aMatches[1],
+        window.opener.wrappedJSObject.SimpleTest.is(aMatches[1], aTest.current,
           "Currently highlighted match should be at " + aTest.current);
-        window.opener.wrappedJSObject.SimpleTest.is(aTest.total, aMatches[2],
+        window.opener.wrappedJSObject.SimpleTest.is(aMatches[2], aTest.total,
           "Total amount of matches should be " + aTest.total);
       }
 
-      function testString(aTest, aNext) {
-        gFindBar.clear();
-        enterStringIntoFindField(aTest.text);
-
-        setTimeout(function() {
+      function* generatorTest() {
+        for (let test of tests) {
+          gFindBar.clear();
+          yield;
+          enterStringIntoFindField(test.text);
+          yield;
           let matches = foundMatches.value.match(regex);
-          if (!aTest.total) {
+          if (!test.total) {
             ok(!matches, "No message should be shown when 0 matches are expected");
-            aNext();
           } else {
-            assertMatches(aTest, matches);
-            let cycleTests = [];
-            let cycles = aTest.total;
-            while (--cycles) {
-              aTest.current++;
-              if (aTest.current > aTest.total)
-                aTest.current = 1;
-              cycleTests.push({
-                current: aTest.current,
-                total: aTest.total
-              });
+            assertMatches(test, matches);
+            for (let i = 1; i < test.total; i++) {
+              gFindBar.onFindAgainCommand();
+              yield;
+              // test.current + 1, test.current + 2, ..., test.total, 1, ..., test.current
+              let current = (test.current + i - 1) % test.total + 1;
+              assertMatches({
+                current: current,
+                total: test.total
+              }, foundMatches.value.match(regex));
             }
-            asyncForEach(cycleTests, function(aCycleTest, aNextCycle) {
-              gFindBar.onFindAgainCommand();
-              setTimeout(function() {
-                assertMatches(aCycleTest, foundMatches.value.match(regex));
-                aNextCycle();
-              }, timeout);
-            }, aNext);
           }
-        }, timeout);
+        }
+        callback();
       }
-
-      asyncForEach(tests, testString, callback);
+      let test = generatorTest();
+      let resultListener = {
+        onMatchesCountResult: function() {
+          test.next();
+        }
+      };
+      gFindBar.browser.finder.addResultListener(resultListener);
+      test.next();
     }
 
     function testClipboardSearchString(aExpected) {
       if (!gHasFindClipboard)
         return;
 
       if (!aExpected)
         aExpected = "";
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -1214,17 +1214,17 @@ extends="chrome://global/content/binding
         </xul:hbox>
         <xul:label anonid="title-overflow-ellipsis" xbl:inherits="selected"
                    class="ac-ellipsis-after ac-comment"/>
         <xul:hbox anonid="extra-box" class="ac-extra" align="center" hidden="true">
           <xul:image class="ac-result-type-tag"/>
           <xul:label class="ac-normal-text ac-comment" xbl:inherits="selected" value=":"/>
           <xul:description anonid="extra" class="ac-normal-text ac-comment" xbl:inherits="selected"/>
         </xul:hbox>
-        <xul:image anonid="type-image" class="ac-type-icon"/>
+        <xul:image anonid="type-image" class="ac-type-icon" xbl:inherits="selected"/>
       </xul:hbox>
       <xul:hbox align="center" class="ac-url-box">
         <xul:spacer class="ac-site-icon"/>
         <xul:image class="ac-action-icon"/>
         <xul:hbox anonid="url-box" class="ac-url" flex="1"
                   onunderflow="_doUnderflow('_url');"
                   onoverflow="_doOverflow('_url');">
           <xul:description anonid="url" class="ac-normal-text ac-url-text"
@@ -1629,39 +1629,47 @@ extends="chrome://global/content/binding
             // Each tag is split by a comma in an undefined order, so sort it
             let sortedTags = tags.split(",").sort().join(", ");
 
             // Emphasize the matching text in the tags
             this._setUpDescription(this._extra, sortedTags);
 
             // Treat tagged matches as bookmarks for the star
             type = "bookmark";
-          } else if (type == "keyword") {
+          // keyword and favicon type results for search engines
+          // have an extra magnifying glass icon after them
+          } else if (type == "keyword" || type == "search favicon") {
             // Configure the extra box for keyword display
             this._extraBox.hidden = false;
             this._extraBox.childNodes[0].hidden = true;
-            this._extraBox.childNodes[1].hidden = false;
+            // The second child node is ":" and it should be hidden for non keyword types
+            this._extraBox.childNodes[1].hidden = type == "keyword" ? false : true;
             this._extraBox.pack = "start";
             this._titleBox.flex = 0;
 
             // Hide the ellipsis so it doesn't take up space.
             this._titleOverflowEllipsis.hidden = true;
 
-            // Put the parameters next to the title if we have any
-            let search = this.getAttribute("text");
-            let params = "";
-            let paramsIndex = search.indexOf(' ');
-            if (paramsIndex != -1)
-              params = search.substr(paramsIndex + 1);
+            if (type == "keyword") {
+              // Put the parameters next to the title if we have any
+              let search = this.getAttribute("text");
+              let params = "";
+              let paramsIndex = search.indexOf(" ");
+              if (paramsIndex != -1)
+                params = search.substr(paramsIndex + 1);
 
-            // Emphasize the keyword parameters
-            this._setUpDescription(this._extra, params);
+              // Emphasize the keyword parameters
+              this._setUpDescription(this._extra, params);
 
-            // Don't emphasize keyword searches in the title or url
-            this.setAttribute("text", "");
+              // Don't emphasize keyword searches in the title or url
+              this.setAttribute("text", "");
+            }
+            // If the result has the type favicon and a known search provider,
+            // customize it the same way as a keyword result.
+            type = "keyword";
           }
 
           // Give the image the icon style and a special one for the type
           this._typeImage.className = "ac-type-icon" +
             (type ? " ac-result-type-" + type : "");
 
           // Show the url as the title if we don't have a title
           if (title == "")
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -443,50 +443,34 @@
           if (!this._pluralForm) {
             this._pluralForm = Components.utils.import(
                                "resource://gre/modules/PluralForm.jsm", {}).PluralForm;
           }
           return this._pluralForm;
         ]]></getter>
       </property>
 
-      <method name="_updateMatchesCountWorker">
-        <parameter name="aRes"/>
-        <body><![CDATA[
-          let word = this._findField.value;
-          if (aRes == this.nsITypeAheadFind.FIND_NOTFOUND || !word) {
-            this._foundMatches.hidden = true;
-            this._foundMatches.value = "";
-          } else {
-            let matchesCount = this.browser.finder.requestMatchesCount(
-              word, this._matchesCountLimit, this._findMode == this.FIND_LINKS);
-            window.clearTimeout(this._updateMatchesCountTimeout);
-            this._updateMatchesCountTimeout = null;
-          }
-        ]]></body>
-      </method>
-
       <!--
         - Updates the search match count after each find operation on a new string.
         - @param aRes
         -        the result of the find operation
         -->
       <method name="_updateMatchesCount">
-        <parameter name="aRes"/>
         <body><![CDATA[
           if (this._matchesCountLimit == 0 || !this._dispatchFindEvent("matchescount"))
             return;
 
           if (this._updateMatchesCountTimeout) {
             window.clearTimeout(this._updateMatchesCountTimeout);
-            this._updateMatchesCountTimeout = null;
           }
           this._updateMatchesCountTimeout =
-            window.setTimeout(() => this._updateMatchesCountWorker(aRes),
-                              this._matchesCountTimeoutLength);
+            window.setTimeout(() => {
+              this.browser.finder.requestMatchesCount(this._findField.value, this._matchesCountLimit,
+                  this._findMode == this.FIND_LINKS);
+            }, this._matchesCountTimeoutLength);
         ]]></body>
       </method>
 
       <!--
         - Turns highlight on or off.
         - @param aHighlight (boolean)
         -        Whether to turn the highlight on or off
         -->
--- a/toolkit/content/widgets/menulist.xml
+++ b/toolkit/content/widgets/menulist.xml
@@ -588,26 +588,16 @@
               this.open = true;
             }
           }
         ]]>
       </handler>
     </handlers>
   </binding>
 
-  <binding id="menulist-compact" display="xul:menu"
-           extends="chrome://global/content/bindings/menulist.xml#menulist">
-    <content sizetopopup="false">
-      <xul:dropmarker class="menulist-dropmarker" type="menu" xbl:inherits="disabled,open"/>
-      <xul:image class="menulist-icon" xbl:inherits="src=image,src"/>
-      <xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
-      <children includes="menupopup"/>
-    </content>
-  </binding>
-
   <binding id="menulist-description" display="xul:menu"
            extends="chrome://global/content/bindings/menulist.xml#menulist">
     <content sizetopopup="pref">
       <xul:hbox class="menulist-label-box" flex="1">
         <xul:image class="menulist-icon" xbl:inherits="src=image,src"/>
         <xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
         <xul:label class="menulist-label menulist-description" xbl:inherits="value=description" crop="right" flex="10000"/>
       </xul:hbox>
--- a/toolkit/modules/Finder.jsm
+++ b/toolkit/modules/Finder.jsm
@@ -6,27 +6,30 @@ this.EXPORTED_SYMBOLS = ["Finder"];
 
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Geometry.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "TextToSubURIService",
                                          "@mozilla.org/intl/texttosuburi;1",
                                          "nsITextToSubURI");
 XPCOMUtils.defineLazyServiceGetter(this, "Clipboard",
                                          "@mozilla.org/widget/clipboard;1",
                                          "nsIClipboard");
 XPCOMUtils.defineLazyServiceGetter(this, "ClipboardHelper",
                                          "@mozilla.org/widget/clipboardhelper;1",
                                          "nsIClipboardHelper");
 
+const kHighlightIterationSizeMax = 100;
+
 function Finder(docShell) {
   this._fastFind = Cc["@mozilla.org/typeaheadfind;1"].createInstance(Ci.nsITypeAheadFind);
   this._fastFind.init(docShell);
 
   this._docShell = docShell;
   this._listeners = [];
   this._previousLink = null;
   this._searchString = null;
@@ -122,42 +125,44 @@ Finder.prototype = {
                                           Ci.nsIClipboard.kFindClipboard,
                                           this._getWindow().document);
   },
 
   set caseSensitive(aSensitive) {
     this._fastFind.caseSensitive = aSensitive;
   },
 
+  _lastFindResult: null,
+
   /**
    * Used for normal search operations, highlights the first match.
    *
    * @param aSearchString String to search for.
    * @param aLinksOnly Only consider nodes that are links for the search.
    * @param aDrawOutline Puts an outline around matched links.
    */
   fastFind: function (aSearchString, aLinksOnly, aDrawOutline) {
-    let result = this._fastFind.find(aSearchString, aLinksOnly);
+    this._lastFindResult = this._fastFind.find(aSearchString, aLinksOnly);
     let searchString = this._fastFind.searchString;
-    this._notify(searchString, result, false, aDrawOutline);
+    this._notify(searchString, this._lastFindResult, false, aDrawOutline);
   },
 
   /**
    * Repeat the previous search. Should only be called after a previous
    * call to Finder.fastFind.
    *
    * @param aFindBackwards Controls the search direction:
    *    true: before current match, false: after current match.
    * @param aLinksOnly Only consider nodes that are links for the search.
    * @param aDrawOutline Puts an outline around matched links.
    */
   findAgain: function (aFindBackwards, aLinksOnly, aDrawOutline) {
-    let result = this._fastFind.findAgain(aFindBackwards, aLinksOnly);
+    this._lastFindResult = this._fastFind.findAgain(aFindBackwards, aLinksOnly);
     let searchString = this._fastFind.searchString;
-    this._notify(searchString, result, aFindBackwards, aDrawOutline);
+    this._notify(searchString, this._lastFindResult, aFindBackwards, aDrawOutline);
   },
 
   /**
    * Forcibly set the search string of the find clipboard to the currently
    * selected text in the window, on supported platforms (i.e. OSX).
    */
   setSearchStringToSelection: function() {
     // Find the selected text.
@@ -169,24 +174,28 @@ Finder.prototype = {
     // Empty strings are rather useless to search for.
     if (!searchString.length)
       return null;
 
     this.clipboardSearchString = searchString;
     return searchString;
   },
 
-  highlight: function (aHighlight, aWord) {
-    let found = this._highlight(aHighlight, aWord, null);
+  highlight: Task.async(function* (aHighlight, aWord) {
+    if (this._abortHighlight) {
+      this._abortHighlight();
+    }
+
+    let found = yield this._highlight(aHighlight, aWord, null);
     if (aHighlight) {
       let result = found ? Ci.nsITypeAheadFind.FIND_FOUND
                          : Ci.nsITypeAheadFind.FIND_NOTFOUND;
       this._notify(aWord, result, false, false, false);
     }
-  },
+  }),
 
   enableSelection: function() {
     this._fastFind.setSelectionModeAndRepaint(Ci.nsISelectionController.SELECTION_ON);
     this._restoreOriginalOutline();
   },
 
   removeSelection: function() {
     this._fastFind.collapseSelection();
@@ -257,38 +266,49 @@ Finder.prototype = {
         controller.scrollLine(false);
         break;
       case Ci.nsIDOMKeyEvent.DOM_VK_DOWN:
         controller.scrollLine(true);
         break;
     }
   },
 
+  _notifyMatchesCount: function(result) {
+    for (let l of this._listeners) {
+      try {
+        l.onMatchesCountResult(result);
+      } catch (ex) {}
+    }
+  },
+
   requestMatchesCount: function(aWord, aMatchLimit, aLinksOnly) {
+    if (this._lastFindResult == Ci.nsITypeAheadFind.FIND_NOTFOUND ||
+        this.searchString == "") {
+      return this._notifyMatchesCount({
+        total: 0,
+        current: 0
+      });
+    }
     let window = this._getWindow();
     let result = this._countMatchesInWindow(aWord, aMatchLimit, aLinksOnly, window);
 
     // Count matches in (i)frames AFTER searching through the main window.
     for (let frame of result._framesToCount) {
       // We've reached our limit; no need to do more work.
       if (result.total == -1 || result.total == aMatchLimit)
         break;
       this._countMatchesInWindow(aWord, aMatchLimit, aLinksOnly, frame, result);
     }
 
     // The `_currentFound` and `_framesToCount` properties are only used for
     // internal bookkeeping between recursive calls.
     delete result._currentFound;
     delete result._framesToCount;
 
-    for (let l of this._listeners) {
-      try {
-        l.onMatchesCountResult(result);
-      } catch (ex) {}
-    }
+    this._notifyMatchesCount(result);
   },
 
   /**
    * Counts the number of matches for the searched word in the passed window's
    * content.
    * @param aWord
    *        the word to search for.
    * @param aMatchLimit
@@ -317,51 +337,47 @@ Finder.prototype = {
       aStats.total = -1;
       return aStats;
     }
 
     this._collectFrames(aWindow, aStats);
 
     let foundRange = this._fastFind.getFoundRange();
 
-    this._findIterator(aWord, aWindow, aRange => {
-      if (!aLinksOnly || this._rangeStartsInLink(aRange)) {
+    for(let range of this._findIterator(aWord, aWindow)) {
+      if (!aLinksOnly || this._rangeStartsInLink(range)) {
         ++aStats.total;
         if (!aStats._currentFound) {
           ++aStats.current;
           aStats._currentFound = (foundRange &&
-            aRange.startContainer == foundRange.startContainer &&
-            aRange.startOffset == foundRange.startOffset &&
-            aRange.endContainer == foundRange.endContainer &&
-            aRange.endOffset == foundRange.endOffset);
+            range.startContainer == foundRange.startContainer &&
+            range.startOffset == foundRange.startOffset &&
+            range.endContainer == foundRange.endContainer &&
+            range.endOffset == foundRange.endOffset);
         }
       }
       if (aStats.total == aMatchLimit) {
         aStats.total = -1;
-        return false;
+        break;
       }
-    });
+    };
 
     return aStats;
   },
 
   /**
-   * Basic wrapper around nsIFind that provides invoking a callback `aOnFind`
-   * each time an occurence of `aWord` string is found.
+   * Basic wrapper around nsIFind that provides a generator yielding
+   * a range each time an occurence of `aWord` string is found.
    *
    * @param aWord
    *        the word to search for.
    * @param aWindow
    *        the window to search in.
-   * @param aOnFind
-   *        the Function to invoke when a word is found. if Boolean `false` is
-   *        returned, the find operation will be stopped and the Function will
-   *        not be invoked again.
    */
-  _findIterator: function(aWord, aWindow, aOnFind) {
+  _findIterator: function* (aWord, aWindow) {
     let doc = aWindow.document;
     let body = (doc instanceof Ci.nsIDOMHTMLDocument && doc.body) ?
                doc.body : doc.documentElement;
 
     if (!body)
       return;
 
     let searchRange = doc.createRange();
@@ -376,23 +392,44 @@ Finder.prototype = {
     let retRange = null;
 
     let finder = Cc["@mozilla.org/embedcomp/rangefind;1"]
                    .createInstance()
                    .QueryInterface(Ci.nsIFind);
     finder.caseSensitive = this._fastFind.caseSensitive;
 
     while ((retRange = finder.Find(aWord, searchRange, startPt, endPt))) {
-      if (aOnFind(retRange) === false)
-        break;
+      yield retRange;
       startPt = retRange.cloneRange();
       startPt.collapse(false);
     }
   },
 
+  _highlightIterator: Task.async(function* (aWord, aWindow, aOnFind) {
+    let count = 0;
+    for (let range of this._findIterator(aWord, aWindow)) {
+      aOnFind(range);
+      if (++count >= kHighlightIterationSizeMax) {
+          count = 0;
+          yield this._highlightSleep(0);
+      }
+    }
+  }),
+
+  _abortHighlight: null,
+  _highlightSleep: function(delay) {
+    return new Promise((resolve, reject) => {
+      this._abortHighlight = () => {
+        this._abortHighlight = null;
+        reject();
+      };
+      this._getWindow().setTimeout(resolve, delay);
+    });
+  },
+
   /**
    * Helper method for `_countMatchesInWindow` that recursively collects all
    * visible (i)frames inside a window.
    *
    * @param aWindow
    *        the window to extract the (i)frames from.
    * @param aStats
    *        Object that contains a Set called '_framesToCount'
@@ -516,35 +553,35 @@ Finder.prototype = {
     // Removes the outline around the last found link.
     if (this._previousLink) {
       this._previousLink.style.outline = this._tmpOutline;
       this._previousLink.style.outlineOffset = this._tmpOutlineOffset;
       this._previousLink = null;
     }
   },
 
-  _highlight: function (aHighlight, aWord, aWindow) {
+  _highlight: Task.async(function* (aHighlight, aWord, aWindow) {
     let win = aWindow || this._getWindow();
 
     let found = false;
     for (let i = 0; win.frames && i < win.frames.length; i++) {
-      if (this._highlight(aHighlight, aWord, win.frames[i]))
+      if (yield this._highlight(aHighlight, aWord, win.frames[i]))
         found = true;
     }
 
     let controller = this._getSelectionController(win);
     let doc = win.document;
     if (!controller || !doc || !doc.documentElement) {
       // Without the selection controller,
       // we are unable to (un)highlight any matches
       return found;
     }
 
     if (aHighlight) {
-      this._findIterator(aWord, win, aRange => {
+      yield this._highlightIterator(aWord, win, aRange => {
         this._highlightRange(aRange, controller);
         found = true;
       });
     } else {
       // First, attempt to remove highlighting from main document
       let sel = controller.getSelection(Ci.nsISelectionController.SELECTION_FIND);
       sel.removeAllRanges();
 
@@ -562,17 +599,17 @@ Finder.prototype = {
         }
       }
 
       // Removing the highlighting always succeeds, so return true.
       found = true;
     }
 
     return found;
-  },
+  }),
 
   _highlightRange: function(aRange, aController) {
     let node = aRange.startContainer;
     let controller = aController;
 
     let editableNode = this._getEditableNode(node);
     if (editableNode)
       controller = editableNode.editor.selectionController;
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/linux/global/icons/autocomplete-search.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     x="0px" y="0px"
+     viewBox="0 0 16 16"
+     enable-background="new 0 0 16 16"
+     xml:space="preserve">
+<style>
+  use:not(:target) {
+    display: none;
+  }
+
+  use {
+    fill: GrayText;
+  }
+
+  use[id$="-inverted"] {
+    fill: highlighttext;
+  }
+</style>
+<defs style="display:none">
+  <path id="search" fill-rule="evenodd" clip-rule="evenodd" d="M9.356,1.178c-3.014,0-5.458,2.45-5.458,5.472c0,1.086,0.32,2.096,0.864,2.947
+    l-3.279,3.287c-0.396,0.397-0.396,1.041,0,1.438l0.202,0.202c0.396,0.397,1.039,0.397,1.435,0l3.275-3.283
+    c0.854,0.554,1.869,0.88,2.962,0.88c3.014,0,5.458-2.45,5.458-5.471C14.814,3.627,12.371,1.178,9.356,1.178z M9.356,10.001
+    c-1.847,0-3.344-1.501-3.344-3.352c0-1.851,1.497-3.352,3.344-3.352c1.846,0,3.344,1.501,3.344,3.352
+    C12.7,8.501,11.203,10.001,9.356,10.001z"/>
+</defs>
+<use id="search-icon"             xlink:href="#search"/>
+<use id="search-icon-inverted"    xlink:href="#search"/>
+</svg>
--- a/toolkit/themes/linux/global/jar.mn
+++ b/toolkit/themes/linux/global/jar.mn
@@ -34,16 +34,17 @@ toolkit.jar:
 +  skin/classic/global/toolbarbutton.css
 +  skin/classic/global/tree.css
 +  skin/classic/global/alerts/alert.css                        (alerts/alert.css)
 +  skin/classic/global/alerts/notification-48.png              (alerts/notification-48.png)
 +  skin/classic/global/console/console.css                     (console/console.css)
 +  skin/classic/global/console/console.png                     (console/console.png)
 +  skin/classic/global/console/console-toolbar.png             (console/console-toolbar.png)
 +  skin/classic/global/dirListing/remote.png                   (dirListing/remote.png)
++  skin/classic/global/icons/autocomplete-search.svg           (icons/autocomplete-search.svg)
 +  skin/classic/global/icons/Authentication.png                (icons/Authentication.png)
 +  skin/classic/global/icons/autoscroll.png                    (icons/autoscroll.png)
 +  skin/classic/global/icons/blacklist_favicon.png             (icons/blacklist_favicon.png)
 +  skin/classic/global/icons/blacklist_large.png               (icons/blacklist_large.png)
 +  skin/classic/global/icons/close.svg                         (icons/close.svg)
 +  skin/classic/global/icons/find.png                          (icons/find.png)
 +  skin/classic/global/icons/loading_16.png                    (icons/loading_16.png)
 +  skin/classic/global/icons/panelarrow-horizontal.svg         (icons/panelarrow-horizontal.svg)
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/osx/global/icons/autocomplete-search.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     x="0px" y="0px"
+     viewBox="0 0 16 16"
+     enable-background="new 0 0 16 16"
+     xml:space="preserve">
+<style>
+  use:not(:target) {
+    display: none;
+  }
+
+  use {
+    fill: GrayText;
+  }
+
+  use[id$="-inverted"] {
+    fill: highlighttext;
+  }
+</style>
+<defs style="display:none">
+  <path id="search" fill-rule="evenodd" clip-rule="evenodd" d="M14.517,12.884l-3.279-3.287c0.545-0.851,0.864-1.861,0.864-2.947
+    c0-3.022-2.444-5.472-5.458-5.472c-3.014,0-5.458,2.45-5.458,5.472c0,3.022,2.444,5.471,5.458,5.471
+    c1.093,0,2.108-0.325,2.962-0.88l3.275,3.283c0.396,0.397,1.039,0.397,1.435,0l0.202-0.202
+    C14.913,13.925,14.913,13.281,14.517,12.884z M6.644,10.001c-1.846,0-3.344-1.501-3.344-3.352c0-1.851,1.497-3.352,3.344-3.352
+    c1.847,0,3.344,1.501,3.344,3.352C9.987,8.501,8.49,10.001,6.644,10.001z"/>
+</defs>
+<use id="search-icon"             xlink:href="#search"/>
+<use id="search-icon-inverted"    xlink:href="#search"/>
+</svg>
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -87,16 +87,17 @@ toolkit.jar:
   skin/classic/global/console/console-error-dash.gif                 (console/console-error-dash.gif)
 * skin/classic/global/console/console.css                            (console/console.css)
   skin/classic/global/dirListing/dirListing.css                      (dirListing/dirListing.css)
   skin/classic/global/dirListing/folder.png                          (dirListing/folder.png)
   skin/classic/global/dirListing/local.png                           (dirListing/folder.png)
   skin/classic/global/dirListing/remote.png                          (dirListing/remote.png)
   skin/classic/global/dirListing/up.png                              (dirListing/up.png)
   skin/classic/global/icons/autocomplete-dropmarker.png              (icons/autocomplete-dropmarker.png)
+  skin/classic/global/icons/autocomplete-search.svg                  (icons/autocomplete-search.svg)
   skin/classic/global/icons/autoscroll.png                           (icons/autoscroll.png)
   skin/classic/global/icons/blacklist_favicon.png                    (icons/blacklist_favicon.png)
   skin/classic/global/icons/blacklist_64.png                         (icons/blacklist_64.png)
   skin/classic/global/icons/chevron.png                              (icons/chevron.png)
   skin/classic/global/icons/chevron@2x.png                           (icons/chevron@2x.png)
   skin/classic/global/icons/checkbox.png                             (icons/checkbox.png)
   skin/classic/global/icons/checkbox@2x.png                          (icons/checkbox@2x.png)
   skin/classic/global/icons/close.png                                (icons/close.png)
@@ -137,17 +138,17 @@ toolkit.jar:
   skin/classic/global/icons/question-24.png                          (icons/question-24.png)
   skin/classic/global/icons/question-32.png                          (icons/question-32.png)
   skin/classic/global/icons/question-64.png                          (icons/question-64.png)
   skin/classic/global/icons/question-large.png                       (icons/question-large.png)
   skin/classic/global/icons/sslWarning.png                           (icons/sslWarning.png)
   skin/classic/global/icons/webapps-16.png                           (icons/webapps-16.png)
   skin/classic/global/icons/webapps-16@2x.png                        (icons/webapps-16@2x.png)
   skin/classic/global/icons/webapps-64.png                           (icons/webapps-64.png)
-  skin/classic/global/inContentUI/background-texture.png            (inContentUI/background-texture.png)
+  skin/classic/global/inContentUI/background-texture.png             (inContentUI/background-texture.png)
   skin/classic/global/notification/close.png                         (notification/close.png)
   skin/classic/global/notification/critical-bar-background.png       (notification/critical-bar-background.png)
   skin/classic/global/notification/error-icon.png                    (notification/error-icon.png)
   skin/classic/global/notification/info-bar-background.png           (notification/info-bar-background.png)
   skin/classic/global/notification/info-icon.png                     (notification/info-icon.png)
   skin/classic/global/notification/warning-bar-background.png        (notification/warning-bar-background.png)
   skin/classic/global/notification/warning-icon.png                  (notification/warning-icon.png)
   skin/classic/global/media/TopLevelImageDocument.css                (media/TopLevelImageDocument.css)
--- a/toolkit/themes/windows/global/globalBindings.xml
+++ b/toolkit/themes/windows/global/globalBindings.xml
@@ -47,20 +47,9 @@
            extends="chrome://global/content/bindings/toolbar.xml#toolbarpaletteitem">
     <content>
       <xul:spacer class="spacer-left"/>
       <children/>
       <xul:spacer class="spacer-right"/>
     </content>
   </binding>
 
-  <binding id="menulist-compact" display="xul:menu" 
-           extends="chrome://global/content/bindings/menulist.xml#menulist">
-    <content sizetopopup="false">
-      <xul:hbox class="menulist-label-box" flex="1">
-        <xul:image class="menulist-icon" xbl:inherits="src"/>
-        <xul:label class="menulist-label" xbl:inherits="value=label,crop,accesskey" crop="right" flex="1"/>
-      </xul:hbox>
-      <children includes="menupopup"/>
-    </content>
-  </binding>
-
 </bindings>
new file mode 100644
--- /dev/null
+++ b/toolkit/themes/windows/global/icons/autocomplete-search.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg"
+     xmlns:xlink="http://www.w3.org/1999/xlink"
+     x="0px" y="0px"
+     viewBox="0 0 16 16"
+     enable-background="new 0 0 16 16"
+     xml:space="preserve">
+<style>
+  use:not(:target) {
+    display: none;
+  }
+
+  use {
+    fill: GrayText;
+  }
+
+  use[id$="-inverted"] {
+    fill: highlighttext;
+  }
+</style>
+<defs style="display:none">
+  <path id="search" fill-rule="evenodd" clip-rule="evenodd" d="M9.356,1.178c-3.014,0-5.458,2.45-5.458,5.472c0,1.086,0.32,2.096,0.864,2.947
+    l-3.279,3.287c-0.396,0.397-0.396,1.041,0,1.438l0.202,0.202c0.396,0.397,1.039,0.397,1.435,0l3.275-3.283
+    c0.854,0.554,1.869,0.88,2.962,0.88c3.014,0,5.458-2.45,5.458-5.471C14.814,3.627,12.371,1.178,9.356,1.178z M9.356,10.001
+    c-1.847,0-3.344-1.501-3.344-3.352c0-1.851,1.497-3.352,3.344-3.352c1.846,0,3.344,1.501,3.344,3.352
+    C12.7,8.501,11.203,10.001,9.356,10.001z"/>
+</defs>
+<use id="search-icon"             xlink:href="#search"/>
+<use id="search-icon-inverted"    xlink:href="#search"/>
+</svg>
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -94,16 +94,17 @@ toolkit.jar:
         skin/classic/global/console/itemSelected.png             (console/itemSelected.png)
 *       skin/classic/global/dirListing/dirListing.css            (dirListing/dirListing.css)
         skin/classic/global/dirListing/folder.png                (dirListing/folder.png)
         skin/classic/global/dirListing/local.png                 (dirListing/local.png)
         skin/classic/global/dirListing/remote.png                (dirListing/remote.png)
         skin/classic/global/dirListing/up.png                    (dirListing/up.png)
         skin/classic/global/Filepicker.png                       (filepicker/Filepicker.png)
         skin/classic/global/icons/autoscroll.png                 (icons/autoscroll.png)
+        skin/classic/global/icons/autocomplete-search.svg        (icons/autocomplete-search.svg)
         skin/classic/global/icons/blacklist_favicon.png          (icons/blacklist_favicon.png)
         skin/classic/global/icons/blacklist_large.png            (icons/blacklist_large.png)
         skin/classic/global/icons/Close.gif                      (icons/Close.gif)
         skin/classic/global/icons/close.png                      (icons/close.png)
         skin/classic/global/icons/close-lunaBlue.png             (icons/close-lunaBlue.png)
         skin/classic/global/icons/close-lunaOlive.png            (icons/close-lunaOlive.png)
         skin/classic/global/icons/close-lunaSilver.png           (icons/close-lunaSilver.png)
         skin/classic/global/icons/collapse.png                   (icons/collapse.png)
@@ -291,16 +292,17 @@ toolkit.jar:
         skin/classic/aero/global/console/itemSelected.png                (console/itemSelected.png)
 *       skin/classic/aero/global/dirListing/dirListing.css               (dirListing/dirListing.css)
         skin/classic/aero/global/dirListing/folder.png                   (dirListing/folder-aero.png)
         skin/classic/aero/global/dirListing/local.png                    (dirListing/local-aero.png)
         skin/classic/aero/global/dirListing/remote.png                   (dirListing/remote-aero.png)
         skin/classic/aero/global/dirListing/up.png                       (dirListing/up-aero.png)
         skin/classic/aero/global/Filepicker.png                          (filepicker/Filepicker.png)
         skin/classic/aero/global/icons/autoscroll.png                    (icons/autoscroll-aero.png)
+        skin/classic/aero/global/icons/autocomplete-search.svg           (icons/autocomplete-search.svg)
         skin/classic/aero/global/icons/blacklist_favicon.png             (icons/blacklist_favicon-aero.png)
         skin/classic/aero/global/icons/blacklist_large.png               (icons/blacklist_large-aero.png)
         skin/classic/aero/global/icons/Close.gif                         (icons/Close.gif)
         skin/classic/aero/global/icons/close.png                         (icons/close.png)
         skin/classic/aero/global/icons/collapse.png                      (icons/collapse.png)
         skin/classic/aero/global/icons/Error.png                         (icons/Error-aero.png)
         skin/classic/aero/global/icons/error-16.png                      (icons/error-16-aero.png)
         skin/classic/aero/global/icons/error-24.png                      (icons/error-24-aero.png)
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -9,16 +9,17 @@
 #include "nsQAppInstance.h"
 #endif // MOZ_WIDGET_QT
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/ChaosMode.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Poison.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsAppRunner.h"
 #include "mozilla/AppData.h"
@@ -2982,16 +2983,20 @@ int
 XREMain::XRE_mainInit(bool* aExitFlag)
 {
   if (!aExitFlag)
     return 1;
   *aExitFlag = false;
 
   StartupTimeline::Record(StartupTimeline::MAIN);
 
+  if (ChaosMode::isActive()) {
+    printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n");
+  }
+
   nsresult rv;
   ArgResult ar;
 
 #ifdef DEBUG
   if (PR_GetEnv("XRE_MAIN_BREAK"))
     NS_BREAK();
 #endif