Merge m-c to fx-team a=merge CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Thu, 09 Oct 2014 17:11:58 -0700
changeset 209703 27a288fc5313d1963adab2045e95ca2ff4973338
parent 209702 8f632f1754a79635397bde0eecbcaea8b0340e57 (current diff)
parent 209672 95d1486223f7c222b70f6878348ea0be3a66b821 (diff)
child 209704 b91b22431613232f0818721e064002575a04ff9f
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmerge
milestone35.0a1
Merge m-c to fx-team a=merge CLOSED TREE
browser/components/nsBrowserGlue.js
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,19 +10,19 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,18 +14,18 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,18 +12,18 @@
   <!--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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,19 +10,19 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,18 +14,18 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,19 +10,19 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,18 +12,18 @@
   <!--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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "9d8c254abad2ceaad8f1ae22a18e0f36af5860c4", 
+    "revision": "ce7bf759bbf4ecdfa46b64cdccc16ccf7531178d", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,18 +12,18 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,18 +10,18 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="575fdbf046e966a5915b1f1e800e5d6ad0ea14c0"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,18 +12,18 @@
   <!--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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,18 +12,18 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="7b92615bdc97e5c675cd385ec68bc5e47e0c5288"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="a42f56ffac1c52e5bbc82143a949feeed359d528"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="55766f4d12f57b5e7289d068a81a3dc501cf10db"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
   <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="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
   <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="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/browser/base/content/test/general/test_contextmenu.html
+++ b/browser/base/content/test/general/test_contextmenu.html
@@ -637,20 +637,20 @@ function runTest(testNum) {
         selectInputText(select_inputtext_password); // Select text prior to opening context menu.
         openContextMenuFor(select_inputtext_password); // Invoke context menu for next test.
     },
 
     function () {
         // Context menu for selected text in input[type="password"]
         checkContextMenu(["context-undo",        false,
                           "---",                 null,
-                          "context-cut",         true,
-                          "context-copy",        true,
+                          "context-cut",         false,
+                          "context-copy",        false,
                           "context-paste",       null, // ignore clipboard state
-                          "context-delete",      true,
+                          "context-delete",      false,
                           "---",                 null,
                           "context-selectall",   true,
                           "---",                 null,
                           "spell-check-enabled", true,
                           //spell checker is shown on input[type="password"] on this testcase
                           "spell-dictionaries",  true,
                               ["spell-check-dictionary-en-US", true,
                                "---",                          null,
--- a/build/moz-automation.mk
+++ b/build/moz-automation.mk
@@ -97,16 +97,20 @@ AUTOMATION_EXTRA_CMDLINE-check = -k
 # We need the log from make upload to grep it for urls in order to set
 # properties.
 AUTOMATION_EXTRA_CMDLINE-upload = 2>&1 | tee $(AUTOMATION_UPLOAD_OUTPUT)
 
 # Note: We have to force -j1 here, at least until bug 1036563 is fixed.
 AUTOMATION_EXTRA_CMDLINE-l10n-check = -j1
 AUTOMATION_EXTRA_CMDLINE-pretty-l10n-check = -j1
 
+# And force -j1 here until bug 1077670 is fixed.
+AUTOMATION_EXTRA_CMDLINE-package-tests = -j1
+AUTOMATION_EXTRA_CMDLINE-pretty-package-tests = -j1
+
 # The commands only run if the corresponding MOZ_AUTOMATION_* variable is
 # enabled. This means, for example, if we enable MOZ_AUTOMATION_UPLOAD, then
 # 'buildsymbols' will only run if MOZ_AUTOMATION_BUILD_SYMBOLS is also set.
 # However, the target automation/buildsymbols will still be executed in this
 # case because it is a prerequisite of automation/upload.
 define automation_commands
 $(call BUILDSTATUS,TIER_START $1)
 @$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1)
--- a/configure.in
+++ b/configure.in
@@ -1525,25 +1525,25 @@ if test "$GNU_CXX"; then
     # -Wtrigraphs - catches unlikely use of trigraphs
     # -Wtype-limits - catches overflow bugs, few false positives
     # -Wunused-label - catches unused goto labels
     # -Wwrite-strings - catches non-const char* pointers to string literals
     #
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wempty-body"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Woverloaded-virtual"
-    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wpointer-arith"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wsign-compare"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wwrite-strings"
 
     # Treat some warnings as errors:
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=endif-labels"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=int-to-pointer-cast"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=missing-braces"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=parentheses"
+    _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=pointer-arith"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs"
     _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=type-limits"
 
     # Turn off the following warnings that -Wall turns on:
     # -Wno-invalid-offsetof - we use offsetof on non-POD types frequently
--- a/content/base/public/File.h
+++ b/content/base/public/File.h
@@ -136,19 +136,16 @@ public:
   const nsTArray<nsRefPtr<FileImpl>>* GetSubBlobImpls() const;
 
   bool IsSizeUnknown() const;
 
   bool IsDateUnknown() const;
 
   bool IsFile() const;
 
-  void SetLazyData(const nsAString& aName, const nsAString& aContentType,
-                   uint64_t aLength, uint64_t aLastModifiedDate);
-
   already_AddRefed<File>
   CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
               ErrorResult& aRv);
 
   // WebIDL methods
   nsISupports* GetParentObject() const
   {
     return mParent;
--- a/content/base/src/File.cpp
+++ b/content/base/src/File.cpp
@@ -311,23 +311,16 @@ File::IsDateUnknown() const
 }
 
 bool
 File::IsFile() const
 {
   return mImpl->IsFile();
 }
 
-void
-File::SetLazyData(const nsAString& aName, const nsAString& aContentType,
-                     uint64_t aLength, uint64_t aLastModifiedDate)
-{
-  return mImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate);
-}
-
 already_AddRefed<File>
 File::CreateSlice(uint64_t aStart, uint64_t aLength,
                   const nsAString& aContentType,
                   ErrorResult& aRv)
 {
   nsRefPtr<FileImpl> impl = mImpl->CreateSlice(aStart, aLength,
                                                aContentType, aRv);
   if (aRv.Failed()) {
@@ -348,17 +341,17 @@ File::GetName(nsAString& aFileName)
 NS_IMETHODIMP
 File::GetPath(nsAString& aPath)
 {
   return mImpl->GetPath(aPath);
 }
 
 NS_IMETHODIMP
 File::GetLastModifiedDate(JSContext* aCx,
-                             JS::MutableHandle<JS::Value> aDate)
+                          JS::MutableHandle<JS::Value> aDate)
 {
   ErrorResult rv;
   Date value = GetLastModifiedDate(rv);
   if (rv.Failed()) {
     return rv.ErrorCode();
   }
 
   if (!value.ToDateObject(aCx, aDate)) {
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5978,17 +5978,18 @@ nsContentUtils::CreateArrayBuffer(JSCont
   int32_t dataLen = aData.Length();
   *aResult = JS_NewArrayBuffer(aCx, dataLen);
   if (!*aResult) {
     return NS_ERROR_FAILURE;
   }
 
   if (dataLen > 0) {
     NS_ASSERTION(JS_IsArrayBufferObject(*aResult), "What happened?");
-    memcpy(JS_GetArrayBufferData(*aResult), aData.BeginReading(), dataLen);
+    JS::AutoCheckCannotGC nogc;
+    memcpy(JS_GetArrayBufferData(*aResult, nogc), aData.BeginReading(), dataLen);
   }
 
   return NS_OK;
 }
 
 // Initial implementation: only stores to RAM, not file
 // TODO: bug 704447: large file support
 nsresult
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -289,18 +289,32 @@ nsDOMFileReader::DoOnLoadEnd(nsresult aS
   // Clear out the data if necessary
   if (NS_FAILED(aStatus)) {
     FreeFileData();
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
   switch (mDataFormat) {
-    case FILE_AS_ARRAYBUFFER:
-      break; //Already accumulated mResultArrayBuffer
+    case FILE_AS_ARRAYBUFFER: {
+      AutoJSAPI jsapi;
+      if (NS_WARN_IF(!jsapi.Init(mozilla::DOMEventTargetHelper::GetParentObject()))) {
+        return NS_ERROR_FAILURE;
+      }
+
+      RootResultArrayBuffer();
+      mResultArrayBuffer = JS_NewArrayBufferWithContents(jsapi.cx(), mTotal, mFileData);
+      if (!mResultArrayBuffer) {
+        JS_ClearPendingException(jsapi.cx());
+        rv = NS_ERROR_OUT_OF_MEMORY;
+      } else {
+        mFileData = nullptr; // Transfer ownership
+      }
+      break;
+    }
     case FILE_AS_BINARY:
       break; //Already accumulated mResult
     case FILE_AS_TEXT:
       if (!mFileData) {
         if (mDataLen) {
           rv = NS_ERROR_OUT_OF_MEMORY;
           break;
         }
@@ -337,45 +351,40 @@ nsDOMFileReader::DoReadData(nsIAsyncInpu
     mResult.GetMutableData(&buf, oldLen + aCount, fallible_t());
     NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
 
     uint32_t bytesRead = 0;
     aStream->ReadSegments(ReadFuncBinaryString, buf + oldLen, aCount,
                           &bytesRead);
     NS_ASSERTION(bytesRead == aCount, "failed to read data");
   }
-  else if (mDataFormat == FILE_AS_ARRAYBUFFER) {
-    uint32_t bytesRead = 0;
-    aStream->Read((char*) JS_GetArrayBufferData(mResultArrayBuffer) + mDataLen,
-                  aCount, &bytesRead);
-    NS_ASSERTION(bytesRead == aCount, "failed to read data");
-  }
   else {
     //Update memory buffer to reflect the contents of the file
     if (mDataLen + aCount > UINT32_MAX) {
       // PR_Realloc doesn't support over 4GB memory size even if 64-bit OS
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    mFileData = (char *) moz_realloc(mFileData, mDataLen + aCount);
-    NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
+    if (mDataFormat != FILE_AS_ARRAYBUFFER) {
+      mFileData = (char *) moz_realloc(mFileData, mDataLen + aCount);
+      NS_ENSURE_TRUE(mFileData, NS_ERROR_OUT_OF_MEMORY);
+    }
 
     uint32_t bytesRead = 0;
     aStream->Read(mFileData + mDataLen, aCount, &bytesRead);
     NS_ASSERTION(bytesRead == aCount, "failed to read data");
   }
 
   mDataLen += aCount;
   return NS_OK;
 }
 
 // Helper methods
 
 void
-nsDOMFileReader::ReadFileContent(JSContext* aCx,
-                                 File& aFile,
+nsDOMFileReader::ReadFileContent(File& aFile,
                                  const nsAString &aCharset,
                                  eDataFormat aDataFormat,
                                  ErrorResult& aRv)
 {
   //Implicit abort to clear any other activity going on
   Abort();
   mError = nullptr;
   SetDOMStringToNull(mResult);
@@ -438,21 +447,20 @@ nsDOMFileReader::ReadFileContent(JSConte
     return;
   }
 
   //FileReader should be in loading state here
   mReadyState = nsIDOMFileReader::LOADING;
   DispatchProgressEvent(NS_LITERAL_STRING(LOADSTART_STR));
 
   if (mDataFormat == FILE_AS_ARRAYBUFFER) {
-    RootResultArrayBuffer();
-    mResultArrayBuffer = JS_NewArrayBuffer(aCx, mTotal);
-    if (!mResultArrayBuffer) {
-      NS_WARNING("Failed to create JS array buffer");
-      aRv.Throw(NS_ERROR_FAILURE);
+    mFileData = js_pod_malloc<char>(mTotal);
+    if (!mFileData) {
+      NS_WARNING("Preallocation failed for ReadFileData");
+      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     }
   }
 }
 
 nsresult
 nsDOMFileReader::GetAsText(nsIDOMBlob *aFile,
                            const nsACString &aCharset,
                            const char *aFileData,
--- a/content/base/src/nsDOMFileReader.h
+++ b/content/base/src/nsDOMFileReader.h
@@ -65,27 +65,27 @@ public:
   }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // WebIDL
   static already_AddRefed<nsDOMFileReader>
   Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
   void ReadAsArrayBuffer(JSContext* aCx, File& aBlob, ErrorResult& aRv)
   {
-    ReadFileContent(aCx, aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
+    ReadFileContent(aBlob, EmptyString(), FILE_AS_ARRAYBUFFER, aRv);
   }
 
   void ReadAsText(File& aBlob, const nsAString& aLabel, ErrorResult& aRv)
   {
-    ReadFileContent(nullptr, aBlob, aLabel, FILE_AS_TEXT, aRv);
+    ReadFileContent(aBlob, aLabel, FILE_AS_TEXT, aRv);
   }
 
   void ReadAsDataURL(File& aBlob, ErrorResult& aRv)
   {
-    ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
+    ReadFileContent(aBlob, EmptyString(), FILE_AS_DATAURL, aRv);
   }
 
   using FileIOObject::Abort;
 
   // Inherited ReadyState().
 
   void GetResult(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
                  ErrorResult& aRv);
@@ -99,17 +99,17 @@ public:
   using FileIOObject::GetOnabort;
   using FileIOObject::SetOnabort;
   using FileIOObject::GetOnerror;
   using FileIOObject::SetOnerror;
   IMPL_EVENT_HANDLER(loadend)
 
   void ReadAsBinaryString(File& aBlob, ErrorResult& aRv)
   {
-    ReadFileContent(nullptr, aBlob, EmptyString(), FILE_AS_BINARY, aRv);
+    ReadFileContent(aBlob, EmptyString(), FILE_AS_BINARY, aRv);
   }
 
 
   nsresult Init();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMFileReader,
                                                          FileIOObject)
   void RootResultArrayBuffer();
@@ -119,17 +119,17 @@ protected:
 
   enum eDataFormat {
     FILE_AS_ARRAYBUFFER,
     FILE_AS_BINARY,
     FILE_AS_TEXT,
     FILE_AS_DATAURL
   };
 
-  void ReadFileContent(JSContext* aCx, File& aBlob,
+  void ReadFileContent(File& aBlob,
                        const nsAString &aCharset, eDataFormat aDataFormat,
                        ErrorResult& aRv);
   nsresult GetAsText(nsIDOMBlob *aFile, const nsACString &aCharset,
                      const char *aFileData, uint32_t aDataLen, nsAString &aResult);
   nsresult GetAsDataURL(nsIDOMBlob *aFile, const char *aFileData, uint32_t aDataLen, nsAString &aResult);
 
   void FreeFileData() {
     moz_free(mFileData);
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -5843,16 +5843,21 @@ nsDocument::ProcessBaseElementQueue()
 }
 
 // static
 void
 nsDocument::ProcessTopElementQueue(bool aIsBaseQueue)
 {
   MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
 
+  if (sProcessingStack.isNothing()) {
+    // If XPCOM shutdown has reset the processing stack, don't do anything.
+    return;
+  }
+
   nsTArray<CustomElementData*>& stack = *sProcessingStack;
   uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
 
   if (aIsBaseQueue && firstQueue != 0) {
     return;
   }
 
   for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -842,20 +842,21 @@ nsFrameLoader::MarginsChanged(uint32_t a
   if (!mDocShell)
     return;
 
   // Set the margins
   mDocShell->SetMarginWidth(aMarginWidth);
   mDocShell->SetMarginHeight(aMarginHeight);
 
   // Trigger a restyle if there's a prescontext
+  // FIXME: This could do something much less expensive.
   nsRefPtr<nsPresContext> presContext;
   mDocShell->GetPresContext(getter_AddRefs(presContext));
   if (presContext)
-    presContext->RebuildAllStyleData(nsChangeHint(0));
+    presContext->RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
 }
 
 bool
 nsFrameLoader::ShowRemoteFrame(const nsIntSize& size,
                                nsSubDocumentFrame *aFrame)
 {
   NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
 
--- a/content/html/content/test/test_audio_wakelock.html
+++ b/content/html/content/test/test_audio_wakelock.html
@@ -26,38 +26,41 @@ function testAudioPlayPause() {
 
   var content = document.getElementById('content');
 
   var audio = document.createElement('audio');
   audio.src = "wakelock.ogg";
   content.appendChild(audio);
 
   var startDate;
-  audio.addEventListener('playing', function() {
-    startDate = new Date();
-
-    // The next step is to unlock the resource.
-    lockState = false;
-    audio.pause();
-  });
-
   function testAudioPlayListener(topic, state) {
-    is(topic, "cpu", "Audio element locked the target == cpu");
+    is(topic, "cpu", "#1 Audio element locked the target == cpu");
     var locked = state == "locked-foreground" ||
                  state == "locked-background";
 
-    is(locked, lockState, "Audio element locked the cpu - no paused");
+    var s = locked ? "locked" : "unlocked";
+    is(locked, lockState, "#1 Audio element " + s + " the cpu");
     count++;
 
     // count == 1 is when the cpu wakelock is created
     // count == 2 is when the cpu wakelock is released
 
+    if (count == 1) {
+      // The next step is to unlock the resource.
+      lockState = false;
+      audio.pause();
+      startDate = new Date();
+      return;
+    }
+
+    is(count, 2, "The count should be 2 which indicates wakelock release");
+
     if (count == 2) {
       var diffDate = (new Date() - startDate);
-      ok(diffDate > 200, "There was at least 200 milliseconds between the stop and the wakelock release");
+      ok(diffDate > 200, "#1 There was at least 200 milliseconds between the stop and the wakelock release");
 
       content.removeChild(audio);
       navigator.mozPower.removeWakeLockListener(testAudioPlayListener);
       runTests();
     }
   };
 
   navigator.mozPower.addWakeLockListener(testAudioPlayListener);
@@ -69,40 +72,33 @@ function testAudioPlay() {
   var count = 0;
 
   var content = document.getElementById('content');
 
   var audio = document.createElement('audio');
   audio.src = "wakelock.ogg";
   content.appendChild(audio);
 
-  var startDate;
-  audio.addEventListener('progress', function() {
-    startDate = new Date();
-  });
-
   function testAudioPlayListener(topic, state) {
-    is(topic, "cpu", "Audio element locked the target == cpu");
+    is(topic, "cpu", "#2 Audio element locked the target == cpu");
     var locked = state == "locked-foreground" ||
                  state == "locked-background";
 
-    is(locked, lockState, "Audio element locked the cpu - no paused");
+    var s = locked ? "locked" : "unlocked";
+    is(locked, lockState, "#2 Audio element " + s + " the cpu");
     count++;
 
     // count == 1 is when the cpu wakelock is created: the wakelock must be
     // created when the media element starts playing.
     // count == 2 is when the cpu wakelock is released.
 
     if (count == 1) {
       // The next step is to unlock the resource.
       lockState = false;
     } else if (count == 2) {
-      var diffDate = (new Date() - startDate);
-      ok(diffDate > 200, "There was at least 200 milliseconds between the stop and the wakelock release");
-
       content.removeChild(audio);
       navigator.mozPower.removeWakeLockListener(testAudioPlayListener);
       runTests();
     }
   };
 
   navigator.mozPower.addWakeLockListener(testAudioPlayListener);
   audio.play();
--- a/content/media/RtspMediaResource.cpp
+++ b/content/media/RtspMediaResource.cpp
@@ -48,29 +48,38 @@ namespace mozilla {
 #define BUFFER_SLOT_EMPTY 0
 
 struct BufferSlotData {
   int32_t mLength;
   uint64_t mTime;
   int32_t  mFrameType;
 };
 
+// This constant is used to determine if the buffer usage is over a threshold.
+const float kBufferThresholdPerc = 0.8f;
+// The default value of playout delay duration.
+const uint32_t kPlayoutDelayMs = 3000;
+
+//-----------------------------------------------------------------------------
+// RtspTrackBuffer
+//-----------------------------------------------------------------------------
 class RtspTrackBuffer
 {
 public:
   RtspTrackBuffer(const char *aMonitor, int32_t aTrackIdx, uint32_t aSlotSize)
   : mMonitor(aMonitor)
   , mSlotSize(aSlotSize)
   , mTotalBufferSize(BUFFER_SLOT_NUM * mSlotSize)
   , mFrameType(0)
-  , mIsStarted(false) {
+  , mIsStarted(false)
+  , mDuringPlayoutDelay(false)
+  , mPlayoutDelayMs(kPlayoutDelayMs)
+  , mPlayoutDelayTimer(nullptr) {
     MOZ_COUNT_CTOR(RtspTrackBuffer);
-#ifdef PR_LOGGING
     mTrackIdx = aTrackIdx;
-#endif
     MOZ_ASSERT(mSlotSize < UINT32_MAX / BUFFER_SLOT_NUM);
     mRingBuffer = new uint8_t[mTotalBufferSize];
     Reset();
   };
   ~RtspTrackBuffer() {
     MOZ_COUNT_DTOR(RtspTrackBuffer);
     mRingBuffer = nullptr;
   };
@@ -88,16 +97,17 @@ public:
   void Start() {
     MonitorAutoLock monitor(mMonitor);
     mIsStarted = true;
     mFrameType = 0;
   }
   void Stop() {
     MonitorAutoLock monitor(mMonitor);
     mIsStarted = false;
+    StopPlayoutDelay();
   }
 
   // Read the data from mRingBuffer[mConsumerIdx*mSlotSize] into aToBuffer.
   // If the aToBufferSize is smaller than mBufferSlotDataLength[mConsumerIdx],
   // early return and set the aFrameSize to notify the reader the aToBuffer
   // doesn't have enough space. The reader must realloc the aToBuffer if it
   // wishes to read the data.
   nsresult ReadBuffer(uint8_t* aToBuffer, uint32_t aToBufferSize,
@@ -113,29 +123,55 @@ public:
   // We should call SetFrameType first then reset().
   // If we call reset() first, the queue may still has some "garbage" frame
   // from another thread's |OnMediaDataAvailable| before |SetFrameType|.
   void ResetWithFrameType(uint32_t aFrameType) {
     SetFrameType(aFrameType);
     Reset();
   }
 
+  // When RtspTrackBuffer is in playout delay duration, it should suspend
+  // reading data from the buffer until the playout-delay-ended event occurs,
+  // which wil be trigger by mPlayoutDelayTimer.
+  void StartPlayoutDelay() {
+    mDuringPlayoutDelay = true;
+  }
+  void LockStartPlayoutDelay() {
+    MonitorAutoLock monitor(mMonitor);
+    StartPlayoutDelay();
+  }
+
+  // If the playout delay is stopped, mPlayoutDelayTimer should be canceled.
+  void StopPlayoutDelay() {
+    if (mPlayoutDelayTimer) {
+      mPlayoutDelayTimer->Cancel();
+      mPlayoutDelayTimer = nullptr;
+    }
+    mDuringPlayoutDelay = false;
+  }
+  void LockStopPlayoutDelay() {
+    MonitorAutoLock monitor(mMonitor);
+    StopPlayoutDelay();
+  }
+
+  bool IsBufferOverThreshold();
+  void CreatePlayoutDelayTimer(unsigned long delayMs);
+  static void PlayoutDelayTimerCallback(nsITimer *aTimer, void *aClosure);
+
 private:
   // The FrameType is sync to nsIStreamingProtocolController.h
   void SetFrameType(uint32_t aFrameType) {
     MonitorAutoLock monitor(mMonitor);
     mFrameType = mFrameType | aFrameType;
   }
 
   // A monitor lock to prevent racing condition.
   Monitor mMonitor;
-#ifdef PR_LOGGING
   // Indicate the track number for Rtsp.
   int32_t mTrackIdx;
-#endif
   // mProducerIdx: A slot index that we store data from
   // nsIStreamingProtocolController.
   // mConsumerIdx: A slot index that we read when decoder need(from OMX decoder).
   int32_t mProducerIdx;
   int32_t mConsumerIdx;
 
   // Because each slot's size is fixed, we need an array to record the real
   // data length and data time stamp.
@@ -154,16 +190,23 @@ private:
   uint32_t mTotalBufferSize;
   // A flag that that indicate the incoming data should be dropped or stored.
   // When we are seeking, the incoming data should be dropped.
   // Bit definition in |nsIStreamingProtocolController.h|
   uint32_t mFrameType;
 
   // Set true/false when |Start()/Stop()| is called.
   bool mIsStarted;
+
+  // Indicate the buffer is in playout delay duration or not.
+  bool mDuringPlayoutDelay;
+  // Playout delay duration defined in milliseconds.
+  uint32_t mPlayoutDelayMs;
+  // Timer used to fire playout-delay-ended event.
+  nsCOMPtr<nsITimer> mPlayoutDelayTimer;
 };
 
 nsresult RtspTrackBuffer::ReadBuffer(uint8_t* aToBuffer, uint32_t aToBufferSize,
                                      uint32_t& aReadCount, uint64_t& aFrameTime,
                                      uint32_t& aFrameSize)
 {
   MonitorAutoLock monitor(mMonitor);
   RTSPMLOG("ReadBuffer mTrackIdx %d mProducerIdx %d mConsumerIdx %d "
@@ -172,19 +215,26 @@ nsresult RtspTrackBuffer::ReadBuffer(uin
            ,mBufferSlotData[mConsumerIdx].mLength);
   // Reader should skip the slots with mLength==BUFFER_SLOT_INVALID.
   // The loop ends when
   // 1. Read data successfully
   // 2. Fail to read data due to aToBuffer's space
   // 3. No data in this buffer
   // 4. mIsStarted is not set
   while (1) {
+    // Do not read from buffer if we are still in the playout delay duration.
+    if (mDuringPlayoutDelay) {
+      monitor.Wait();
+      continue;
+    }
+
     if (mBufferSlotData[mConsumerIdx].mFrameType & MEDIASTREAM_FRAMETYPE_END_OF_STREAM) {
       return NS_BASE_STREAM_CLOSED;
     }
+
     if (mBufferSlotData[mConsumerIdx].mLength > 0) {
       // Check the aToBuffer space is enough for data copy.
       if ((int32_t)aToBufferSize < mBufferSlotData[mConsumerIdx].mLength) {
         aFrameSize = mBufferSlotData[mConsumerIdx].mLength;
         break;
       }
       uint32_t slots = (mBufferSlotData[mConsumerIdx].mLength / mSlotSize) + 1;
       // we have data, copy to aToBuffer
@@ -266,16 +316,22 @@ void RtspTrackBuffer::WriteBuffer(const 
   // Checking current buffer frame type.
   // If the MEDIASTREAM_FRAMETYPE_DISCONTINUNITY bit is set, imply the
   // RtspTrackBuffer can't receive data now. So we drop the frame until we
   // receive MEDIASTREAM_FRAMETYPE_DISCONTINUNITY.
   if (mFrameType & MEDIASTREAM_FRAMETYPE_DISCONTINUITY) {
     RTSPMLOG("Return because the mFrameType is set");
     return;
   }
+
+  // Create a timer to delay ReadBuffer() for a duration.
+  if (mDuringPlayoutDelay && !mPlayoutDelayTimer) {
+    CreatePlayoutDelayTimer(mPlayoutDelayMs);
+  }
+
   // The flag is true if the incoming data is larger than one slot size.
   bool isMultipleSlots = false;
   // The flag is true if the incoming data is larger than remainder free slots
   bool returnToHead = false;
   // Calculate how many slots the incoming data needed.
   int32_t slots = 1;
   int32_t i;
   RTSPMLOG("WriteBuffer mTrackIdx %d mProducerIdx %d mConsumerIdx %d",
@@ -309,24 +365,31 @@ void RtspTrackBuffer::WriteBuffer(const 
     }
     mProducerIdx = 0;
   }
 
   if (!(aFrameType & MEDIASTREAM_FRAMETYPE_END_OF_STREAM)) {
     memcpy(&(mRingBuffer[mSlotSize * mProducerIdx]), aFromBuffer, aWriteCount);
   }
 
+  // If the buffer is almost full, stop the playout delay to let ReadBuffer()
+  // consume data in the buffer.
+  if (mDuringPlayoutDelay && IsBufferOverThreshold()) {
+    StopPlayoutDelay();
+  }
+
   if (mProducerIdx <= mConsumerIdx && mConsumerIdx < mProducerIdx + slots
       && mBufferSlotData[mConsumerIdx].mLength > 0) {
     // Wrote one or more slots that the decode thread has not yet read.
     RTSPMLOG("overwrite!! %d time %lld"
              ,mTrackIdx,mBufferSlotData[mConsumerIdx].mTime);
     if (aFrameType & MEDIASTREAM_FRAMETYPE_END_OF_STREAM) {
       mBufferSlotData[mProducerIdx].mLength = 0;
       mBufferSlotData[mProducerIdx].mTime = 0;
+      StopPlayoutDelay();
     } else {
       mBufferSlotData[mProducerIdx].mLength = aWriteCount;
       mBufferSlotData[mProducerIdx].mTime = aFrameTime;
     }
     mBufferSlotData[mProducerIdx].mFrameType = aFrameType;
     // Clear the mBufferSlotDataLength except the start slot.
     if (isMultipleSlots) {
       for (i = mProducerIdx + 1; i < mProducerIdx + slots; ++i) {
@@ -337,16 +400,17 @@ void RtspTrackBuffer::WriteBuffer(const 
     // Move the mConsumerIdx forward to ensure that the decoder reads the
     // oldest data available.
     mConsumerIdx = mProducerIdx;
   } else {
     // Normal case, the writer doesn't take over the reader.
     if (aFrameType & MEDIASTREAM_FRAMETYPE_END_OF_STREAM) {
       mBufferSlotData[mProducerIdx].mLength = 0;
       mBufferSlotData[mProducerIdx].mTime = 0;
+      StopPlayoutDelay();
     } else {
       mBufferSlotData[mProducerIdx].mLength = aWriteCount;
       mBufferSlotData[mProducerIdx].mTime = aFrameTime;
     }
     mBufferSlotData[mProducerIdx].mFrameType = aFrameType;
     // Clear the mBufferSlotData[].mLength except the start slot.
     if (isMultipleSlots) {
       for (i = mProducerIdx + 1; i < mProducerIdx + slots; ++i) {
@@ -363,19 +427,68 @@ void RtspTrackBuffer::Reset() {
   MonitorAutoLock monitor(mMonitor);
   mProducerIdx = 0;
   mConsumerIdx = 0;
   for (uint32_t i = 0; i < BUFFER_SLOT_NUM; ++i) {
     mBufferSlotData[i].mLength = BUFFER_SLOT_EMPTY;
     mBufferSlotData[i].mTime = BUFFER_SLOT_EMPTY;
     mBufferSlotData[i].mFrameType = MEDIASTREAM_FRAMETYPE_NORMAL;
   }
+  StopPlayoutDelay();
   mMonitor.NotifyAll();
 }
 
+bool
+RtspTrackBuffer::IsBufferOverThreshold()
+{
+  static int32_t numSlotsThreshold =
+    BUFFER_SLOT_NUM * kBufferThresholdPerc;
+
+  int32_t numSlotsUsed = mProducerIdx - mConsumerIdx;
+  if (numSlotsUsed < 0) {  // wrap-around
+    numSlotsUsed = (BUFFER_SLOT_NUM - mConsumerIdx) + mProducerIdx;
+  }
+  if (numSlotsUsed > numSlotsThreshold) {
+    return true;
+  }
+
+  return false;
+}
+
+void
+RtspTrackBuffer::CreatePlayoutDelayTimer(unsigned long delayMs)
+{
+  if (delayMs <= 0) {
+    return;
+  }
+  mPlayoutDelayTimer = do_CreateInstance("@mozilla.org/timer;1");
+  if (mPlayoutDelayTimer) {
+    mPlayoutDelayTimer->InitWithFuncCallback(PlayoutDelayTimerCallback,
+                                             this, delayMs,
+                                             nsITimer::TYPE_ONE_SHOT);
+  }
+}
+
+// static
+void
+RtspTrackBuffer::PlayoutDelayTimerCallback(nsITimer *aTimer,
+                                           void *aClosure)
+{
+  MOZ_ASSERT(aTimer);
+  MOZ_ASSERT(aClosure);
+
+  RtspTrackBuffer *self = static_cast<RtspTrackBuffer*>(aClosure);
+  MonitorAutoLock lock(self->mMonitor);
+  self->StopPlayoutDelay();
+  lock.NotifyAll();
+}
+
+//-----------------------------------------------------------------------------
+// RtspMediaResource
+//-----------------------------------------------------------------------------
 RtspMediaResource::RtspMediaResource(MediaDecoder* aDecoder,
     nsIChannel* aChannel, nsIURI* aURI, const nsACString& aContentType)
   : BaseMediaResource(aDecoder, aChannel, aURI, aContentType)
   , mIsConnected(false)
   , mRealTime(false)
   , mIsSuspend(true)
 {
 #ifndef NECKO_PROTOCOL_rtsp
@@ -753,10 +866,26 @@ nsresult RtspMediaResource::SeekTime(int
   // Clear buffer and raise the frametype flag.
   for(uint32_t i = 0 ; i < mTrackBuffer.Length(); ++i) {
     mTrackBuffer[i]->ResetWithFrameType(MEDIASTREAM_FRAMETYPE_DISCONTINUITY);
   }
 
   return mMediaStreamController->Seek(aOffset);
 }
 
+void
+RtspMediaResource::EnablePlayoutDelay()
+{
+  for (uint32_t i = 0; i < mTrackBuffer.Length(); ++i) {
+    mTrackBuffer[i]->LockStartPlayoutDelay();
+  }
+}
+
+void
+RtspMediaResource::DisablePlayoutDelay()
+{
+  for (uint32_t i = 0; i < mTrackBuffer.Length(); ++i) {
+    mTrackBuffer[i]->LockStopPlayoutDelay();
+  }
+}
+
 } // namespace mozilla
 
--- a/content/media/RtspMediaResource.h
+++ b/content/media/RtspMediaResource.h
@@ -2,16 +2,18 @@
 /* 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/. */
 
 #if !defined(RtspMediaResource_h_)
 #define RtspMediaResource_h_
 
 #include "MediaResource.h"
+#include "mozilla/Monitor.h"
+#include "nsITimer.h"
 
 namespace mozilla {
 
 class RtspTrackBuffer;
 
 /* RtspMediaResource
  * RtspMediaResource provides an interface to deliver and control RTSP media
  * data to RtspDecoder.
@@ -107,16 +109,22 @@ public:
   //   aFrameSize: actual data size in track.
   nsresult ReadFrameFromTrack(uint8_t* aBuffer, uint32_t aBufferSize,
                               uint32_t aTrackIdx, uint32_t& aBytes,
                               uint64_t& aTime, uint32_t& aFrameSize);
 
   // Seek to the given time offset
   nsresult SeekTime(int64_t aOffset);
 
+  // The idea of playout delay is to hold frames in the playout buffer
+  // (RtspTrackBuffer) for a period of time in order to smooth timing variations
+  // caused by the network.
+  void EnablePlayoutDelay();
+  void DisablePlayoutDelay();
+
   // dummy
   virtual nsresult ReadAt(int64_t aOffset, char* aBuffer,
                           uint32_t aCount, uint32_t* aBytes)  MOZ_OVERRIDE{
     return NS_ERROR_FAILURE;
   }
   // dummy
   virtual void     SetReadMode(MediaCacheStream::ReadMode aMode) MOZ_OVERRIDE {}
   // dummy
--- a/content/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/content/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -89,43 +89,38 @@ GonkAudioDecoderManager::Init(MediaDataD
   } else {
     ALOG("Failed to input codec specific data!");
     return nullptr;
   }
 }
 
 nsresult
 GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
-
-  void *data;
-  size_t dataOffset;
-  size_t size;
-  int64_t timeUs;
-
   if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
     ALOG("Audio Buffer is not valid!");
     return NS_ERROR_UNEXPECTED;
   }
 
+  int64_t timeUs;
   if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   if (mAudioBuffer->range_length() == 0) {
     // Some decoders may return spurious empty buffers that we just want to ignore
     // quoted from Android's AwesomePlayer.cpp
     ReleaseAudioBuffer();
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  data = mAudioBuffer->data();
-  dataOffset = mAudioBuffer->range_offset();
-  size = mAudioBuffer->range_length();
+  const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data());
+  size_t dataOffset = mAudioBuffer->range_offset();
+  size_t size = mAudioBuffer->range_length();
 
-  nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[size/2] );
+  nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[size/2]);
   memcpy(buffer.get(), data+dataOffset, size);
   uint32_t frames = size / (2 * mAudioChannels);
 
   CheckedInt64 duration = FramesToUsecs(frames, mAudioRate);
   if (!duration.isValid()) {
     return NS_ERROR_UNEXPECTED;
   }
   *v = new AudioData(aStreamOffset,
@@ -148,17 +143,17 @@ GonkAudioDecoderManager::Output(int64_t 
   err = mDecoder->Output(&mAudioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
 
   switch (err) {
     case OK:
     {
       AudioData* data = nullptr;
       nsresult rv = CreateAudioData(aStreamOffset, &data);
       if (rv == NS_ERROR_NOT_AVAILABLE) {
-	// Decoder outputs a empty video buffer, try again
+        // Decoder outputs an empty video buffer, try again
         return NS_ERROR_NOT_AVAILABLE;
       } else if (rv != NS_OK || data == nullptr) {
         return NS_ERROR_UNEXPECTED;
       }
       aOutData = data;
       return NS_OK;
     }
     case android::INFO_FORMAT_CHANGED:
--- a/content/media/gmp/GMPChild.cpp
+++ b/content/media/gmp/GMPChild.cpp
@@ -11,16 +11,20 @@
 #include "GMPVideoHost.h"
 #include "nsDebugImpl.h"
 #include "nsIFile.h"
 #include "nsXULAppAPI.h"
 #include "gmp-video-decode.h"
 #include "gmp-video-encode.h"
 #include "GMPPlatform.h"
 #include "mozilla/dom/CrashReporterChild.h"
+#ifdef XP_WIN
+#include <fstream>
+#include "nsCRT.h"
+#endif
 
 using mozilla::dom::CrashReporterChild;
 
 #ifdef XP_WIN
 #include <stdlib.h> // for _exit()
 #else
 #include <unistd.h> // for _exit()
 #endif
@@ -46,63 +50,95 @@ GMPChild::GMPChild()
   nsDebugImpl::SetMultiprocessMode("GMP");
 }
 
 GMPChild::~GMPChild()
 {
 }
 
 static bool
-GetPluginFile(const std::string& aPluginPath,
+GetFileBase(const std::string& aPluginPath,
 #if defined(XP_MACOSX)
-              nsCOMPtr<nsIFile>& aLibDirectory,
+            nsCOMPtr<nsIFile>& aLibDirectory,
 #endif
-              nsCOMPtr<nsIFile>& aLibFile)
+            nsCOMPtr<nsIFile>& aFileBase,
+            nsAutoString& aBaseName)
 {
   nsDependentCString pluginPath(aPluginPath.c_str());
 
   nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(pluginPath),
-                                true, getter_AddRefs(aLibFile));
+                                true, getter_AddRefs(aFileBase));
   if (NS_FAILED(rv)) {
     return false;
   }
 
 #if defined(XP_MACOSX)
-  if (NS_FAILED(aLibFile->Clone(getter_AddRefs(aLibDirectory)))) {
+  if (NS_FAILED(aFileBase->Clone(getter_AddRefs(aLibDirectory)))) {
     return false;
   }
 #endif
 
   nsCOMPtr<nsIFile> parent;
-  rv = aLibFile->GetParent(getter_AddRefs(parent));
+  rv = aFileBase->GetParent(getter_AddRefs(parent));
   if (NS_FAILED(rv)) {
     return false;
   }
 
   nsAutoString parentLeafName;
   rv = parent->GetLeafName(parentLeafName);
   if (NS_FAILED(rv)) {
     return false;
   }
 
-  nsAutoString baseName(Substring(parentLeafName, 4, parentLeafName.Length() - 1));
+  aBaseName = Substring(parentLeafName,
+                        4,
+                        parentLeafName.Length() - 1);
+  return true;
+}
+
+static bool
+GetPluginFile(const std::string& aPluginPath,
+#if defined(XP_MACOSX)
+              nsCOMPtr<nsIFile>& aLibDirectory,
+#endif
+              nsCOMPtr<nsIFile>& aLibFile)
+{
+  nsAutoString baseName;
+#ifdef XP_MACOSX
+  GetFileBase(aPluginPath, aLibDirectory, aLibFile, baseName);
+#else
+  GetFileBase(aPluginPath, aLibFile, baseName);
+#endif
 
 #if defined(XP_MACOSX)
   nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".dylib");
 #elif defined(OS_POSIX)
   nsAutoString binaryName = NS_LITERAL_STRING("lib") + baseName + NS_LITERAL_STRING(".so");
 #elif defined(XP_WIN)
   nsAutoString binaryName =                            baseName + NS_LITERAL_STRING(".dll");
 #else
 #error not defined
 #endif
   aLibFile->AppendRelativePath(binaryName);
   return true;
 }
 
+#ifdef XP_WIN
+static bool
+GetInfoFile(const std::string& aPluginPath,
+            nsCOMPtr<nsIFile>& aInfoFile)
+{
+  nsAutoString baseName;
+  GetFileBase(aPluginPath, aInfoFile, baseName);
+  nsAutoString infoFileName = baseName + NS_LITERAL_STRING(".info");
+  aInfoFile->AppendRelativePath(infoFileName);
+  return true;
+}
+#endif
+
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
 static bool
 GetPluginPaths(const std::string& aPluginPath,
                nsCString &aPluginDirectoryPath,
                nsCString &aPluginFilePath)
 {
   nsCOMPtr<nsIFile> libDirectory, libFile;
   if (!GetPluginFile(aPluginPath, libDirectory, libFile)) {
@@ -232,23 +268,87 @@ GMPChild::Init(const std::string& aPlugi
   SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
 #endif
 
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   mPluginPath = aPluginPath;
   return true;
 #endif
 
+#ifdef XP_WIN
+  PreLoadLibraries(aPluginPath);
+#endif
+
 #if defined(MOZ_SANDBOX) && defined(XP_WIN)
   mozilla::SandboxTarget::Instance()->StartSandbox();
 #endif
 
   return LoadPluginLibrary(aPluginPath);
 }
 
+#ifdef XP_WIN
+// Pre-load DLLs that need to be used by the EME plugin but that can't be
+// loaded after the sandbox has started
+bool
+GMPChild::PreLoadLibraries(const std::string& aPluginPath)
+{
+  // This must be in sorted order and lowercase!
+  static const char* whitelist[] =
+    {
+       "d3d9.dll", // Create an `IDirect3D9` to get adapter information
+       "dxva2.dll", // Get monitor information
+       "msauddecmft.dll", // H.264 decoder
+       "msmpeg2adec.dll", // AAC decoder (on Windows 7)
+       "msmpeg2vdec.dll", // AAC decoder (on Windows 8)
+    };
+  static const int whitelistLen = sizeof(whitelist) / sizeof(whitelist[0]);
+
+  nsCOMPtr<nsIFile> infoFile;
+  GetInfoFile(aPluginPath, infoFile);
+
+  nsString path;
+  infoFile->GetPath(path);
+
+  std::ifstream stream;
+  stream.open(path.get());
+  if (!stream.good()) {
+    NS_WARNING("Failure opening info file for required DLLs");
+    return false;
+  }
+
+  do {
+    std::string line;
+    getline(stream, line);
+    if (stream.fail()) {
+      NS_WARNING("Failure reading info file for required DLLs");
+      return false;
+    }
+    std::transform(line.begin(), line.end(), line.begin(), tolower);
+    static const char* prefix = "libraries:";
+    static const int prefixLen = strlen(prefix);
+    if (0 == line.compare(0, prefixLen, prefix)) {
+      char* lineCopy = strdup(line.c_str() + prefixLen);
+      char* start = lineCopy;
+      while (char* tok = nsCRT::strtok(start, ", ", &start)) {
+        for (int i = 0; i < whitelistLen; i++) {
+          if (0 == strcmp(whitelist[i], tok)) {
+            LoadLibraryA(tok);
+            break;
+          }
+        }
+      }
+      free(lineCopy);
+      break;
+    }
+  } while (!stream.eof());
+
+  return true;
+}
+#endif
+
 bool
 GMPChild::LoadPluginLibrary(const std::string& aPluginPath)
 {
 #if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
   nsAutoCString nativePath;
   nativePath.Assign(mPluginBinaryPath);
 
   mLib = PR_LoadLibrary(nativePath.get());
--- a/content/media/gmp/GMPChild.h
+++ b/content/media/gmp/GMPChild.h
@@ -29,16 +29,19 @@ public:
   void OnChannelConnected(int32_t aPid);
 #endif
 
   bool Init(const std::string& aPluginPath,
             base::ProcessHandle aParentProcessHandle,
             MessageLoop* aIOLoop,
             IPC::Channel* aChannel);
   bool LoadPluginLibrary(const std::string& aPluginPath);
+#ifdef XP_WIN
+  bool PreLoadLibraries(const std::string& aPluginPath);
+#endif
   MessageLoop* GMPMessageLoop();
 
   // Main thread only.
   GMPTimerChild* GetGMPTimers();
   GMPStorageChild* GetGMPStorage();
 
   // GMPSharedMem
   virtual void CheckThread() MOZ_OVERRIDE;
--- a/content/media/omx/RtspOmxReader.cpp
+++ b/content/media/omx/RtspOmxReader.cpp
@@ -36,16 +36,17 @@ nsresult RtspOmxReader::Seek(int64_t aTi
                              int64_t aEndTime, int64_t aCurrentTime)
 {
   // The seek function of Rtsp is time-based, we call the SeekTime function in
   // RtspMediaResource. The SeekTime function finally send a seek command to
   // Rtsp stream server through network and also clear the buffer data in
   // RtspMediaResource.
   if (mRtspResource) {
     mRtspResource->SeekTime(aTime);
+    mRtspResource->EnablePlayoutDelay();
   }
 
   // Call |MediaOmxReader::Seek| to notify the OMX decoder we are performing a
   // seek operation. The function will clear the |mVideoQueue| and |mAudioQueue|
   // that store the decoded data and also call the |DecodeToTarget| to pass
   // the seek time to OMX a/v decoders.
   return MediaOmxReader::Seek(aTime, aStartTime, aEndTime, aCurrentTime);
 }
@@ -75,9 +76,27 @@ void RtspOmxReader::EnsureActive() {
     }
     mRtspResource->SetSuspend(false);
   }
 
   // Call parent class to set OMXCodec active.
   MediaOmxReader::EnsureActive();
 }
 
+nsresult RtspOmxReader::ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags)
+{
+  // Send a PLAY command to the RTSP server before reading metadata.
+  // Because we might need some decoded samples to ensure we have configuration.
+  mRtspResource->DisablePlayoutDelay();
+  EnsureActive();
+  nsresult rv = MediaOmxReader::ReadMetadata(aInfo, aTags);
+
+  if (rv == NS_OK && !IsWaitingMediaResources()) {
+    mRtspResource->EnablePlayoutDelay();
+  } else if (IsWaitingMediaResources()) {
+    // Send a PAUSE to the RTSP server because the underlying media resource is
+    // not ready.
+    SetIdle();
+  }
+  return rv;
+}
+
 } // namespace mozilla
--- a/content/media/omx/RtspOmxReader.h
+++ b/content/media/omx/RtspOmxReader.h
@@ -60,16 +60,19 @@ public:
   // data so the |GetBuffered| function can retrieve useful time ranges.
   virtual nsresult GetBuffered(mozilla::dom::TimeRanges* aBuffered,
                                int64_t aStartTime) MOZ_FINAL MOZ_OVERRIDE {
     return NS_OK;
   }
 
   virtual void SetIdle() MOZ_OVERRIDE;
 
+  virtual nsresult ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags)
+    MOZ_FINAL MOZ_OVERRIDE;
+
 private:
   // A pointer to RtspMediaResource for calling the Rtsp specific function.
   // The lifetime of mRtspResource is controlled by MediaDecoder. MediaDecoder
   // holds the MediaDecoderStateMachine and RtspMediaResource.
   // And MediaDecoderStateMachine holds this RtspOmxReader.
   RtspMediaResource* mRtspResource;
 };
 
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -17,17 +17,17 @@
 # throws an error (and does not cause a crash or hang), just add it to
 # gErrorTests in manifest.js.
 
 # To test for a specific bug in handling a specific resource type, make the
 # test first check canPlayType for the type, and if it's not supported, just
 # do ok(true, "Type not supported") and stop the test.
 
 [DEFAULT]
-skip-if = buildapp == 'mulet'
+skip-if = buildapp == 'mulet' || (os == 'win' && contentSandbox != 'off') # contentSandbox(Bug 1042735)
 support-files =
   320x240.ogv
   320x240.ogv^headers^
   448636.ogv
   448636.ogv^headers^
   VID_0001.ogg
   VID_0001.ogg^headers^
   allowed.sjs
@@ -362,17 +362,16 @@ skip-if = toolkit == 'android' # bug 608
 [test_invalid_reject_play.html]
 [test_invalid_seek.html]
 [test_load.html]
 [test_load_candidates.html]
 [test_load_same_resource.html]
 [test_load_source.html]
 [test_loop.html]
 [test_media_selection.html]
-skip-if = toolkit == 'gonk' && !debug # bug 1021677
 [test_media_sniffer.html]
 [test_mediarecorder_avoid_recursion.html]
 [test_mediarecorder_creation.html]
 [test_mediarecorder_creation_fail.html]
 [test_mediarecorder_getencodeddata.html]
 [test_mediarecorder_record_4ch_audiocontext.html]
 [test_mediarecorder_record_audiocontext.html]
 [test_mediarecorder_record_audiocontext_mlk.html]
@@ -457,17 +456,16 @@ skip-if = true # bug 1021673
 [test_source_write.html]
 [test_standalone.html]
 [test_streams_autoplay.html]
 [test_streams_element_capture.html]
 skip-if = e10s && os == 'win' # Bug 1065881 - Crash on child process shutdown in ShadowLayerForwarder::InWorkerThread
 [test_streams_element_capture_createObjectURL.html]
 [test_streams_element_capture_playback.html]
 [test_streams_element_capture_reset.html]
-skip-if = buildapp == 'b2g' # bug 901102
 [test_streams_gc.html]
 skip-if = buildapp == 'b2g' # bug 1021682
 [test_streams_srcObject.html]
 [test_streams_tracks.html]
 [test_texttrack.html]
 [test_texttrackcue.html]
 [test_texttracklist.html]
 [test_texttrackregion.html]
--- a/content/media/test/test_media_selection.html
+++ b/content/media/test/test_media_selection.html
@@ -4,16 +4,21 @@
   <title>Media test: media selection</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="application/javascript" src="manifest.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
+//longer timeout for sometimes B2G emulator runs very slowly
+if (SpecialPowers.Services.appinfo.name == "B2G") {
+  SimpleTest.requestLongerTimeout(3);
+}
+
 var manager = new MediaTestManager;
 
 function maketest(attach_media, name, type, check_metadata) {
   return function (token) {
     var e = document.createElement('video');
     e.preload = "metadata";
     manager.started(token);
     var errorRun = false;
--- a/content/media/test/test_playback.html
+++ b/content/media/test/test_playback.html
@@ -16,66 +16,101 @@ if (SpecialPowers.Services.appinfo.name 
 }
 
 var manager = new MediaTestManager;
 
 function startTest(test, token) {
   var v = document.createElement('video');
   v.preload = "metadata";
   v.token = token;
+  v.prevTime = 0;
   manager.started(token);
 
   v.src = test.name;
   v.name = test.name;
+
   var check = function(test, v) { return function() {
-    is(test.name, v.name, "Name should match test.name #1");
+    is(test.name, v.name, test.name + ": Name should match #1");
     checkMetadata(test.name, v, test);
   }}(test, v);
+
   var noLoad = function(test, v) { return function() {
     ok(false, test.name + " should not fire 'load' event");
   }}(test, v);
+
+  // Used to cancel timer callback.
+  var timer = null;
+
+  var cancelTimer = function() {
+    if (timer) {
+      clearTimeout(timer);
+    }
+  }
+
+  var finish = function() {
+    cancelTimer();
+    v.finished = true;
+    v.removeEventListener("timeupdate", timeUpdate, false);
+    removeNodeAndSource(v);
+    manager.finished(v.token);
+  }
+
+  // We should get "ended" and "suspend" events to finish the test.
+  var mayFinish = function() {
+    if (v.seenEnded && v.seenSuspend) {
+      finish();
+    }
+  }
+
+  var onTimeout = function() {
+    ok(v.seenEnded, v.name + " timed out, should get 'ended'");
+    ok(v.seenSuspend, v.name + " timed out, should get 'suspend'");
+    finish();
+  }
+
+  // Check if we time out in waiting for some events.
+  var registerTimer = function() {
+    cancelTimer();
+    timer = setTimeout(onTimeout, 30000);
+  }
+
   var checkEnded = function(test, v) { return function() {
-    if (test.duration) {
-      ok(Math.abs(v.currentTime - test.duration) < 0.1,
-         test.name + " current time at end: " + v.currentTime + " should be: " + test.duration);
-    }
-    is(test.name, v.name, "Name should match test.name #2");
+    is(test.name, v.name, test.name + ": Name should match #2");
+    checkMetadata(test.name, v, test);
     is(v.readyState, v.HAVE_CURRENT_DATA, test.name + " checking readyState");
     ok(v.readyState != v.NETWORK_LOADED, test.name + " shouldn't report NETWORK_LOADED");
     ok(v.ended, test.name + " checking playback has ended");
-    if (v.ended && v.seenSuspend && !v.finished) {
-      v.finished = true;
-      v.removeEventListener("timeupdate", timeUpdate, false);
-      removeNodeAndSource(v);
-      manager.finished(v.token);
+    ok(!v.finished, test.name + " shouldn't be finished");
+    ok(!v.seenEnded, test.name + " shouldn't be ended");
+
+    v.seenEnded = true;
+    registerTimer();
+    mayFinish();
+  }}(test, v);
+
+  var checkSuspended = function(test, v) { return function() {
+    if (v.seenSuspend) {
+      return;
     }
-  }}(test, v);
-  var checkSuspended = function(test, v) { return function() {
-    is(test.name, v.name, "Name should match test.name #3");
-    if (v.seenSuspend)
-      return;
+    is(test.name, v.name, test.name + ": Name should match #3");
 
     v.seenSuspend = true;
-    ok(true, test.name + " got suspend");
-    if (v.ended && !v.finished) {
-      v.finished = true;
-      v.removeEventListener("timeupdate", timeUpdate, false);
-      removeNodeAndSource(v);
-      manager.finished(v.token);
-    }
+    registerTimer();
+    mayFinish();
   }}(test, v);
-  v.prevTime = 0;
+
   var timeUpdate = function(test, v) { return function() {
-    is(test.name, v.name, "Name should match test.name #4");
-    checkMetadata(test.name, v, test);
-    ok(v.prevTime <= v.currentTime,
-       test.name + " time should run forwards: p=" +
-       v.prevTime + " c=" + v.currentTime);
+    if (v.prevTime > v.currentTime) {
+      ok(false, test.name + " time should run forwards: p=" +
+                v.prevTime + " c=" + v.currentTime);
+    }
     v.prevTime = v.currentTime;
+    registerTimer();
   }}(test, v);
+
   v.addEventListener("load", noLoad, false);
   v.addEventListener("loadedmetadata", check, false);
   v.addEventListener("timeupdate", timeUpdate, false);
 
   // We should get "ended" and "suspend" events for every resource
   v.addEventListener("ended", checkEnded, false);
   v.addEventListener("suspend", checkSuspended, false);
 
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -110,17 +110,18 @@ AudioBuffer::RestoreJSChannelData(JSCont
       // The following code first zeroes the array and then copies our data
       // into it. We could avoid this with additional JS APIs to construct
       // an array (or ArrayBuffer) containing initial data.
       JS::Rooted<JSObject*> array(aJSContext,
                                   JS_NewFloat32Array(aJSContext, mLength));
       if (!array) {
         return false;
       }
-      memcpy(JS_GetFloat32ArrayData(array), data, sizeof(float)*mLength);
+      JS::AutoCheckCannotGC nogc;
+      mozilla::PodCopy(JS_GetFloat32ArrayData(array, nogc), data, mLength);
       mJSChannels[i] = array;
     }
 
     mSharedChannels = nullptr;
   }
 
   return true;
 }
@@ -141,19 +142,20 @@ AudioBuffer::CopyFromChannel(const Float
   }
 
   if (!mSharedChannels && JS_GetTypedArrayLength(mJSChannels[aChannelNumber]) != mLength) {
     // The array was probably neutered
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
+  JS::AutoCheckCannotGC nogc;
   const float* sourceData = mSharedChannels ?
     mSharedChannels->GetData(aChannelNumber) :
-    JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]);
+    JS_GetFloat32ArrayData(mJSChannels[aChannelNumber], nogc);
   PodMove(aDestination.Data(), sourceData + aStartInChannel, length);
 }
 
 void
 AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
                            uint32_t aChannelNumber, uint32_t aStartInChannel,
                            ErrorResult& aRv)
 {
@@ -174,26 +176,28 @@ AudioBuffer::CopyToChannel(JSContext* aJ
     return;
   }
 
   if (!RestoreJSChannelData(aJSContext)) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
-  PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber]) + aStartInChannel,
+  JS::AutoCheckCannotGC nogc;
+  PodMove(JS_GetFloat32ArrayData(mJSChannels[aChannelNumber], nogc) + aStartInChannel,
           aSource.Data(), length);
 }
 
 void
 AudioBuffer::SetRawChannelContents(uint32_t aChannel, float* aContents)
 {
   MOZ_ASSERT(!GetWrapperPreserveColor() && !mSharedChannels,
              "The AudioBuffer object should not have been handed to JS or have C++ callers neuter its typed array");
-  PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, mLength);
+  JS::AutoCheckCannotGC nogc;
+  PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel], nogc), aContents, mLength);
 }
 
 void
 AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
                             JS::MutableHandle<JSObject*> aRetval,
                             ErrorResult& aRv)
 {
   if (aChannel >= NumberOfChannels()) {
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) #b2g-debug,b2g-desktop(bug 916135)
+skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && (toolkit != 'gonk' || debug)) || (os == 'win' && contentSandbox != 'off') #b2g-debug,b2g-desktop(bug 916135); contentSandbox(Bug 1042735)
 support-files =
   audio-expected.wav
   audio-mono-expected-2.wav
   audio-mono-expected.wav
   audio-quad.wav
   audio.ogv
   audioBufferSourceNodeNeutered_worker.js
   invalid.txt
--- a/content/media/webm/WebMReader.cpp
+++ b/content/media/webm/WebMReader.cpp
@@ -26,39 +26,40 @@ using mozilla::NesteggPacketHolder;
 template <>
 class nsAutoRefTraits<NesteggPacketHolder> :
   public nsPointerRefTraits<NesteggPacketHolder>
 {
 public:
   static void Release(NesteggPacketHolder* aHolder) { delete aHolder; }
 };
 
-namespace mozilla {
-
-using namespace gfx;
-using namespace layers;
-
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
 
 #ifdef PR_LOGGING
 #include "prprf.h"
-extern PRLogModuleInfo* gMediaDecoderLog;
-PRLogModuleInfo* gNesteggLog;
 #define LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #ifdef SEEK_LOGGING
 #define SEEK_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
 #else
 #define SEEK_LOG(type, msg)
 #endif
 #else
 #define LOG(type, msg)
 #define SEEK_LOG(type, msg)
 #endif
 
+namespace mozilla {
+
+using namespace gfx;
+using namespace layers;
+
+extern PRLogModuleInfo* gMediaDecoderLog;
+PRLogModuleInfo* gNesteggLog;
+
 static const unsigned NS_PER_USEC = 1000;
 static const double NS_PER_S = 1e9;
 
 // Functions for reading and seeking using MediaResource required for
 // nestegg_io. The 'user data' passed to these functions is the
 // decoder from which the media resource is obtained.
 static int webm_read(void *aBuffer, size_t aLength, void *aUserData)
 {
--- a/content/media/webspeech/synth/nsSpeechTask.cpp
+++ b/content/media/webspeech/synth/nsSpeechTask.cpp
@@ -157,16 +157,30 @@ nsSpeechTask::Setup(nsISpeechTaskCallbac
   AudioSegment* segment = new AudioSegment();
   mStream->AddTrack(1, aRate, 0, segment);
   mStream->AddAudioOutput(this);
   mStream->SetAudioOutputVolume(this, mVolume);
 
   return NS_OK;
 }
 
+static nsRefPtr<mozilla::SharedBuffer>
+makeSamples(int16_t* aData, uint32_t aDataLen)
+{
+  nsRefPtr<mozilla::SharedBuffer> samples =
+    SharedBuffer::Create(aDataLen * sizeof(int16_t));
+  int16_t* frames = static_cast<int16_t*>(samples->Data());
+
+  for (uint32_t i = 0; i < aDataLen; i++) {
+    frames[i] = aData[i];
+  }
+
+  return samples;
+}
+
 NS_IMETHODIMP
 nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLandmarks,
                         JSContext* aCx)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
 
   NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
   NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
@@ -189,18 +203,23 @@ nsSpeechTask::SendAudio(JS::Handle<JS::V
   } else if (JS_IsArrayObject(aCx, darray)) {
     tsrc = JS_NewInt16ArrayFromArray(aCx, darray);
   }
 
   if (!tsrc) {
     return NS_ERROR_DOM_TYPE_MISMATCH_ERR;
   }
 
-  SendAudioImpl(JS_GetInt16ArrayData(tsrc),
-                JS_GetTypedArrayLength(tsrc));
+  uint32_t dataLen = JS_GetTypedArrayLength(tsrc);
+  nsRefPtr<mozilla::SharedBuffer> samples;
+  {
+    JS::AutoCheckCannotGC nogc;
+    samples = makeSamples(JS_GetInt16ArrayData(tsrc, nogc), dataLen);
+  }
+  SendAudioImpl(samples, dataLen);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
 {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
@@ -209,41 +228,34 @@ nsSpeechTask::SendAudioNative(int16_t* a
   NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
   NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
 
   if (mIndirectAudio) {
     NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
     return NS_ERROR_FAILURE;
   }
 
-  SendAudioImpl(aData, aDataLen);
+  nsRefPtr<mozilla::SharedBuffer> samples = makeSamples(aData, aDataLen);
+  SendAudioImpl(samples, aDataLen);
 
   return NS_OK;
 }
 
 void
-nsSpeechTask::SendAudioImpl(int16_t* aData, uint32_t aDataLen)
+nsSpeechTask::SendAudioImpl(nsRefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen)
 {
   if (aDataLen == 0) {
     mStream->EndAllTrackAndFinish();
     return;
   }
 
-  nsRefPtr<mozilla::SharedBuffer> samples =
-    SharedBuffer::Create(aDataLen * sizeof(int16_t));
-  int16_t* frames = static_cast<int16_t*>(samples->Data());
-
-  for (uint32_t i = 0; i < aDataLen; i++) {
-    frames[i] = aData[i];
-  }
-
   AudioSegment segment;
   nsAutoTArray<const int16_t*, 1> channelData;
-  channelData.AppendElement(frames);
-  segment.AppendFrames(samples.forget(), channelData, aDataLen);
+  channelData.AppendElement(static_cast<int16_t*>(aSamples->Data()));
+  segment.AppendFrames(aSamples.forget(), channelData, aDataLen);
   mStream->AppendToTrack(1, &segment);
   mStream->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 }
 
 NS_IMETHODIMP
 nsSpeechTask::DispatchStart()
 {
   if (!mIndirectAudio) {
--- a/content/media/webspeech/synth/nsSpeechTask.h
+++ b/content/media/webspeech/synth/nsSpeechTask.h
@@ -69,17 +69,17 @@ protected:
 
   float mVolume;
 
   nsString mText;
 
 private:
   void End();
 
-  void SendAudioImpl(int16_t* aData, uint32_t aDataLen);
+  void SendAudioImpl(nsRefPtr<mozilla::SharedBuffer>& aSamples, uint32_t aDataLen);
 
   nsRefPtr<SourceMediaStream> mStream;
 
   nsCOMPtr<nsISpeechTaskCallback> mCallback;
 
   uint32_t mChannels;
 
   nsRefPtr<SpeechSynthesis> mSpeechSynthesis;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4372,32 +4372,32 @@ nsDocShell::GetWindow()
 {
   NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
   return mScriptGlobal;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
 {
-    if (mDeviceSizeIsPageSize != aValue) {
-      mDeviceSizeIsPageSize = aValue;
-      nsRefPtr<nsPresContext> presContext;
-      GetPresContext(getter_AddRefs(presContext));
-      if (presContext) {
-          presContext->MediaFeatureValuesChanged(presContext->eAlwaysRebuildStyle);
-      }
-    }
-    return NS_OK;
+  if (mDeviceSizeIsPageSize != aValue) {
+    mDeviceSizeIsPageSize = aValue;
+    nsRefPtr<nsPresContext> presContext;
+    GetPresContext(getter_AddRefs(presContext));
+    if (presContext) {
+      presContext->MediaFeatureValuesChanged(nsRestyleHint(0));
+    }
+  }
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
 {
-    *aValue = mDeviceSizeIsPageSize;
-    return NS_OK;
+  *aValue = mDeviceSizeIsPageSize;
+  return NS_OK;
 }
 
 void
 nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
 {
   nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
   nsCOMPtr<nsISHistory> rootSH;
   GetRootSessionHistory(getter_AddRefs(rootSH));
--- a/dom/base/nsHistory.cpp
+++ b/dom/base/nsHistory.cpp
@@ -162,17 +162,17 @@ nsHistory::Go(int32_t aDelta, ErrorResul
       // trick to work around gecko reflow bugs, and this should have
       // the same effect.
 
       nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
 
       nsIPresShell *shell;
       nsPresContext *pcx;
       if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
-        pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
+        pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW, eRestyle_Subtree);
       }
 
       return;
     }
   }
 
   nsCOMPtr<nsISHistory> session_history = GetSessionHistory();
   nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history));
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -918,17 +918,17 @@ nsLocation::Reload(bool aForceget)
     // page since some sites may use this trick to work around gecko
     // reflow bugs, and this should have the same effect.
 
     nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
 
     nsIPresShell *shell;
     nsPresContext *pcx;
     if (doc && (shell = doc->GetShell()) && (pcx = shell->GetPresContext())) {
-      pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
+      pcx->RebuildAllStyleData(NS_STYLE_HINT_REFLOW, eRestyle_Subtree);
     }
 
     return NS_OK;
   }
 
   if (webNav) {
     uint32_t reloadFlags = nsIWebNavigation::LOAD_FLAGS_NONE;
 
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -134,17 +134,17 @@ public:
 
 private:
   TypedArray_base(const TypedArray_base&) MOZ_DELETE;
 };
 
 
 template<typename T,
          JSObject* UnwrapArray(JSObject*),
-         T* GetData(JSObject*),
+         T* GetData(JSObject*, const JS::AutoCheckCannotGC&),
          void GetLengthAndData(JSObject*, uint32_t*, T**),
          JSObject* CreateNew(JSContext*, uint32_t)>
 struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
 private:
   typedef TypedArray_base<T, UnwrapArray, GetLengthAndData> Base;
 
 public:
   TypedArray()
@@ -176,17 +176,18 @@ public:
 private:
   static inline JSObject*
   CreateCommon(JSContext* cx, uint32_t length, const T* data) {
     JSObject* obj = CreateNew(cx, length);
     if (!obj) {
       return nullptr;
     }
     if (data) {
-      T* buf = static_cast<T*>(GetData(obj));
+      JS::AutoCheckCannotGC nogc;
+      T* buf = static_cast<T*>(GetData(obj, nogc));
       memcpy(buf, data, length*sizeof(T));
     }
     return obj;
   }
 
   TypedArray(const TypedArray&) MOZ_DELETE;
 };
 
--- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp
@@ -363,24 +363,37 @@ public:
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     if (mImpl->IsShutdownOnMainThread()) {
       BT_LOGD("mConsumer is null, aborting receive!");
       return;
     }
 
+    if (aConnectionStatus != 0) {
+      mImpl->mConsumer->NotifyError();
+      return;
+    }
+
     mImpl->mConsumer->SetAddress(aBdAddress);
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new AcceptTask(mImpl, aFd));
   }
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     BT_LOGR("BluetoothSocketInterface::Accept failed: %d", (int)aStatus);
+
+    if (!mImpl->IsShutdownOnMainThread()) {
+      // Instead of NotifyError(), call NotifyDisconnect() to trigger
+      // BluetoothOppManager::OnSocketDisconnect() as
+      // DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
+      // order to keep the same behavior and reduce regression risk.
+      mImpl->mConsumer->NotifyDisconnect();
+    }
   }
 
 private:
   DroidSocketImpl* mImpl;
 };
 
 class AcceptRunnable MOZ_FINAL : public SocketIORunnable<DroidSocketImpl>
 {
@@ -499,27 +512,43 @@ public:
     MOZ_ASSERT(mImpl);
   }
 
   void Connect(int aFd, const nsAString& aBdAddress,
                int aConnectionStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
-    if (!mImpl->IsShutdownOnMainThread()) {
-      mImpl->mConsumer->SetAddress(aBdAddress);
+    if (mImpl->IsShutdownOnMainThread()) {
+      BT_LOGD("mConsumer is null, aborting send!");
+      return;
     }
+
+    if (aConnectionStatus != 0) {
+      mImpl->mConsumer->NotifyError();
+      return;
+    }
+
+    mImpl->mConsumer->SetAddress(aBdAddress);
     XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
                                      new SocketConnectTask(mImpl, aFd));
   }
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     BT_WARNING("Connect failed: %d", (int)aStatus);
+
+    if (!mImpl->IsShutdownOnMainThread()) {
+      // Instead of NotifyError(), call NotifyDisconnect() to trigger
+      // BluetoothOppManager::OnSocketDisconnect() as
+      // DroidSocketImpl::OnFileCanReadWithoutBlocking() in Firefox OS 2.0 in
+      // order to keep the same behavior and reduce regression risk.
+      mImpl->mConsumer->NotifyDisconnect();
+    }
   }
 
 private:
   DroidSocketImpl* mImpl;
 };
 
 bool
 BluetoothSocket::ConnectSocket(const nsAString& aDeviceAddress, int aChannel)
--- a/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp
@@ -281,17 +281,17 @@ private:
     iv.iov_len = MSG1_SIZE;
 
     struct msghdr msg;
     memset(&msg, 0, sizeof(msg));
     msg.msg_iov = &iv;
     msg.msg_iovlen = 1;
 
     ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
-    if (res < 0) {
+    if (res <= 0) {
       return STATUS_FAIL;
     }
 
     mLen += res;
 
     return STATUS_SUCCESS;
   }
 
@@ -306,17 +306,17 @@ private:
     struct cmsghdr cmsgbuf[2 * sizeof(cmsghdr) + 0x100];
     memset(&msg, 0, sizeof(msg));
     msg.msg_iov = &iv;
     msg.msg_iovlen = 1;
     msg.msg_control = cmsgbuf;
     msg.msg_controllen = sizeof(cmsgbuf);
 
     ssize_t res = TEMP_FAILURE_RETRY(recvmsg(mFd, &msg, MSG_NOSIGNAL));
-    if (res < 0) {
+    if (res <= 0) {
       return STATUS_FAIL;
     }
 
     mLen += res;
 
     if (msg.msg_flags & (MSG_CTRUNC | MSG_OOB | MSG_ERRQUEUE)) {
       return STATUS_FAIL;
     }
--- a/dom/browser-element/mochitest/browserElement_CopyPaste.js
+++ b/dom/browser-element/mochitest/browserElement_CopyPaste.js
@@ -87,59 +87,49 @@ function dispatchTest(e) {
       pasteData = "from parent ";
       iframe.src = "data:text/html,<html><body>" +
                    "<input type='text' id='text' value='" + defaultData + "'>" +
                    "</body>" +
                    "</html>";
       stateMeaning = " (test: <input type=text>)";
       focusScript = "var elt=content.document.getElementById('text');elt.focus();elt.select();";
       break;
-    case 2: // test for input password
-      defaultData = "Test for selection change event";
-      pasteData = "from parent ";
-      iframe.src = "data:text/html,<html><body>" +
-                   "<input type='password' id='text' value='" + defaultData + "'>" +
-                   "</body>" +
-                   "</html>";
-      stateMeaning = " (test: <input type=password>)";
-      focusScript = "var elt=content.document.getElementById('text');elt.focus();elt.select();";
-      break;
-    case 3: // test for input number
+    case 2: // test for input number
       defaultData = "12345";
       pasteData = "67890";
       iframe.src = "data:text/html,<html><body>" +
                    "<input type='number' id='text' value='" + defaultData + "'>" +
                    "</body>" +
                    "</html>";
       stateMeaning = " (test: <input type=number>)";
       focusScript = "var elt=content.document.getElementById('text');elt.focus();elt.select();";
       break;
-    case 4: // test for div contenteditable
+    case 3: // test for div contenteditable
       defaultData = "Test for selection change event";
       pasteData = "from parent ";
       iframe.src = "data:text/html,<html><body>" +
                    "<div contenteditable='true' id='text'>" + defaultData + "</div>" +
                    "</body>" +
                    "</html>";
       stateMeaning = " (test: content editable div)";
       focusScript = "var elt=content.document.getElementById('text');elt.focus();";
       break;
-    case 5: // test for normal div
+    case 4: // test for normal div
       SimpleTest.finish();
       return;
       defaultData = "Test for selection change event";
       pasteData = "from parent ";
       iframe.src = "data:text/html,<html><body>" +
                    "<div id='text'>" + defaultData + "</div>" +
                    "</body>" +
                    "</html>";
       stateMeaning = " (test: normal div)";
       focusScript = "var elt=content.document.getElementById('text');elt.focus();";
       break;
-    case 6: // test for normal div with designMode:on
+    case 5: // test for normal div with designMode:on
       defaultData = "Test for selection change event";
       pasteData = "from parent ";
       iframe.src = "data:text/html,<html><body id='text'>" +
                    defaultData +
                    "</body>" +
                    "<script>document.designMode='on';</script>" +
                    "</html>";
       stateMeaning = " (test: normal div with designMode:on)";
@@ -187,43 +177,35 @@ function testCopy1(e) {
     nextTest(true);
   }
 
   let fail = function() {
     nextTest(false);
   }
 
   let compareData = defaultData;
-  if (state == 2) {
-    // In password case, we just check length of text at clipboard is equal
-    // to length of defaultData
-    compareData = function(clipboardText) {
-      return clipboardText.length == defaultData.length;
-    };
-  }
-
   SimpleTest.waitForClipboard(compareData, setup, success, fail);
 }
 
 function testPaste1(e) {
   // Next test paste command, first we copy to global clipboard in parent side.
   // Then paste it to child side.
   copyToClipboard(pasteData);
 
   doCommand("paste");
   SimpleTest.executeSoon(function() { testPaste2(e); });
 }
 
 function testPaste2(e) {
   mm.addMessageListener('content-text', function messageforpaste(msg) {
     mm.removeMessageListener('content-text', messageforpaste);
-    if (state == 5) {
+    if (state == 4) {
       // normal div cannot paste, so the content remain unchange
       ok(SpecialPowers.wrap(msg).json === defaultData, "paste command works" + stateMeaning);
-    } else if (state == 4 && browserElementTestHelpers.getOOPByDefaultPref()) {
+    } else if (state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) {
       // Something weird when we doCommand with content editable element in OOP. Mark this case as todo
       todo(false, "paste command works" + stateMeaning);
     } else {
       ok(SpecialPowers.wrap(msg).json === pasteData, "paste command works" + stateMeaning);
     }
     SimpleTest.executeSoon(function() { testCut1(e); });
   });
 
@@ -234,17 +216,17 @@ function testCut1(e) {
   // Clean clipboard first
   copyToClipboard("");
   let setup = function() {
     doCommand("selectall");
     doCommand("cut");
   };
 
   let nextTest = function(success) {
-    if (state == 4 && browserElementTestHelpers.getOOPByDefaultPref()) {
+    if (state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) {
       // Something weird when we doCommand with content editable element in OOP.
       todo(false, "cut function works" + stateMeaning);
     } else {
       ok(success, "cut function works" + stateMeaning);
     }
     SimpleTest.executeSoon(function() { testCut2(e); });
   };
 
@@ -252,38 +234,32 @@ function testCut1(e) {
     nextTest(true);
   }
 
   let fail = function() {
     nextTest(false);
   }
 
   let compareData = pasteData;
-  if (state == 2) {
-    // In password case, we just check length of text at clipboard is equal
-    // to length of pasteData
-    compareData = function(clipboardText) {
-      return clipboardText.length == pasteData.length;
-    };
-  } else if (state == 4 && browserElementTestHelpers.getOOPByDefaultPref()) {
+  if (state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) {
     // Something weird when we doCommand with content editable element in OOP.
     // Always true in this case
     compareData = function() { return true; }
   }
 
   SimpleTest.waitForClipboard(compareData, setup, success, fail);
 }
 
 function testCut2(e) {
   mm.addMessageListener('content-text', function messageforcut(msg) {
     mm.removeMessageListener('content-text', messageforcut);
     // normal div cannot cut
-    if (state == 5) {
+    if (state == 4) {
       ok(SpecialPowers.wrap(msg).json !== "", "cut command works" + stateMeaning);
-    } else if (state == 4 && browserElementTestHelpers.getOOPByDefaultPref()) {
+    } else if (state == 3 && browserElementTestHelpers.getOOPByDefaultPref()) {
       // Something weird when we doCommand with content editable element in OOP. Mark this case as todo
       todo(false, "cut command works" + stateMeaning);
     } else {
       ok(SpecialPowers.wrap(msg).json === "", "cut command works" + stateMeaning);
     }
 
     state++;
     dispatchTest(e);
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -4510,28 +4510,34 @@ CanvasRenderingContext2D::GetImageDataAr
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (mZero) {
     *aRetval = darray;
     return NS_OK;
   }
 
-  uint8_t* data = JS_GetUint8ClampedArrayData(darray);
-
   IntRect dstWriteRect = srcReadRect;
   dstWriteRect.MoveBy(-aX, -aY);
 
-  uint8_t* src = data;
-  uint32_t srcStride = aWidth * 4;
+  uint8_t* src;
+  uint32_t srcStride;
+
   if (readback) {
     srcStride = readback->Stride();
     src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4;
   }
 
+  JS::AutoCheckCannotGC nogc;
+  uint8_t* data = JS_GetUint8ClampedArrayData(darray, nogc);
+  if (!readback) {
+    src = data;
+    srcStride = aWidth * 4;
+  }
+
   // NOTE! dst is the same as src, and this relies on reading
   // from src and advancing that ptr before writing to dst.
   // NOTE! I'm not sure that it is, I think this comment might have been
   // inherited from Thebes canvas and is no longer true
   uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4;
 
   if (mOpaque) {
     for (int32_t j = 0; j < dstWriteRect.height; ++j) {
--- a/dom/cellbroadcast/gonk/CellBroadcastService.js
+++ b/dom/cellbroadcast/gonk/CellBroadcastService.js
@@ -11,20 +11,32 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "RIL", function () {
   let obj = {};
   Cu.import("resource://gre/modules/ril_consts.js", obj);
   return obj;
 });
 
+const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
+const kSettingsCellBroadcastDisabled = "ril.cellbroadcast.disabled";
+const kSettingsCellBroadcastSearchList = "ril.cellbroadcast.searchlist";
+
 XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
                                    "@mozilla.org/system-message-internal;1",
                                    "nsISystemMessagesInternal");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
+                                   "@mozilla.org/settingsService;1",
+                                   "nsISettingsService");
+
+XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
+                                   "@mozilla.org/ril;1",
+                                   "nsIRadioInterfaceLayer");
+
 const GONK_CELLBROADCAST_SERVICE_CONTRACTID =
   "@mozilla.org/cellbroadcast/gonkservice;1";
 const GONK_CELLBROADCAST_SERVICE_CID =
   Components.ID("{7ba407ce-21fd-11e4-a836-1bfdee377e5c}");
 const CELLBROADCASTMESSAGE_CID =
   Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
 const CELLBROADCASTETWSINFO_CID =
   Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
@@ -36,35 +48,68 @@ function debug(s) {
   dump("CellBroadcastService: " + s);
 }
 
 function CellBroadcastService() {
   this._listeners = [];
 
   this._updateDebugFlag();
 
+  let lock = gSettingsService.createLock();
+
+  /**
+  * Read the settings of the toggle of Cellbroadcast Service:
+  *
+  * Simple Format: Boolean
+  *   true if CBS is disabled. The value is applied to all RadioInterfaces.
+  * Enhanced Format: Array of Boolean
+  *   Each element represents the toggle of CBS per RadioInterface.
+  */
+  lock.get(kSettingsCellBroadcastDisabled, this);
+
+  /**
+   * Read the Cell Broadcast Search List setting to set listening channels:
+   *
+   * Simple Format:
+   *   String of integers or integer ranges separated by comma.
+   *   For example, "1, 2, 4-6"
+   * Enhanced Format:
+   *   Array of Objects with search lists specified in gsm/cdma network.
+   *   For example, [{'gsm' : "1, 2, 4-6", 'cdma' : "1, 50, 99"},
+   *                 {'cdma' : "3, 6, 8-9"}]
+   *   This provides the possibility to
+   *   1. set gsm/cdma search list individually for CDMA+LTE device.
+   *   2. set search list per RadioInterface.
+   */
+  lock.get(kSettingsCellBroadcastSearchList, this);
+
   Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+  Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
 }
 CellBroadcastService.prototype = {
   classID: GONK_CELLBROADCAST_SERVICE_CID,
 
   classInfo: XPCOMUtils.generateCI({classID: GONK_CELLBROADCAST_SERVICE_CID,
                                     contractID: GONK_CELLBROADCAST_SERVICE_CONTRACTID,
                                     classDescription: "CellBroadcastService",
                                     interfaces: [Ci.nsICellBroadcastService,
                                                  Ci.nsIGonkCellBroadcastService],
                                     flags: Ci.nsIClassInfo.SINGLETON}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastService,
                                          Ci.nsIGonkCellBroadcastService,
+                                         Ci.nsISettingsServiceCallback,
                                          Ci.nsIObserver]),
 
   // An array of nsICellBroadcastListener instances.
   _listeners: null,
 
+  // Setting values of Cell Broadcast SearchList.
+  _cellBroadcastSearchList: null,
+
   _updateDebugFlag: function() {
     try {
       DEBUG = RIL.DEBUG_RIL ||
               Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
     } catch (e) {}
   },
 
   _convertCbGsmGeographicalScope: function(aGeographicalScope) {
@@ -80,16 +125,84 @@ CellBroadcastService.prototype = {
   },
 
   _convertCbEtwsWarningType: function(aWarningType) {
     return (aWarningType >= Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID)
       ? null
       : RIL.CB_ETWS_WARNING_TYPE_NAMES[aWarningType];
   },
 
+  _retrieveSettingValueByClient: function(aClientId, aSettings) {
+    return Array.isArray(aSettings) ? aSettings[aClientId] : aSettings;
+  },
+
+  /**
+   * Helper function to set CellBroadcastDisabled to each RadioInterface.
+   */
+  setCellBroadcastDisabled: function(aSettings) {
+    let numOfRilClients = gRadioInterfaceLayer.numRadioInterfaces;
+    let responses = [];
+    for (let clientId = 0; clientId < numOfRilClients; clientId++) {
+      gRadioInterfaceLayer
+        .getRadioInterface(clientId)
+        .sendWorkerMessage("setCellBroadcastDisabled",
+                           { disabled: this._retrieveSettingValueByClient(clientId, aSettings) });
+    }
+  },
+
+  /**
+   * Helper function to set CellBroadcastSearchList to each RadioInterface.
+   */
+  setCellBroadcastSearchList: function(aSettings) {
+    let numOfRilClients = gRadioInterfaceLayer.numRadioInterfaces;
+    let responses = [];
+    for (let clientId = 0; clientId < numOfRilClients; clientId++) {
+      let newSearchList = this._retrieveSettingValueByClient(clientId, aSettings);
+      let oldSearchList = this._retrieveSettingValueByClient(clientId,
+                                                          this._cellBroadcastSearchList);
+
+      if ((newSearchList == oldSearchList) ||
+          (newSearchList && oldSearchList &&
+           newSearchList.gsm == oldSearchList.gsm &&
+           newSearchList.cdma == oldSearchList.cdma)) {
+        return;
+      }
+
+      gRadioInterfaceLayer
+        .getRadioInterface(clientId).sendWorkerMessage("setCellBroadcastSearchList",
+                                                       { searchList: newSearchList },
+                                                       (function callback(aResponse) {
+        if (DEBUG && !aResponse.success) {
+          debug("Failed to set new search list: " + newSearchList +
+                " to client id: " + clientId);
+        }
+
+        responses.push(aResponse);
+        if (responses.length == numOfRilClients) {
+          let successCount = 0;
+          for (let i = 0; i < responses.length; i++) {
+            if (responses[i].success) {
+              successCount++;
+            }
+          }
+          if (successCount == numOfRilClients) {
+            this._cellBroadcastSearchList = aSettings;
+          } else {
+            // Rollback the change when failure.
+            let lock = gSettingsService.createLock();
+            lock.set(kSettingsCellBroadcastSearchList,
+                     this._cellBroadcastSearchList, null);
+          }
+        }
+
+        return false;
+      }).bind(this));
+    }
+  },
+
   /**
    * nsICellBroadcastService interface
    */
   registerListener: function(aListener) {
     if (this._listeners.indexOf(aListener) >= 0) {
       throw Cr.NS_ERROR_UNEXPECTED;
     }
 
@@ -174,22 +287,53 @@ CellBroadcastService.prototype = {
                                        aEtwsPopup);
       } catch (e) {
         debug("listener threw an exception: " + e);
       }
     }
   },
 
   /**
+   * nsISettingsServiceCallback interface.
+   */
+  handle: function(aName, aResult) {
+    switch (aName) {
+      case kSettingsCellBroadcastSearchList:
+        if (DEBUG) {
+          debug("'" + kSettingsCellBroadcastSearchList +
+                "' is now " + JSON.stringify(aResult));
+        }
+
+        this.setCellBroadcastSearchList(aResult);
+        break;
+      case kSettingsCellBroadcastDisabled:
+        if (DEBUG) {
+          debug("'" + kSettingsCellBroadcastDisabled +
+                "' is now " + JSON.stringify(aResult));
+        }
+
+        this.setCellBroadcastDisabled(aResult);
+        break;
+    }
+  },
+
+  /**
    * nsIObserver interface.
    */
   observe: function(aSubject, aTopic, aData) {
     switch (aTopic) {
+      case kMozSettingsChangedObserverTopic:
+        if ("wrappedJSObject" in aSubject) {
+          aSubject = aSubject.wrappedJSObject;
+        }
+        this.handle(aSubject.key, aSubject.value);
+        break;
       case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
         Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+        Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
 
         // Remove all listeners.
         this._listeners = [];
         break;
     }
   }
 };
 
--- a/dom/cellbroadcast/gonk/CellBroadcastService.manifest
+++ b/dom/cellbroadcast/gonk/CellBroadcastService.manifest
@@ -1,6 +1,7 @@
 # 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/.
 
 component {7ba407ce-21fd-11e4-a836-1bfdee377e5c} CellBroadcastService.js
 contract @mozilla.org/cellbroadcast/gonkservice;1 {7ba407ce-21fd-11e4-a836-1bfdee377e5c}
+category profile-after-change CellBroadcastService @mozilla.org/cellbroadcast/gonkservice;1
--- a/dom/fmradio/FMRadio.cpp
+++ b/dom/fmradio/FMRadio.cpp
@@ -338,17 +338,18 @@ void
 FMRadio::GetRdsgroup(JSContext* cx, JS::MutableHandle<JSObject*> retval)
 {
   uint64_t group;
   if (!IFMRadioService::Singleton()->GetRdsgroup(group)) {
     return;
   }
 
   JSObject *rdsgroup = Uint16Array::Create(cx, this, 4);
-  uint16_t *data = JS_GetUint16ArrayData(rdsgroup);
+  JS::AutoCheckCannotGC nogc;
+  uint16_t *data = JS_GetUint16ArrayData(rdsgroup, nogc);
   data[3] = group & 0xFFFF;
   group >>= 16;
   data[2] = group & 0xFFFF;
   group >>= 16;
   data[1] = group & 0xFFFF;
   group >>= 16;
   data[0] = group & 0xFFFF;
 
--- a/dom/indexedDB/test/unit/xpcshell-shared.ini
+++ b/dom/indexedDB/test/unit/xpcshell-shared.ini
@@ -1,13 +1,13 @@
 # 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/.
 [DEFAULT]
-skip-if = toolkit == 'android' || toolkit == 'gonk'
+skip-if = toolkit == 'gonk'
 
 [test_add_put.js]
 [test_add_twice_failure.js]
 [test_advance.js]
 [test_autoIncrement.js]
 [test_autoIncrement_indexes.js]
 [test_blocked_order.js]
 [test_clear.js]
@@ -20,16 +20,17 @@ skip-if = toolkit == 'android' || toolki
 [test_cursor_mutation.js]
 [test_cursor_update_updates_indexes.js]
 [test_cursors.js]
 [test_deleteDatabase.js]
 [test_deleteDatabase_interactions.js]
 [test_event_source.js]
 [test_getAll.js]
 [test_globalObjects_other.js]
+skip-if = toolkit == 'android' # bug 1079278
 [test_globalObjects_xpc.js]
 [test_global_data.js]
 [test_index_empty_keyPath.js]
 [test_index_getAll.js]
 [test_index_getAllObjects.js]
 [test_index_object_cursors.js]
 [test_index_update_delete.js]
 [test_indexes.js]
--- a/dom/inputmethod/forms.js
+++ b/dom/inputmethod/forms.js
@@ -580,21 +580,18 @@ let FormAssistant = {
           });
         }
         break;
       }
 
       case "Forms:ReplaceSurroundingText": {
         CompositionManager.endComposition('');
 
-        let selectionRange = getSelectionRange(target);
         if (!replaceSurroundingText(target,
                                     json.text,
-                                    selectionRange[0],
-                                    selectionRange[1],
                                     json.offset,
                                     json.length)) {
           if (json.requestId) {
             sendAsyncMessage("Forms:ReplaceSurroundingText:Result:Error", {
               requestId: json.requestId,
               error: "failed"
             });
           }
@@ -1134,41 +1131,60 @@ function getPlaintextEditor(element) {
     }
   }
   if (editor) {
     editor.QueryInterface(Ci.nsIPlaintextEditor);
   }
   return editor;
 }
 
-function replaceSurroundingText(element, text, selectionStart, selectionEnd,
-                                offset, length) {
+function replaceSurroundingText(element, text, offset, length) {
   let editor = FormAssistant.editor;
   if (!editor) {
     return false;
   }
 
   // Check the parameters.
-  let start = selectionStart + offset;
-  if (start < 0) {
-    start = 0;
-  }
   if (length < 0) {
     length = 0;
   }
-  let end = start + length;
 
-  if (selectionStart != start || selectionEnd != end) {
-    // Change selection range before replacing.
-    if (!setSelectionRange(element, start, end)) {
-      return false;
+  // Change selection range before replacing. For content editable element,
+  // searching the node for setting selection range is not needed when the
+  // selection is collapsed within a text node.
+  let fastPathHit = false;
+  if (!isPlainTextField(element)) {
+    let sel = element.ownerDocument.defaultView.getSelection();
+    let node = sel.anchorNode;
+    if (sel.isCollapsed && node && node.nodeType == 3 /* TEXT_NODE */) {
+      let start = sel.anchorOffset + offset;
+      let end = start + length;
+      // Fallback to setSelectionRange() if the replacement span multiple nodes.
+      if (start >= 0 && end <= node.textContent.length) {
+        fastPathHit = true;
+        sel.collapse(node, start);
+        sel.extend(node, end);
+      }
+    }
+  }
+  if (!fastPathHit) {
+    let range = getSelectionRange(element);
+    let start = range[0] + offset;
+    if (start < 0) {
+      start = 0;
+    }
+    let end = start + length;
+    if (start != range[0] || end != range[1]) {
+      if (!setSelectionRange(element, start, end)) {
+        return false;
+      }
     }
   }
 
-  if (start != end) {
+  if (length) {
     // Delete the selected text.
     editor.deleteSelection(Ci.nsIEditor.ePrevious, Ci.nsIEditor.eStrip);
   }
 
   if (text) {
     // We don't use CR but LF
     // see https://bugzilla.mozilla.org/show_bug.cgi?id=902847
     text = text.replace(/\r/g, '\n');
new file mode 100644
--- /dev/null
+++ b/dom/inputmethod/mochitest/file_test_sms_app_1066515.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+  <div id="messages-input" x-inputmode="-moz-sms" contenteditable="true"
+    autofocus="autofocus">fxos<br>hello <b>world</b></div>
+  <script type="application/javascript;version=1.7">
+    let input = document.getElementById('messages-input');
+    input.focus();
+  </script>
+</body>
+</html>
+ </div>
+</body>
+</html>
--- a/dom/inputmethod/mochitest/inputmethod_common.js
+++ b/dom/inputmethod/mochitest/inputmethod_common.js
@@ -26,10 +26,11 @@ function inputmethod_setup(callback) {
     ];
     SpecialPowers.pushPrefEnv({set: prefs}, function() {
       SimpleTest.waitForFocus(callback);
     });
   });
 }
 
 function inputmethod_cleanup() {
+  SpecialPowers.wrap(navigator.mozInputMethod).setActive(false);
   SimpleTest.finish();
 }
--- a/dom/inputmethod/mochitest/mochitest.ini
+++ b/dom/inputmethod/mochitest/mochitest.ini
@@ -3,20 +3,22 @@
 skip-if = (toolkit == 'android' || toolkit == 'gonk') || e10s
 support-files =
   inputmethod_common.js
   file_inputmethod.html
   file_inputmethod_1043828.html
   file_test_app.html
   file_test_sendkey_cancel.html
   file_test_sms_app.html
+  file_test_sms_app_1066515.html
 
 [test_basic.html]
 [test_bug944397.html]
 [test_bug949059.html]
 [test_bug953044.html]
 [test_bug960946.html]
 [test_bug978918.html]
 [test_bug1026997.html]
 [test_bug1043828.html]
+[test_bug1066515.html]
 [test_delete_focused_element.html]
 [test_sendkey_cancel.html]
 [test_two_inputs.html]
new file mode 100644
--- /dev/null
+++ b/dom/inputmethod/mochitest/test_bug1066515.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1066515
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1066515</title>
+  <script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1066515">Mozilla Bug 1066515</a>
+<p id="display"></p>
+<pre id="test">
+<script class="testbody" type="application/javascript;version=1.7">
+
+// The input context.
+var gContext = null;
+
+inputmethod_setup(function() {
+  runTest();
+});
+
+function runTest() {
+  let im = navigator.mozInputMethod;
+
+  im.oninputcontextchange = function() {
+    ok(true, 'inputcontextchange event was fired.');
+    im.oninputcontextchange = null;
+
+    gContext = im.inputcontext;
+    if (!gContext) {
+      ok(false, 'Should have a non-null inputcontext.');
+      inputmethod_cleanup();
+      return;
+    }
+
+    test_replaceSurroundingTextWithinTextNode();
+  };
+
+  // Set current page as an input method.
+  SpecialPowers.wrap(im).setActive(true);
+
+  let iframe = document.createElement('iframe');
+  iframe.src = 'file_test_sms_app_1066515.html';
+  iframe.setAttribute('mozbrowser', true);
+  document.body.appendChild(iframe);
+}
+
+function test_replaceSurroundingTextWithinTextNode() {
+  // Set cursor position after 'f'.
+  gContext.setSelectionRange(1, 0);
+
+  // Replace 'fxos' to 'Hitooo' which the range is within current text node.
+  gContext.replaceSurroundingText('Hitooo', -1, 4).then(function() {
+    gContext.getText().then(function(text) {
+      is(text, 'Hitooo\nhello world', 'replaceSurroundingText successfully.');
+      test_replaceSurroundingTextSpanMultipleNodes();
+    }, function(e) {
+      ok(false, 'getText failed: ' + e.name);
+      inputmethod_cleanup();
+    });
+  }, function(e) {
+    ok(false, 'replaceSurroundingText failed: ' + e.name);
+    inputmethod_cleanup();
+  });
+}
+
+function test_replaceSurroundingTextSpanMultipleNodes() {
+  // Set cursor position to the beginning.
+  gContext.setSelectionRange(0, 0);
+
+  // Replace whole content editable element to 'abc'.
+  gContext.replaceSurroundingText('abc', 0, 100).then(function() {
+    gContext.getText().then(function(text) {
+      is(text, 'abc', 'replaceSurroundingText successfully.');
+      inputmethod_cleanup();
+    }, function(e) {
+      ok(false, 'getText failed: ' + e.name);
+      inputmethod_cleanup();
+    });
+  }, function(e) {
+    ok(false, 'replaceSurroundingText failed: ' + e.name);
+    inputmethod_cleanup();
+  });
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -114,17 +114,18 @@ nsMathMLElement::BindToTree(nsIDocument*
       doc->
         EnsureOnDemandBuiltInUASheet(nsLayoutStylesheetCache::MathMLSheet());
 
       // Rebuild style data for the presshell, because style system
       // optimizations may have taken place assuming MathML was disabled.
       // (See nsRuleNode::CheckSpecifiedProperties.)
       nsCOMPtr<nsIPresShell> shell = doc->GetShell();
       if (shell) {
-        shell->GetPresContext()->PostRebuildAllStyleDataEvent(nsChangeHint(0));
+        shell->GetPresContext()->
+          PostRebuildAllStyleDataEvent(nsChangeHint(0), eRestyle_Subtree);
       }
     }
   }
 
   return rv;
 }
 
 void
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,9 +1,10 @@
 [DEFAULT]
+skip-if = (os == 'win' && contentSandbox != 'off') # contentSandbox(Bug 1042735)
 support-files =
   head.js
   constraints.js
   mediaStreamPlayback.js
   pc.js
   templates.js
   NetworkPreparationChromeScript.js
   blacksilence.js
--- a/dom/network/TCPSocketChild.cpp
+++ b/dom/network/TCPSocketChild.cpp
@@ -1,15 +1,16 @@
 /* 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 <algorithm>
 #include "TCPSocketChild.h"
 #include "mozilla/unused.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/TabChild.h"
 #include "nsIDOMTCPSocket.h"
 #include "nsJSUtils.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
@@ -22,24 +23,27 @@ namespace IPC {
 bool
 DeserializeArrayBuffer(JS::Handle<JSObject*> aObj,
                        const InfallibleTArray<uint8_t>& aBuffer,
                        JS::MutableHandle<JS::Value> aVal)
 {
   mozilla::AutoSafeJSContext cx;
   JSAutoCompartment ac(cx, aObj);
 
-  JS::Rooted<JSObject*> obj(cx, JS_NewArrayBuffer(cx, aBuffer.Length()));
+  mozilla::UniquePtr<uint8_t[], JS::FreePolicy> data(js_pod_malloc<uint8_t>(aBuffer.Length()));
+  if (!data)
+      return false;
+  memcpy(data.get(), aBuffer.Elements(), aBuffer.Length());
+
+  JSObject* obj = JS_NewArrayBufferWithContents(cx, aBuffer.Length(), data.get());
   if (!obj)
-    return false;
-  uint8_t* data = JS_GetArrayBufferData(obj);
-  if (!data)
-    return false;
-  memcpy(data, aBuffer.Elements(), aBuffer.Length());
-  aVal.set(OBJECT_TO_JSVAL(obj));
+      return false;
+  data.release();
+
+  aVal.setObject(*obj);
   return true;
 }
 
 } // namespace IPC
 
 namespace mozilla {
 namespace dom {
 
@@ -219,23 +223,26 @@ TCPSocketChild::SendSend(JS::Handle<JS::
     SendData(str, aTrackingNumber);
   } else {
     NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
     JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
     NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE);
     uint32_t buflen = JS_GetArrayBufferByteLength(obj);
     aByteOffset = std::min(buflen, aByteOffset);
     uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
-    uint8_t* data = JS_GetArrayBufferData(obj);
-    if (!data) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
     FallibleTArray<uint8_t> fallibleArr;
-    if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) {
-      return NS_ERROR_OUT_OF_MEMORY;
+    {
+        JS::AutoCheckCannotGC nogc;
+        uint8_t* data = JS_GetArrayBufferData(obj, nogc);
+        if (!data) {
+            return NS_ERROR_OUT_OF_MEMORY;
+        }
+        if (!fallibleArr.InsertElementsAt(0, data + aByteOffset, nbytes)) {
+            return NS_ERROR_OUT_OF_MEMORY;
+        }
     }
     InfallibleTArray<uint8_t> arr;
     arr.SwapElements(fallibleArr);
     SendData(arr, aTrackingNumber);
   }
   return NS_OK;
 }
 
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -280,27 +280,37 @@ TCPSocketParent::SendEvent(const nsAStri
     data = SendableData(str);
 
   } else if (aDataVal.isUndefined() || aDataVal.isNull()) {
     data = mozilla::void_t();
 
   } else if (aDataVal.isObject()) {
     JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject());
     if (JS_IsArrayBufferObject(obj)) {
-      uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
-      uint8_t* buffer = JS_GetArrayBufferData(obj);
-      if (!buffer) {
-        FireInteralError(this, __LINE__);
-        return NS_ERROR_OUT_OF_MEMORY;
+      FallibleTArray<uint8_t> fallibleArr;
+      uint32_t errLine = 0;
+      do {
+          JS::AutoCheckCannotGC nogc;
+          uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
+          uint8_t* buffer = JS_GetArrayBufferData(obj, nogc);
+          if (!buffer) {
+              errLine = __LINE__;
+              break;
+          }
+          if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) {
+              errLine = __LINE__;
+              break;
+          }
+      } while (false);
+
+      if (errLine) {
+          FireInteralError(this, errLine);
+          return NS_ERROR_OUT_OF_MEMORY;
       }
-      FallibleTArray<uint8_t> fallibleArr;
-      if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) {
-        FireInteralError(this, __LINE__);
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
+
       InfallibleTArray<uint8_t> arr;
       arr.SwapElements(fallibleArr);
       data = SendableData(arr);
 
     } else {
       nsAutoJSString name;
 
       JS::Rooted<JS::Value> val(aCx);
--- a/dom/settings/SettingsRequestManager.jsm
+++ b/dom/settings/SettingsRequestManager.jsm
@@ -738,30 +738,43 @@ let SettingsRequestManager = {
     // If index is 0, the lock we just removed was at the head of
     // the queue, so possibly queue the next lock if it's
     // consumable.
     if (index == 0) {
       this.queueConsume();
     }
   },
 
-  removeMessageManager: function(aMsgMgr){
+  removeMessageManager: function(aMsgMgr, aPrincipal) {
     if (DEBUG) debug("Removing message manager");
     this.removeObserver(aMsgMgr);
     let closedLockIDs = [];
     let lockIDs = Object.keys(this.lockInfo);
     for (let i in lockIDs) {
-      if (this.lockInfo[lockIDs[i]]._mm == aMsgMgr) {
-      	if (DEBUG) debug("Removing lock " + lockIDs[i] + " due to process close/crash");
-        closedLockIDs.push(lockIDs[i]);
+      let lock = this.lockInfo[lockIDs[i]];
+      if (lock._mm == aMsgMgr) {
+        let is_finalizing = false;
+        for (let task_index in lock.tasks) {
+          if (lock.tasks[task_index].operation === "finalize") {
+            is_finalizing = true;
+            break;
+          }
+        }
+        if (!is_finalizing) {
+          this.queueTask("finalize", {lockID: lockIDs[i]}, aPrincipal).then(
+            function() {
+              if (DEBUG) debug("Lock " + lockIDs[i] + " with dead message manager finalized");
+            },
+            function(error) {
+              if (DEBUG) debug("Lock " + lockIDs[i] + " with dead message manager NOT FINALIZED due to error: " + error);
+            }
+          );
+        }
       }
     }
-    for (let i in closedLockIDs) {
-      this.removeLock(closedLockIDs[i]);
-    }
   },
 
   receiveMessage: function(aMessage) {
     if (DEBUG) debug("receiveMessage " + aMessage.name);
 
     let msg = aMessage.data;
     let mm = aMessage.target;
 
@@ -807,17 +820,17 @@ let SettingsRequestManager = {
         }
       default:
       break;
     }
 
     switch (aMessage.name) {
       case "child-process-shutdown":
         if (DEBUG) debug("Child process shutdown received.");
-        this.removeMessageManager(mm);
+        this.removeMessageManager(mm, aMessage.principal);
         break;
       case "Settings:RegisterForMessages":
         if (!SettingsPermissions.hasSomeReadPermission(aMessage.principal)) {
           Cu.reportError("Settings message " + aMessage.name +
                          " from a content process with no 'settings-api-read' privileges.");
           aMessage.target.assertPermission("message-manager-no-read-kill");
           return;
         }
--- a/dom/system/gonk/MozMtpDatabase.cpp
+++ b/dom/system/gonk/MozMtpDatabase.cpp
@@ -692,22 +692,28 @@ MozMtpDatabase::getNumObjects(MtpStorage
   MTP_LOG("  returning %d items", count);
   return count;
 }
 
 //virtual
 MtpObjectFormatList*
 MozMtpDatabase::getSupportedPlaybackFormats()
 {
-  static const uint16_t init_data[] = {MTP_FORMAT_UNDEFINED, MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG};
+  static const uint16_t init_data[] = {MTP_FORMAT_UNDEFINED, MTP_FORMAT_ASSOCIATION,
+                                       MTP_FORMAT_TEXT, MTP_FORMAT_HTML, MTP_FORMAT_WAV,
+                                       MTP_FORMAT_MP3, MTP_FORMAT_MPEG, MTP_FORMAT_EXIF_JPEG,
+                                       MTP_FORMAT_TIFF_EP, MTP_FORMAT_BMP, MTP_FORMAT_GIF,
+                                       MTP_FORMAT_PNG, MTP_FORMAT_TIFF, MTP_FORMAT_WMA,
+                                       MTP_FORMAT_OGG, MTP_FORMAT_AAC, MTP_FORMAT_MP4_CONTAINER,
+                                       MTP_FORMAT_MP2, MTP_FORMAT_3GP_CONTAINER, MTP_FORMAT_FLAC};
 
   MtpObjectFormatList *list = new MtpObjectFormatList();
   list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data));
 
-  MTP_LOG("returning MTP_FORMAT_UNDEFINED, MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG");
+  MTP_LOG("returning Supported Playback Formats");
   return list;
 }
 
 //virtual
 MtpObjectFormatList*
 MozMtpDatabase::getSupportedCaptureFormats()
 {
   static const uint16_t init_data[] = {MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG};
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -73,18 +73,16 @@ const kSmsSentObserverTopic             
 const kSmsFailedObserverTopic            = "sms-failed";
 const kSmsDeliverySuccessObserverTopic   = "sms-delivery-success";
 const kSmsDeliveryErrorObserverTopic     = "sms-delivery-error";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
 const kSysMsgListenerReadyObserverTopic  = "system-message-listener-ready";
 const kSysClockChangeObserverTopic       = "system-clock-change";
 const kScreenStateChangedTopic           = "screen-state-changed";
 
-const kSettingsCellBroadcastDisabled = "ril.cellbroadcast.disabled";
-const kSettingsCellBroadcastSearchList = "ril.cellbroadcast.searchlist";
 const kSettingsClockAutoUpdateEnabled = "time.clock.automatic-update.enabled";
 const kSettingsClockAutoUpdateAvailable = "time.clock.automatic-update.available";
 const kSettingsTimezoneAutoUpdateEnabled = "time.timezone.automatic-update.enabled";
 const kSettingsTimezoneAutoUpdateAvailable = "time.timezone.automatic-update.available";
 
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
 
 const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
@@ -1818,42 +1816,16 @@ function RadioInterface(aClientId, aWork
   lock.get(kSettingsTimezoneAutoUpdateEnabled, this);
 
   // Set "time.clock.automatic-update.available" to false when starting up.
   this.setClockAutoUpdateAvailable(false);
 
   // Set "time.timezone.automatic-update.available" to false when starting up.
   this.setTimezoneAutoUpdateAvailable(false);
 
-  /**
-  * Read the settings of the toggle of Cellbroadcast Service:
-  *
-  * Simple Format: Boolean
-  *   true if CBS is disabled. The value is applied to all RadioInterfaces.
-  * Enhanced Format: Array of Boolean
-  *   Each element represents the toggle of CBS per RadioInterface.
-  */
-  lock.get(kSettingsCellBroadcastDisabled, this);
-
-  /**
-   * Read the Cell Broadcast Search List setting to set listening channels:
-   *
-   * Simple Format:
-   *   String of integers or integer ranges separated by comma.
-   *   For example, "1, 2, 4-6"
-   * Enhanced Format:
-   *   Array of Objects with search lists specified in gsm/cdma network.
-   *   For example, [{'gsm' : "1, 2, 4-6", 'cdma' : "1, 50, 99"},
-   *                 {'cdma' : "3, 6, 8-9"}]
-   *   This provides the possibility to
-   *   1. set gsm/cdma search list individually for CDMA+LTE device.
-   *   2. set search list per RadioInterface.
-   */
-  lock.get(kSettingsCellBroadcastSearchList, this);
-
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
   Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
   Services.obs.addObserver(this, kScreenStateChangedTopic, false);
 
   Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false);
 
   this.portAddressedSmsApps = {};
   this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
@@ -2236,46 +2208,16 @@ RadioInterface.prototype = {
     }
 
     target.sendAsyncMessage("RIL:MatchMvno", {
       clientId: this.clientId,
       data: message
     });
   },
 
-  setCellBroadcastSearchList: function(settings) {
-    let newSearchList =
-      Array.isArray(settings) ? settings[this.clientId] : settings;
-    let oldSearchList =
-      Array.isArray(this._cellBroadcastSearchList) ?
-        this._cellBroadcastSearchList[this.clientId] :
-        this._cellBroadcastSearchList;
-
-    if ((newSearchList == oldSearchList) ||
-          (newSearchList && oldSearchList &&
-            newSearchList.gsm == oldSearchList.gsm &&
-            newSearchList.cdma == oldSearchList.cdma)) {
-      return;
-    }
-
-    this.workerMessenger.send("setCellBroadcastSearchList",
-                              { searchList: newSearchList },
-                              (function callback(response) {
-      if (!response.success) {
-        let lock = gSettingsService.createLock();
-        lock.set(kSettingsCellBroadcastSearchList,
-                 this._cellBroadcastSearchList, null);
-      } else {
-        this._cellBroadcastSearchList = settings;
-      }
-
-      return false;
-    }).bind(this));
-  },
-
   setDataRegistration: function(attach) {
     let deferred = Promise.defer();
     this.workerMessenger.send("setDataRegistration",
                               {attach: attach},
                               (function(response) {
       // Always resolve to proceed with the following steps.
       deferred.resolve(response.errorMsg ? response.errorMsg : null);
     }).bind(this));
@@ -3100,35 +3042,16 @@ RadioInterface.prototype = {
 
         if (this._timezoneAutoUpdateEnabled) {
           // Apply the latest cached NITZ for timezone if it's available.
           if (this._timezoneAutoUpdateEnabled && this._lastNitzMessage) {
             this.setTimezoneByNitz(this._lastNitzMessage);
           }
         }
         break;
-      case kSettingsCellBroadcastSearchList:
-        if (DEBUG) {
-          this.debug("'" + kSettingsCellBroadcastSearchList +
-            "' is now " + JSON.stringify(aResult));
-        }
-
-        this.setCellBroadcastSearchList(aResult);
-        break;
-      case kSettingsCellBroadcastDisabled:
-        if (DEBUG) {
-          this.debug("'" + kSettingsCellBroadcastDisabled +
-            "' is now " + JSON.stringify(aResult));
-        }
-
-        let setCbsDisabled =
-          Array.isArray(aResult) ? aResult[this.clientId] : aResult;
-        this.workerMessenger.send("setCellBroadcastDisabled",
-                                  { disabled: setCbsDisabled });
-        break;
     }
   },
 
   handleError: function(aErrorMessage) {
     if (DEBUG) {
       this.debug("There was an error while reading RIL settings.");
     }
   },
--- a/dom/wifi/DOMWifiManager.js
+++ b/dom/wifi/DOMWifiManager.js
@@ -178,48 +178,16 @@ DOMWifiManager.prototype = {
   },
 
   _convertWifiCapabilities: function(aCapabilities) {
     let capabilities = aCapabilities ?
                          new MozWifiCapabilities(aCapabilities) : null;
     return capabilities;
   },
 
-  _genReadonlyPropDesc: function(value) {
-    return {
-      enumerable: true, configurable: false, writable: false, value: value
-    };
-  },
-
-  _convertWifiCertificateInfo: function(aInfo) {
-    let propList = {};
-    for (let k in aInfo) {
-      propList[k] = this._genReadonlyPropDesc(aInfo[k]);
-    }
-
-    let info = Cu.createObjectIn(this._window);
-    Object.defineProperties(info, propList);
-    Cu.makeObjectPropsNormal(info);
-
-    return info;
-  },
-
-  _convertWifiCertificateList: function(aList) {
-    let propList = {};
-    for (let k in aList) {
-      propList[k] = this._genReadonlyPropDesc(aList[k]);
-    }
-
-    let list = Cu.createObjectIn(this._window);
-    Object.defineProperties(list, propList);
-    Cu.makeObjectPropsNormal(list);
-
-    return list;
-  },
-
   _sendMessageForRequest: function(name, data, request) {
     let id = this.getRequestId(request);
     this._mm.sendAsyncMessage(name, { data: data, rid: id, mid: this._id });
   },
 
   receiveMessage: function(aMessage) {
     let msg = aMessage.json;
     if (msg.mid && msg.mid != this._id)
@@ -302,25 +270,25 @@ DOMWifiManager.prototype = {
         Services.DOMRequest.fireSuccess(request, msg.data);
         break;
 
       case "WifiManager:setStaticIpMode:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:importCert:Return:OK":
-        Services.DOMRequest.fireSuccess(request, this._convertWifiCertificateInfo(msg.data));
+        Services.DOMRequest.fireSuccess(request, Cu.cloneInto(msg.data, this._window));
         break;
 
       case "WifiManager:importCert:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:getImportedCerts:Return:OK":
-        Services.DOMRequest.fireSuccess(request, this._convertWifiCertificateList(msg.data));
+        Services.DOMRequest.fireSuccess(request, Cu.cloneInto(msg.data, this._window));
         break;
 
       case "WifiManager:getImportedCerts:Return:NO":
         Services.DOMRequest.fireError(request, msg.data);
         break;
 
       case "WifiManager:deleteCert:Return:OK":
         Services.DOMRequest.fireSuccess(request, msg.data);
--- a/dom/workers/FileReaderSync.cpp
+++ b/dom/workers/FileReaderSync.cpp
@@ -56,47 +56,45 @@ FileReaderSync::ReadAsArrayBuffer(JSCont
 {
   uint64_t blobSize;
   nsresult rv = aBlob.GetSize(&blobSize);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
-  JS::Rooted<JSObject*> jsArrayBuffer(aCx, JS_NewArrayBuffer(aCx, blobSize));
-  if (!jsArrayBuffer) {
-    // XXXkhuey we need a way to indicate to the bindings that the call failed
-    // but there's already a pending exception that we should not clobber.
-    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return;
-  }
-
-  uint32_t bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer);
-  uint8_t* arrayBuffer = JS_GetStableArrayBufferData(aCx, jsArrayBuffer);
-  if (!arrayBuffer) {
+  UniquePtr<char[], JS::FreePolicy> bufferData(js_pod_malloc<char>(blobSize));
+  if (!bufferData) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   nsCOMPtr<nsIInputStream> stream;
   rv = aBlob.GetInternalStream(getter_AddRefs(stream));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   uint32_t numRead;
-  rv = stream->Read((char*)arrayBuffer, bufferLength, &numRead);
+  rv = stream->Read(bufferData.get(), blobSize, &numRead);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
-  NS_ASSERTION(numRead == bufferLength, "failed to read data");
+  NS_ASSERTION(numRead == blobSize, "failed to read data");
 
-  aRetval.set(jsArrayBuffer);
+  JSObject* arrayBuffer = JS_NewArrayBufferWithContents(aCx, blobSize, bufferData.get());
+  if (!arrayBuffer) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+  bufferData.release();
+
+  aRetval.set(arrayBuffer);
 }
 
 void
 FileReaderSync::ReadAsBinaryString(File& aBlob,
                                    nsAString& aResult,
                                    ErrorResult& aRv)
 {
   nsCOMPtr<nsIInputStream> stream;
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -838,27 +838,38 @@ CreateJSContextForWorker(WorkerPrivate* 
 
 #ifdef JS_GC_ZEAL
   JS_SetGCZeal(workerCx, settings.gcZeal, settings.gcZealFrequency);
 #endif
 
   return workerCx;
 }
 
+static bool
+PreserveWrapper(JSContext *cx, JSObject *obj)
+{
+    MOZ_ASSERT(cx);
+    MOZ_ASSERT(obj);
+    MOZ_ASSERT(mozilla::dom::IsDOMObject(obj));
+
+    return mozilla::dom::TryPreserveWrapper(obj);
+}
+
 class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
 {
 public:
   // The heap size passed here doesn't matter, we will change it later in the
   // call to JS_SetGCParameter inside CreateJSContextForWorker.
   WorkerJSRuntime(JSRuntime* aParentRuntime, WorkerPrivate* aWorkerPrivate)
     : CycleCollectedJSRuntime(aParentRuntime,
                               WORKER_DEFAULT_RUNTIME_HEAPSIZE,
                               WORKER_DEFAULT_NURSERY_SIZE),
     mWorkerPrivate(aWorkerPrivate)
   {
+    js::SetPreserveWrapperCallback(Runtime(), PreserveWrapper);
     JS_InitDestroyPrincipalsCallback(Runtime(), DestroyWorkerPrincipals);
   }
 
   ~WorkerJSRuntime()
   {
     auto rtPrivate = static_cast<WorkerThreadRuntimePrivate*>(JS_GetRuntimePrivate(Runtime()));
     delete rtPrivate;
     JS_SetRuntimePrivate(Runtime(), nullptr);
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/943516.html
@@ -0,0 +1,10 @@
+<!--
+Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<script>
+// Using a DOM bindings object as a weak map key should not crash when attempting to
+// call the preserve wrapper callback.
+new Worker("data:text/javascript;charset=UTF-8,(new WeakMap()).set(self, 0);")
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/crashtests.list
@@ -0,0 +1,1 @@
+load 943516.html
--- a/dom/workers/test/jsm_url_worker.js
+++ b/dom/workers/test/jsm_url_worker.js
@@ -62,21 +62,22 @@ onmessage = function(event) {
   var url = null;
   try {
     url = URL.createObjectURL(blob);
     status = true;
   } catch(e) {
   }
 
   postMessage({type: 'status', status: status, msg: 'Blob URL2:' + url});
-  postMessage({type: 'url', url: url});
 
   status = false;
   try {
     URL.createObjectURL(new Object());
   } catch(e) {
     status = true;
   }
 
   postMessage({type: 'status', status: status, msg: 'Exception wanted' });
 
+  postMessage({type: 'url', url: url});
+
   postMessage({type: 'finish' });
 }
--- a/editor/libeditor/nsPlaintextEditor.cpp
+++ b/editor/libeditor/nsPlaintextEditor.cpp
@@ -1158,16 +1158,19 @@ nsPlaintextEditor::Redo(uint32_t aCount)
 
 bool
 nsPlaintextEditor::CanCutOrCopy()
 {
   nsCOMPtr<nsISelection> selection;
   if (NS_FAILED(GetSelection(getter_AddRefs(selection))))
     return false;
 
+  if (IsPasswordEditor())
+    return false;
+
   return !selection->Collapsed();
 }
 
 bool
 nsPlaintextEditor::FireClipboardEvent(int32_t aType, int32_t aSelectionType)
 {
   if (aType == NS_PASTE)
     ForceCompositionEnd();
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -133,16 +133,17 @@ skip-if = toolkit == 'android' || e10s
 [test_bug832025.html]
 [test_bug857487.html]
 [test_bug966155.html]
 skip-if = os != "win"
 [test_bug966552.html]
 skip-if = os != "win"
 [test_bug998188.html]
 [test_bug1026397.html]
+[test_bug1067255.html]
 skip-if = e10s
 [test_CF_HTML_clipboard.html]
 [test_contenteditable_focus.html]
 [test_dom_input_event_on_htmleditor.html]
 skip-if = toolkit == 'android' # bug 1054087
 [test_dom_input_event_on_texteditor.html]
 [test_keypress_untrusted_event.html]
 [test_root_element_replacement.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1067255.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<!-- 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/. -->
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1067255
+-->
+
+<head>
+  <title>Test for Bug 1067255</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+</head>
+
+<body onload="doTest();">
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1067255">Mozilla Bug 1067255</a>
+
+  <pre id="test">
+    <script type="application/javascript">
+      /** Test for Bug 1067255 **/
+      SimpleTest.waitForExplicitFinish();
+
+      function doTest() {
+        var text = $("text-field");
+        var password = $("password-field");
+
+        var editor1 = SpecialPowers.wrap(text).editor;
+        var editor2 = SpecialPowers.wrap(password).editor;
+
+        text.focus();
+        text.select();
+
+        ok(editor1.canCopy(), "can copy, text");
+        ok(editor1.canCut(), "can cut, text");
+
+        password.focus();
+        password.select();
+
+        ok(!editor2.canCopy(), "can copy, password");
+        ok(!editor2.canCut(), "can cut, password");
+
+        SimpleTest.finish();
+      }
+   </script>
+  </pre>
+
+  <input type="text" value="Gonzo says hi" id="text-field" />
+  <input type="password" value="Jan also" id="password-field" />
+</body>
+</html>
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -106,17 +106,17 @@ public:
 };
 
 MOZ_BEGIN_ENUM_CLASS(LogOptions, int)
   NoNewline = 0x01
 MOZ_END_ENUM_CLASS(LogOptions)
 
 template<typename T>
 struct Hexa {
-  Hexa(T aVal) : mVal(aVal) {}
+  explicit Hexa(T aVal) : mVal(aVal) {}
   T mVal;
 };
 template<typename T>
 Hexa<T> hexa(T val) { return Hexa<T>(val); }
 
 template<int L, typename Logger = BasicLogger>
 class Log
 {
--- a/gfx/layers/GrallocImages.cpp
+++ b/gfx/layers/GrallocImages.cpp
@@ -325,21 +325,21 @@ ConvertOmxYUVFormatToRGB565(android::sp<
     if (!ycbcrData.mYChannel) {
       ycbcrData.mYChannel     = buffer;
       ycbcrData.mYSkip        = 0;
       ycbcrData.mYStride      = aBuffer->getStride();
       ycbcrData.mYSize        = aSurface->GetSize();
       ycbcrData.mCbSkip       = 0;
       ycbcrData.mCbCrSize     = aSurface->GetSize() / 2;
       ycbcrData.mPicSize      = aSurface->GetSize();
-      ycbcrData.mCrChannel    = buffer + ycbcrData.mYStride * ycbcrData.mYSize.height;
+      ycbcrData.mCrChannel    = buffer + ycbcrData.mYStride * aBuffer->getHeight();
       ycbcrData.mCrSkip       = 0;
       // Align to 16 bytes boundary
-      ycbcrData.mCbCrStride   = ((ycbcrData.mYStride / 2) + 15) & ~0x0F;
-      ycbcrData.mCbChannel    = ycbcrData.mCrChannel + (ycbcrData.mCbCrStride * ycbcrData.mCbCrSize.height);
+      ycbcrData.mCbCrStride   = ALIGN(ycbcrData.mYStride / 2, 16);
+      ycbcrData.mCbChannel    = ycbcrData.mCrChannel + (ycbcrData.mCbCrStride * aBuffer->getHeight() / 2);
     }
     gfx::ConvertYCbCrToRGB(ycbcrData,
                            aSurface->GetFormat(),
                            aSurface->GetSize(),
                            aMappedSurface->mData,
                            aMappedSurface->mStride);
     return OK;
   }
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -507,17 +507,17 @@ TileClient::~TileClient()
 TileClient::TileClient(const TileClient& o)
 {
   mBackBuffer.Set(this, o.mBackBuffer);
   mBackBufferOnWhite = o.mBackBufferOnWhite;
   mFrontBuffer = o.mFrontBuffer;
   mFrontBufferOnWhite = o.mFrontBufferOnWhite;
   mBackLock = o.mBackLock;
   mFrontLock = o.mFrontLock;
-  mCompositableClient = nullptr;
+  mCompositableClient = o.mCompositableClient;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   mLastUpdate = o.mLastUpdate;
 #endif
   mManager = o.mManager;
   mInvalidFront = o.mInvalidFront;
   mInvalidBack = o.mInvalidBack;
 }
 
@@ -526,17 +526,17 @@ TileClient::operator=(const TileClient& 
 {
   if (this == &o) return *this;
   mBackBuffer.Set(this, o.mBackBuffer);
   mBackBufferOnWhite = o.mBackBufferOnWhite;
   mFrontBuffer = o.mFrontBuffer;
   mFrontBufferOnWhite = o.mFrontBufferOnWhite;
   mBackLock = o.mBackLock;
   mFrontLock = o.mFrontLock;
-  mCompositableClient = nullptr;
+  mCompositableClient = o.mCompositableClient;
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
   mLastUpdate = o.mLastUpdate;
 #endif
   mManager = o.mManager;
   mInvalidFront = o.mInvalidFront;
   mInvalidBack = o.mInvalidBack;
   return *this;
 }
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -689,17 +689,17 @@ ApplyAsyncTransformToScrollbarForContent
     return;
   }
 
   const FrameMetrics& metrics = aContent.Metrics();
   AsyncPanZoomController* apzc = aContent.GetApzc();
 
   Matrix4x4 asyncTransform = apzc->GetCurrentAsyncTransform();
   Matrix4x4 nontransientTransform = apzc->GetNontransientAsyncTransform();
-  Matrix4x4 transientTransform = asyncTransform * nontransientTransform.Inverse();
+  Matrix4x4 transientTransform = nontransientTransform.Inverse() * asyncTransform;
 
   // |transientTransform| represents the amount by which we have scrolled and
   // zoomed since the last paint. Because the scrollbar was sized and positioned based
   // on the painted content, we need to adjust it based on transientTransform so that
   // it reflects what the user is actually seeing now.
   // - The scroll thumb needs to be scaled in the direction of scrolling by the inverse
   //   of the transientTransform scale (representing the zoom). This is because zooming
   //   in decreases the fraction of the whole scrollable rect that is in view.
@@ -707,33 +707,47 @@ ApplyAsyncTransformToScrollbarForContent
   //   translation (representing the scroll). This is because scrolling down, which
   //   translates the layer content up, should result in moving the scroll thumb down.
   //   The amount of the translation to the scroll thumb should be such that the ratio
   //   of the translation to the size of the scroll port is the same as the ratio
   //   of the scroll amount to the size of the scrollable rect.
   Matrix4x4 scrollbarTransform;
   if (aScrollbar->GetScrollbarDirection() == Layer::VERTICAL) {
     float scale = metrics.CalculateCompositedSizeInCssPixels().height / metrics.mScrollableRect.height;
+    if (aScrollbarIsDescendant) {
+      // In cases where the scrollbar is a descendant of the content, the
+      // scrollbar gets painted at the same resolution as the content. Since the
+      // coordinate space we apply this transform in includes the resolution, we
+      // need to adjust for it as well here. Note that in another
+      // aScrollbarIsDescendant hunk below we unapply the entire async
+      // transform, which includes the nontransientasync transform and would
+      // normally account for the resolution.
+      scale *= metrics.mResolution.scale;
+    }
     scrollbarTransform.PostScale(1.f, 1.f / transientTransform._22, 1.f);
     scrollbarTransform.PostTranslate(0, -transientTransform._42 * scale, 0);
   }
   if (aScrollbar->GetScrollbarDirection() == Layer::HORIZONTAL) {
     float scale = metrics.CalculateCompositedSizeInCssPixels().width / metrics.mScrollableRect.width;
+    if (aScrollbarIsDescendant) {
+      scale *= metrics.mResolution.scale;
+    }
     scrollbarTransform.PostScale(1.f / transientTransform._11, 1.f, 1.f);
     scrollbarTransform.PostTranslate(-transientTransform._41 * scale, 0, 0);
   }
 
   Matrix4x4 transform = scrollbarTransform * aScrollbar->GetTransform();
 
   if (aScrollbarIsDescendant) {
     // If the scrollbar layer is a child of the content it is a scrollbar for, then we
-    // need to do an extra untransform to cancel out the transient async transform on
-    // the content. This is needed because otherwise that transient async transform is
-    // part of the effective transform of this scrollbar, and the scrollbar will jitter
-    // as the content scrolls.
+    // need to do an extra untransform to cancel out the async transform on
+    // the content. This is needed because layout positions and sizes the
+    // scrollbar on the assumption that there is no async transform, and without
+    // this code the scrollbar will end up in the wrong place.
+    //
     // Since the async transform is applied on top of the content's regular
     // transform, we need to make sure to unapply the async transform in the
     // same coordinate space. This requires applying the content transform and
     // then unapplying it after unapplying the async transform.
     Matrix4x4 asyncUntransform = (asyncTransform * apzc->GetOverscrollTransform()).Inverse();
     Matrix4x4 contentTransform = aContent.GetTransform();
     Matrix4x4 contentUntransform = contentTransform.Inverse();
 
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -242,17 +242,17 @@ TextureSharedDataGonkOGL::GetAndResetGLT
   mBoundEGLImage = EGL_NO_IMAGE;
   return texture;
 }
 
 void
 TextureSharedDataGonkOGL::DeleteTextureIfPresent()
 {
   if (mTexture) {
-    MOZ_ASSERT(gl());
+    MOZ_ASSERT(mCompositor);
     if (gl() && gl()->MakeCurrent()) {
       gl()->fDeleteTextures(1, &mTexture);
     }
     mTexture = 0;
     mBoundEGLImage = EGL_NO_IMAGE;
   }
 }
 
--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,11 +1,12 @@
 This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
 
 Our reference repository is https://github.com/khaledhosny/ots/.
 
-Current revision: 5c25bdac8f02080f49fa416ea997ed77e3be0d30
+Current revision: c24a839b1c66c4de09e58fabaacb82bf3bd692a4
 
 Upstream files included: LICENSE, src/, include/
 
 Additional files: README.mozilla, src/moz.build
 
 Additional patch: ots-visibility.patch (bug 711079).
+Additional patch: ots-brotli-path.patch (bug 1064737).
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -222,25 +222,31 @@ class OTS_API OTSContext {
     //     sanitisied output will be written to this. In the even of a failure,
     //     partial output may have been written.
     //   input: the OpenType file
     //   length: the size, in bytes, of |input|
     //   context: optional context that holds various OTS settings like user callbacks
     bool Process(OTSStream *output, const uint8_t *input, size_t length);
 
     // This function will be called when OTS is reporting an error.
-    virtual void Message(const char *format, ...) MSGFUNC_FMT_ATTR {}
+    //   level: the severity of the generated message:
+    //     0: error messages in case OTS fails to sanitize the font.
+    //     1: warning messages about issue OTS fixed in the sanitized font.
+    virtual void Message(int level, const char *format, ...) MSGFUNC_FMT_ATTR {}
 
     // This function will be called when OTS needs to decide what to do for a
     // font table.
     //   tag: table tag as an integer in big-endian byte order, independent of
     //   platform endianness
     virtual TableAction GetTableAction(uint32_t tag) { return ots::TABLE_ACTION_DEFAULT; }
 };
 
+// For backward compatibility - remove once Chrome switches over to the new API.
+bool Process(OTSStream *output, const uint8_t *input, size_t length);
+
 // Force to disable debug output even when the library is compiled with
 // -DOTS_DEBUG.
 void DisableDebugOutput();
 
 // Enable WOFF2 support(experimental).
 void OTS_API EnableWOFF2();
 
 }  // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/ots-brotli-path.patch
@@ -0,0 +1,22 @@
+diff --git a/gfx/ots/src/woff2.cc b/gfx/ots/src/woff2.cc
+--- a/gfx/ots/src/woff2.cc
++++ b/gfx/ots/src/woff2.cc
+@@ -6,17 +6,17 @@
+ // Condensed file format.
+ 
+ #include <cassert>
+ #include <cstdlib>
+ #include <vector>
+ 
+ #include <zlib.h>
+ 
+-#include "third_party/brotli/src/brotli/dec/decode.h"
++#include "decode.h"
+ 
+ #include "opentype-sanitiser.h"
+ #include "ots-memory-stream.h"
+ #include "ots.h"
+ #include "woff2.h"
+ 
+ namespace {
+ 
--- a/gfx/ots/ots-visibility.patch
+++ b/gfx/ots/ots-visibility.patch
@@ -32,17 +32,17 @@ diff --git a/gfx/ots/include/opentype-sa
  #if defined(_WIN32)
  #include <stdlib.h>
  typedef signed char int8_t;
  typedef unsigned char uint8_t;
  typedef short int16_t;
  typedef unsigned short uint16_t;
  typedef int int32_t;
  typedef unsigned int uint32_t;
-@@ -187,17 +187,17 @@ class OTSStream {
+@@ -187,17 +207,17 @@ class OTSStream {
  
  enum TableAction {
    TABLE_ACTION_DEFAULT,  // Use OTS's default action for that table
    TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
    TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
    TABLE_ACTION_DROP      // Drop the table
  };
  
@@ -51,8 +51,23 @@ diff --git a/gfx/ots/include/opentype-sa
    public:
      OTSContext() {}
      ~OTSContext() {}
  
      // Process a given OpenType file and write out a sanitised version
      //   output: a pointer to an object implementing the OTSStream interface. The
      //     sanitisied output will be written to this. In the even of a failure,
      //     partial output may have been written.
+@@ -222,13 +242,13 @@ class OTSContext {
+ // For backward compatibility - remove once Chrome switches over to the new API.
+ bool Process(OTSStream *output, const uint8_t *input, size_t length);
+ 
+ // Force to disable debug output even when the library is compiled with
+ // -DOTS_DEBUG.
+ void DisableDebugOutput();
+ 
+ // Enable WOFF2 support(experimental).
+-void EnableWOFF2();
++void OTS_API EnableWOFF2();
+ 
+ }  // namespace ots
+ 
+ #endif  // OPENTYPE_SANITISER_H_
--- a/gfx/ots/src/cff.cc
+++ b/gfx/ots/src/cff.cc
@@ -457,31 +457,31 @@ bool ParsePrivateDictData(
     }
     operands.clear();
   }
 
   return true;
 }
 
 bool ParseDictData(const uint8_t *data, size_t table_length,
-                   const ots::CFFIndex &index, size_t glyphs,
+                   const ots::CFFIndex &index, uint16_t glyphs,
                    size_t sid_max, DICT_DATA_TYPE type,
                    ots::OpenTypeCFF *out_cff) {
   for (unsigned i = 1; i < index.offsets.size(); ++i) {
     if (type == DICT_DATA_TOPLEVEL) {
       out_cff->char_strings_array.push_back(new ots::CFFIndex);
     }
     size_t dict_length = index.offsets[i] - index.offsets[i - 1];
     ots::Buffer table(data + index.offsets[i - 1], dict_length);
 
     std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
 
     FONT_FORMAT font_format = FORMAT_UNKNOWN;
     bool have_ros = false;
-    size_t charstring_glyphs = 0;
+    uint16_t charstring_glyphs = 0;
     size_t charset_offset = 0;
 
     while (table.offset() < dict_length) {
       if (!ParseDictDataReadNext(&table, &operands)) {
         return OTS_FAILURE();
       }
       if (operands.empty()) {
         return OTS_FAILURE();
@@ -695,17 +695,17 @@ bool ParseDictData(const uint8_t *data, 
           // parse FDSelect data structure
           ots::Buffer cff_table(data, table_length);
           cff_table.set_offset(operands.back().first);
           uint8_t format = 0;
           if (!cff_table.ReadU8(&format)) {
             return OTS_FAILURE();
           }
           if (format == 0) {
-            for (size_t j = 0; j < glyphs; ++j) {
+            for (uint16_t j = 0; j < glyphs; ++j) {
               uint8_t fd_index = 0;
               if (!cff_table.ReadU8(&fd_index)) {
                 return OTS_FAILURE();
               }
               (out_cff->fd_select)[j] = fd_index;
             }
           } else if (format == 3) {
             uint16_t n_ranges = 0;
@@ -839,17 +839,17 @@ bool ParseDictData(const uint8_t *data, 
       ots::Buffer cff_table(data, table_length);
       cff_table.set_offset(charset_offset);
       uint8_t format = 0;
       if (!cff_table.ReadU8(&format)) {
         return OTS_FAILURE();
       }
       switch (format) {
         case 0:
-          for (unsigned j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
+          for (uint16_t j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
             uint16_t sid = 0;
             if (!cff_table.ReadU16(&sid)) {
               return OTS_FAILURE();
             }
             if (!have_ros && (sid > sid_max)) {
               return OTS_FAILURE();
             }
             // TODO(yusukes): check CIDs when have_ros is true.
@@ -962,17 +962,17 @@ bool ots_cff_parse(OpenTypeFile *file, c
   CFFIndex string_index;
   if (!ParseIndex(&table, &string_index)) {
     return OTS_FAILURE();
   }
   if (string_index.count >= 65000 - kNStdString) {
     return OTS_FAILURE();
   }
 
-  const size_t num_glyphs = file->maxp->num_glyphs;
+  const uint16_t num_glyphs = file->maxp->num_glyphs;
   const size_t sid_max = string_index.count + kNStdString;
   // string_index.count == 0 is allowed.
 
   // parse "9. Top DICT Data"
   if (!ParseDictData(data, length, top_dict_index,
                      num_glyphs, sid_max,
                      DICT_DATA_TOPLEVEL, file->cff)) {
     return OTS_FAILURE();
@@ -991,17 +991,18 @@ bool ots_cff_parse(OpenTypeFile *file, c
   for (iter = file->cff->fd_select.begin(); iter != end; ++iter) {
     if (iter->second >= file->cff->font_dict_length) {
       return OTS_FAILURE();
     }
   }
 
   // Check if all charstrings (font hinting code for each glyph) are valid.
   for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
-    if (!ValidateType2CharStringIndex(*(file->cff->char_strings_array.at(i)),
+    if (!ValidateType2CharStringIndex(file,
+                                      *(file->cff->char_strings_array.at(i)),
                                       global_subrs_index,
                                       file->cff->fd_select,
                                       file->cff->local_subrs_per_font,
                                       file->cff->local_subrs,
                                       &table)) {
       return OTS_FAILURE_MSG("Failed validating charstring set %d", (int) i);
     }
   }
--- a/gfx/ots/src/cff_type2_charstring.cc
+++ b/gfx/ots/src/cff_type2_charstring.cc
@@ -9,31 +9,34 @@
 
 #include <climits>
 #include <cstdio>
 #include <cstring>
 #include <stack>
 #include <string>
 #include <utility>
 
+#define TABLE_NAME "CFF"
+
 namespace {
 
 // Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
 // Note #5177.
 const int32_t kMaxSubrsCount = 65536;
 const size_t kMaxCharStringLength = 65535;
 const size_t kMaxArgumentStack = 48;
 const size_t kMaxNumberOfStemHints = 96;
 const size_t kMaxSubrNesting = 10;
 
 // |dummy_result| should be a huge positive integer so callsubr and callgsubr
 // will fail with the dummy value.
 const int32_t dummy_result = INT_MAX;
 
-bool ExecuteType2CharString(size_t call_depth,
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
+                            size_t call_depth,
                             const ots::CFFIndex& global_subrs_index,
                             const ots::CFFIndex& local_subrs_index,
                             ots::Buffer *cff_table,
                             ots::Buffer *char_string,
                             std::stack<int32_t> *argument_stack,
                             bool *out_found_endchar,
                             bool *out_found_width,
                             size_t *in_out_num_stems);
@@ -217,17 +220,18 @@ bool ReadNextNumberFromType2CharString(o
 
   return true;
 }
 
 // Executes |op| and updates |argument_stack|. Returns true if the execution
 // succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
 // calls ExecuteType2CharString() function. The arguments other than |op| and
 // |argument_stack| are passed for that reason.
-bool ExecuteType2CharStringOperator(int32_t op,
+bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
+                                    int32_t op,
                                     size_t call_depth,
                                     const ots::CFFIndex& global_subrs_index,
                                     const ots::CFFIndex& local_subrs_index,
                                     ots::Buffer *cff_table,
                                     ots::Buffer *char_string,
                                     std::stack<int32_t> *argument_stack,
                                     bool *out_found_endchar,
                                     bool *in_out_found_width,
@@ -281,17 +285,18 @@ bool ExecuteType2CharStringOperator(int3
     }
     const size_t offset = subrs_index.offsets[subr_number];
     cff_table->set_offset(offset);
     if (!cff_table->Skip(length)) {
       return OTS_FAILURE();
     }
     ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
 
-    return ExecuteType2CharString(call_depth + 1,
+    return ExecuteType2CharString(file,
+                                  call_depth + 1,
                                   global_subrs_index,
                                   local_subrs_index,
                                   cff_table,
                                   &char_string_to_jump,
                                   argument_stack,
                                   out_found_endchar,
                                   in_out_found_width,
                                   in_out_num_stems);
@@ -703,34 +708,34 @@ bool ExecuteType2CharStringOperator(int3
     if (stack_size != 11) {
       return OTS_FAILURE();
     }
     while (!argument_stack->empty())
       argument_stack->pop();
     return true;
   }
 
-  //OTS_WARNING("Undefined operator: %d (0x%x)", op, op);
-  return OTS_FAILURE();
+  return OTS_FAILURE_MSG("Undefined operator: %d (0x%x)", op, op);
 }
 
 // Executes |char_string| and updates |argument_stack|.
 //
 // call_depth: The current call depth. Initial value is zero.
 // global_subrs_index: Global subroutines.
 // local_subrs_index: Local subroutines for the current glyph.
 // cff_table: A whole CFF table which contains all global and local subroutines.
 // char_string: A charstring we'll execute. |char_string| can be a main routine
 //              in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
 // argument_stack: The stack which an operator in |char_string| operates.
 // out_found_endchar: true is set if |char_string| contains 'endchar'.
 // in_out_found_width: true is set if |char_string| contains 'width' byte (which
 //                     is 0 or 1 byte.)
 // in_out_num_stems: total number of hstems and vstems processed so far.
-bool ExecuteType2CharString(size_t call_depth,
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
+                            size_t call_depth,
                             const ots::CFFIndex& global_subrs_index,
                             const ots::CFFIndex& local_subrs_index,
                             ots::Buffer *cff_table,
                             ots::Buffer *char_string,
                             std::stack<int32_t> *argument_stack,
                             bool *out_found_endchar,
                             bool *in_out_found_width,
                             size_t *in_out_num_stems) {
@@ -769,17 +774,18 @@ bool ExecuteType2CharString(size_t call_
       argument_stack->push(operator_or_operand);
       if (argument_stack->size() > kMaxArgumentStack) {
         return OTS_FAILURE();
       }
       continue;
     }
 
     // An operator is found. Execute it.
-    if (!ExecuteType2CharStringOperator(operator_or_operand,
+    if (!ExecuteType2CharStringOperator(file,
+                                        operator_or_operand,
                                         call_depth,
                                         global_subrs_index,
                                         local_subrs_index,
                                         cff_table,
                                         char_string,
                                         argument_stack,
                                         out_found_endchar,
                                         in_out_found_width,
@@ -834,44 +840,47 @@ bool SelectLocalSubr(const std::map<uint
   return true;
 }
 
 }  // namespace
 
 namespace ots {
 
 bool ValidateType2CharStringIndex(
+    ots::OpenTypeFile *file,
     const CFFIndex& char_strings_index,
     const CFFIndex& global_subrs_index,
     const std::map<uint16_t, uint8_t> &fd_select,
     const std::vector<CFFIndex *> &local_subrs_per_font,
     const CFFIndex *local_subrs,
     Buffer* cff_table) {
-  if (char_strings_index.offsets.size() == 0) {
+  const uint16_t num_offsets =
+      static_cast<uint16_t>(char_strings_index.offsets.size());
+  if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) {
     return OTS_FAILURE();  // no charstring.
   }
 
   // For each glyph, validate the corresponding charstring.
-  for (unsigned i = 1; i < char_strings_index.offsets.size(); ++i) {
+  for (uint16_t i = 1; i < num_offsets; ++i) {
     // Prepare a Buffer object, |char_string|, which contains the charstring
     // for the |i|-th glyph.
     const size_t length =
       char_strings_index.offsets[i] - char_strings_index.offsets[i - 1];
     if (length > kMaxCharStringLength) {
       return OTS_FAILURE();
     }
     const size_t offset = char_strings_index.offsets[i - 1];
     cff_table->set_offset(offset);
     if (!cff_table->Skip(length)) {
       return OTS_FAILURE();
     }
     Buffer char_string(cff_table->buffer() + offset, length);
 
     // Get a local subrs for the glyph.
-    const unsigned glyph_index = i - 1;  // index in the map is 0-origin.
+    const uint16_t glyph_index = i - 1;  // index in the map is 0-origin.
     const CFFIndex *local_subrs_to_use = NULL;
     if (!SelectLocalSubr(fd_select,
                          local_subrs_per_font,
                          local_subrs,
                          glyph_index,
                          &local_subrs_to_use)) {
       return OTS_FAILURE();
     }
@@ -881,22 +890,25 @@ bool ValidateType2CharStringIndex(
       local_subrs_to_use = &default_empty_subrs;
     }
 
     // Check a charstring for the |i|-th glyph.
     std::stack<int32_t> argument_stack;
     bool found_endchar = false;
     bool found_width = false;
     size_t num_stems = 0;
-    if (!ExecuteType2CharString(0 /* initial call_depth is zero */,
+    if (!ExecuteType2CharString(file,
+                                0 /* initial call_depth is zero */,
                                 global_subrs_index, *local_subrs_to_use,
                                 cff_table, &char_string, &argument_stack,
                                 &found_endchar, &found_width, &num_stems)) {
       return OTS_FAILURE();
     }
     if (!found_endchar) {
       return OTS_FAILURE();
     }
   }
   return true;
 }
 
 }  // namespace ots
+
+#undef TABLE_NAME
--- a/gfx/ots/src/cff_type2_charstring.h
+++ b/gfx/ots/src/cff_type2_charstring.h
@@ -30,16 +30,17 @@ namespace ots {
 //                      in |char_strings_index|.
 //  fd_select: A map from glyph # to font #.
 //  local_subrs_per_font: A list of Local Subrs associated with FDArrays. Can be
 //                        empty.
 //  local_subrs: A Local Subrs associated with Top DICT. Can be NULL.
 //  cff_table: A buffer which contains actual byte code of charstring, global
 //             subroutines and local subroutines.
 bool ValidateType2CharStringIndex(
+    OpenTypeFile *file,
     const CFFIndex &char_strings_index,
     const CFFIndex &global_subrs_index,
     const std::map<uint16_t, uint8_t> &fd_select,
     const std::vector<CFFIndex *> &local_subrs_per_font,
     const CFFIndex *local_subrs,
     Buffer *cff_table);
 
 // The list of Operators. See Appendix. A in Adobe Technical Note #5177.
--- a/gfx/ots/src/cmap.cc
+++ b/gfx/ots/src/cmap.cc
@@ -213,17 +213,17 @@ bool ParseFormat4(ots::OpenTypeFile *fil
                            ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
   }
 
   // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
   // each code-point defined in the table and make sure that they are all valid
   // glyphs and that we don't access anything out-of-bounds.
   for (unsigned i = 0; i < segcount; ++i) {
     for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) {
-      const uint16_t code_point = cp;
+      const uint16_t code_point = static_cast<uint16_t>(cp);
       if (ranges[i].id_range_offset == 0) {
         // this is explictly allowed to overflow in the spec
         const uint16_t glyph = code_point + ranges[i].id_delta;
         if (glyph >= num_glyphs) {
           return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
         }
       } else {
         const uint16_t range_delta = code_point - ranges[i].start_range;
@@ -861,23 +861,23 @@ bool ots_cmap_serialise(OTSStream *out, 
   const bool have_0514 = file->cmap->subtable_0_5_14.size() != 0;
   const bool have_100 = file->cmap->subtable_1_0_0.size() != 0;
   const bool have_304 = file->cmap->subtable_3_0_4_data != NULL;
   // MS Symbol and MS Unicode tables should not co-exist.
   // See the comment above in 0-0-4 parser.
   const bool have_314 = (!have_304) && file->cmap->subtable_3_1_4_data;
   const bool have_31012 = file->cmap->subtable_3_10_12.size() != 0;
   const bool have_31013 = file->cmap->subtable_3_10_13.size() != 0;
-  const unsigned num_subtables = static_cast<unsigned>(have_034) +
-                                 static_cast<unsigned>(have_0514) +
-                                 static_cast<unsigned>(have_100) +
-                                 static_cast<unsigned>(have_304) +
-                                 static_cast<unsigned>(have_314) +
-                                 static_cast<unsigned>(have_31012) +
-                                 static_cast<unsigned>(have_31013);
+  const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
+                                 static_cast<uint16_t>(have_0514) +
+                                 static_cast<uint16_t>(have_100) +
+                                 static_cast<uint16_t>(have_304) +
+                                 static_cast<uint16_t>(have_314) +
+                                 static_cast<uint16_t>(have_31012) +
+                                 static_cast<uint16_t>(have_31013);
   const off_t table_start = out->Tell();
 
   // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables
   // (e.g., old fonts for Mac). We don't support them.
   if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) {
     return OTS_FAILURE_MSG("no supported subtables were found");
   }
 
@@ -1001,18 +1001,18 @@ bool ots_cmap_serialise(OTSStream *out, 
   }
 
   const off_t offset_31013 = out->Tell();
   if (have_31013) {
     std::vector<OpenTypeCMAPSubtableRange> &groups
         = file->cmap->subtable_3_10_13;
     const unsigned num_groups = groups.size();
     if (!out->WriteU16(13) ||
-        !out->WriteU32(0) ||
-        !out->WriteU32(num_groups * 12 + 14) ||
+        !out->WriteU16(0) ||
+        !out->WriteU32(num_groups * 12 + 16) ||
         !out->WriteU32(0) ||
         !out->WriteU32(num_groups)) {
       return OTS_FAILURE();
     }
 
     for (unsigned i = 0; i < num_groups; ++i) {
       if (!out->WriteU32(groups[i].start_range) ||
           !out->WriteU32(groups[i].end_range) ||
--- a/gfx/ots/src/gasp.cc
+++ b/gfx/ots/src/gasp.cc
@@ -82,22 +82,24 @@ bool ots_gasp_parse(OpenTypeFile *file, 
 
 bool ots_gasp_should_serialise(OpenTypeFile *file) {
   return file->gasp != NULL;
 }
 
 bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeGASP *gasp = file->gasp;
 
-  if (!out->WriteU16(gasp->version) ||
-      !out->WriteU16(gasp->gasp_ranges.size())) {
+  const uint16_t num_ranges = static_cast<uint16_t>(gasp->gasp_ranges.size());
+  if (num_ranges != gasp->gasp_ranges.size() ||
+      !out->WriteU16(gasp->version) ||
+      !out->WriteU16(num_ranges)) {
     return OTS_FAILURE_MSG("failed to write gasp header");
   }
 
-  for (unsigned i = 0; i < gasp->gasp_ranges.size(); ++i) {
+  for (uint16_t i = 0; i < num_ranges; ++i) {
     if (!out->WriteU16(gasp->gasp_ranges[i].first) ||
         !out->WriteU16(gasp->gasp_ranges[i].second)) {
       return OTS_FAILURE_MSG("Failed to write gasp subtable %d", i);
     }
   }
 
   return true;
 }
--- a/gfx/ots/src/hdmx.cc
+++ b/gfx/ots/src/hdmx.cc
@@ -102,23 +102,26 @@ bool ots_hdmx_should_serialise(OpenTypeF
   if (!file->hdmx) return false;
   if (!file->glyf) return false;  // this table is not for CFF fonts.
   return true;
 }
 
 bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
   OpenTypeHDMX * const hdmx = file->hdmx;
 
-  if (!out->WriteU16(hdmx->version) ||
-      !out->WriteS16(hdmx->records.size()) ||
+  const int16_t num_recs = static_cast<int16_t>(hdmx->records.size());
+  if (hdmx->records.size() >
+          static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
+      !out->WriteU16(hdmx->version) ||
+      !out->WriteS16(num_recs) ||
       !out->WriteS32(hdmx->size_device_record)) {
     return OTS_FAILURE_MSG("Failed to write hdmx header");
   }
 
-  for (unsigned i = 0; i < hdmx->records.size(); ++i) {
+  for (int16_t i = 0; i < num_recs; ++i) {
     const OpenTypeHDMXDeviceRecord& rec = hdmx->records[i];
     if (!out->Write(&rec.pixel_size, 1) ||
         !out->Write(&rec.max_width, 1) ||
         !out->Write(&rec.widths[0], rec.widths.size())) {
       return OTS_FAILURE_MSG("Failed to write hdmx record %d", i);
     }
     if ((hdmx->pad_len > 0) &&
         !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
--- a/gfx/ots/src/kern.cc
+++ b/gfx/ots/src/kern.cc
@@ -108,18 +108,18 @@ bool ots_kern_parse(OpenTypeFile *file, 
     const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
     if (subtable.search_range != expected_search_range) {
       OTS_WARNING("bad search range");
       subtable.search_range = expected_search_range;
     }
     if (subtable.entry_selector != max_pow2) {
       return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.entry_selector);
     }
-    const uint32_t expected_range_shift
-        = kFormat0PairSize * num_pairs - subtable.search_range;
+    const uint16_t expected_range_shift =
+        kFormat0PairSize * num_pairs - subtable.search_range;
     if (subtable.range_shift != expected_range_shift) {
       OTS_WARNING("bad range shift");
       subtable.range_shift = expected_range_shift;
     }
 
     // Read kerning pairs.
     subtable.pairs.reserve(num_pairs);
     uint32_t last_pair = 0;
@@ -156,27 +156,31 @@ bool ots_kern_parse(OpenTypeFile *file, 
 bool ots_kern_should_serialise(OpenTypeFile *file) {
   if (!file->glyf) return false;  // this table is not for CFF fonts.
   return file->kern != NULL;
 }
 
 bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeKERN *kern = file->kern;
 
-  if (!out->WriteU16(kern->version) ||
-      !out->WriteU16(kern->subtables.size())) {
+  const uint16_t num_subtables = static_cast<uint16_t>(kern->subtables.size());
+  if (num_subtables != kern->subtables.size() ||
+      !out->WriteU16(kern->version) ||
+      !out->WriteU16(num_subtables)) {
     return OTS_FAILURE_MSG("Can't write kern table header");
   }
 
-  for (unsigned i = 0; i < kern->subtables.size(); ++i) {
-    const uint16_t length = 14 + (6 * kern->subtables[i].pairs.size());
-    if (!out->WriteU16(kern->subtables[i].version) ||
-        !out->WriteU16(length) ||
+  for (uint16_t i = 0; i < num_subtables; ++i) {
+    const size_t length = 14 + (6 * kern->subtables[i].pairs.size());
+    if (length > std::numeric_limits<uint16_t>::max() ||
+        !out->WriteU16(kern->subtables[i].version) ||
+        !out->WriteU16(static_cast<uint16_t>(length)) ||
         !out->WriteU16(kern->subtables[i].coverage) ||
-        !out->WriteU16(kern->subtables[i].pairs.size()) ||
+        !out->WriteU16(
+            static_cast<uint16_t>(kern->subtables[i].pairs.size())) ||
         !out->WriteU16(kern->subtables[i].search_range) ||
         !out->WriteU16(kern->subtables[i].entry_selector) ||
         !out->WriteU16(kern->subtables[i].range_shift)) {
       return OTS_FAILURE_MSG("Failed to write kern subtable %d", i);
     }
     for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
       if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
           !out->WriteU16(kern->subtables[i].pairs[j].right) ||
--- a/gfx/ots/src/loca.cc
+++ b/gfx/ots/src/loca.cc
@@ -73,17 +73,19 @@ bool ots_loca_serialise(OTSStream *out, 
   const OpenTypeHEAD *head = file->head;
 
   if (!head) {
     return OTS_FAILURE_MSG("Missing head table in font needed by loca");
   }
 
   if (head->index_to_loc_format == 0) {
     for (unsigned i = 0; i < loca->offsets.size(); ++i) {
-      if (!out->WriteU16(loca->offsets[i] >> 1)) {
+      const uint16_t offset = static_cast<uint16_t>(loca->offsets[i] >> 1);
+      if ((offset != (loca->offsets[i] >> 1)) ||
+          !out->WriteU16(offset)) {
         return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
       }
     }
   } else {
     for (unsigned i = 0; i < loca->offsets.size(); ++i) {
       if (!out->WriteU32(loca->offsets[i])) {
         return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
       }
--- a/gfx/ots/src/ltsh.cc
+++ b/gfx/ots/src/ltsh.cc
@@ -62,21 +62,23 @@ bool ots_ltsh_parse(OpenTypeFile *file, 
 bool ots_ltsh_should_serialise(OpenTypeFile *file) {
   if (!file->glyf) return false;  // this table is not for CFF fonts.
   return file->ltsh != NULL;
 }
 
 bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
   const OpenTypeLTSH *ltsh = file->ltsh;
 
-  if (!out->WriteU16(ltsh->version) ||
-      !out->WriteU16(ltsh->ypels.size())) {
+  const uint16_t num_ypels = static_cast<uint16_t>(ltsh->ypels.size());
+  if (num_ypels != ltsh->ypels.size() ||
+      !out->WriteU16(ltsh->version) ||
+      !out->WriteU16(num_ypels)) {
     return OTS_FAILURE_MSG("Failed to write pels size");
   }
-  for (unsigned i = 0; i < ltsh->ypels.size(); ++i) {
+  for (uint16_t i = 0; i < num_ypels; ++i) {
     if (!out->Write(&(ltsh->ypels[i]), 1)) {
       return OTS_FAILURE_MSG("Failed to write pixel size for glyph %d", i);
     }
   }
 
   return true;
 }
 
--- a/gfx/ots/src/metrics.cc
+++ b/gfx/ots/src/metrics.cc
@@ -121,46 +121,52 @@ bool ParseMetricsTable(const ots::OpenTy
   metrics->entries.reserve(num_metrics);
   for (unsigned i = 0; i < num_metrics; ++i) {
     uint16_t adv = 0;
     int16_t sb = 0;
     if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) {
       return OTS_FAILURE_MSG("Failed to read metric %d", i);
     }
 
+    // This check is bogus, see https://github.com/khaledhosny/ots/issues/36
+#if 0
     // Since so many fonts don't have proper value on |adv| and |sb|,
     // we should not call ots_failure() here. For example, about 20% of fonts
     // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests.
     if (adv > header->adv_width_max) {
       OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max);
       adv = header->adv_width_max;
     }
 
     if (sb < header->min_sb1) {
       OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1);
       sb = header->min_sb1;
     }
+#endif
 
     metrics->entries.push_back(std::make_pair(adv, sb));
   }
 
   metrics->sbs.reserve(num_sbs);
   for (unsigned i = 0; i < num_sbs; ++i) {
     int16_t sb;
     if (!table->ReadS16(&sb)) {
       // Some Japanese fonts (e.g., mona.ttf) fail this test.
       return OTS_FAILURE_MSG("Failed to read side bearing %d", i + num_metrics);
     }
 
+    // This check is bogus, see https://github.com/khaledhosny/ots/issues/36
+#if 0
     if (sb < header->min_sb1) {
       // The same as above. Three fonts in http://www.fontsquirrel.com/fontface
       // (e.g., Notice2Std.otf) have weird lsb values.
       OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1);
       sb = header->min_sb1;
     }
+#endif
 
     metrics->sbs.push_back(sb);
   }
 
   return true;
 }
 
 bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
--- a/gfx/ots/src/name.cc
+++ b/gfx/ots/src/name.cc
@@ -195,17 +195,17 @@ bool ots_name_parse(OpenTypeFile* file, 
   // check existence of required name strings (synthesize if necessary)
   //  [0 - copyright - skip]
   //   1 - family
   //   2 - subfamily
   //  [3 - unique ID - skip]
   //   4 - full name
   //   5 - version
   //   6 - postscript name
-  static const unsigned kStdNameCount = 7;
+  static const uint16_t kStdNameCount = 7;
   static const char* kStdNames[kStdNameCount] = {
     NULL,
     "OTS derived font",
     "Unspecified",
     NULL,
     "OTS derived font",
     "1.000",
     "OTS-derived-font"
@@ -232,17 +232,17 @@ bool ots_name_parse(OpenTypeFile* file, 
       continue;
     }
     if (name_iter->platform_id == 3) {
       win_name[id] = true;
       continue;
     }
   }
 
-  for (unsigned i = 0; i < kStdNameCount; ++i) {
+  for (uint16_t i = 0; i < kStdNameCount; ++i) {
     if (kStdNames[i] == NULL) {
       continue;
     }
     if (!mac_name[i]) {
       NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
                      0 /* language_id */ , i /* name_id */);
       rec.text.assign(kStdNames[i]);
       name->names.push_back(rec);
@@ -266,59 +266,63 @@ bool ots_name_parse(OpenTypeFile* file, 
 
 bool ots_name_should_serialise(OpenTypeFile* file) {
   return file->name != NULL;
 }
 
 bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
   const OpenTypeNAME* name = file->name;
 
-  uint16_t name_count = name->names.size();
-  uint16_t lang_tag_count = name->lang_tags.size();
+  uint16_t name_count = static_cast<uint16_t>(name->names.size());
+  uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
   uint16_t format = 0;
   size_t string_offset = 6 + name_count * 12;
 
   if (name->lang_tags.size() > 0) {
     // lang tags require a format-1 name table
     format = 1;
     string_offset += 2 + lang_tag_count * 4;
   }
   if (string_offset > 0xffff) {
     return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
   }
   if (!out->WriteU16(format) ||
       !out->WriteU16(name_count) ||
-      !out->WriteU16(string_offset)) {
+      !out->WriteU16(static_cast<uint16_t>(string_offset))) {
     return OTS_FAILURE_MSG("Failed to write name header");
   }
 
   std::string string_data;
   for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
        name_iter != name->names.end(); name_iter++) {
     const NameRecord& rec = *name_iter;
-    if (!out->WriteU16(rec.platform_id) ||
+    if (string_data.size() + rec.text.size() >
+            std::numeric_limits<uint16_t>::max() ||
+        !out->WriteU16(rec.platform_id) ||
         !out->WriteU16(rec.encoding_id) ||
         !out->WriteU16(rec.language_id) ||
         !out->WriteU16(rec.name_id) ||
-        !out->WriteU16(rec.text.size()) ||
-        !out->WriteU16(string_data.size()) ) {
+        !out->WriteU16(static_cast<uint16_t>(rec.text.size())) ||
+        !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) {
       return OTS_FAILURE_MSG("Faile to write name entry");
     }
     string_data.append(rec.text);
   }
 
   if (format == 1) {
     if (!out->WriteU16(lang_tag_count)) {
       return OTS_FAILURE_MSG("Faile to write language tag count");
     }
     for (std::vector<std::string>::const_iterator tag_iter =
              name->lang_tags.begin();
          tag_iter != name->lang_tags.end(); tag_iter++) {
-      if (!out->WriteU16(tag_iter->size()) ||
-          !out->WriteU16(string_data.size())) {
+      if (string_data.size() + tag_iter->size() >
+              std::numeric_limits<uint16_t>::max() ||
+          !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
+          !out->WriteU16(static_cast<uint16_t>(string_data.size()))) {
         return OTS_FAILURE_MSG("Failed to write string");
       }
       string_data.append(*tag_iter);
     }
   }
 
   if (!out->Write(string_data.data(), string_data.size())) {
     return OTS_FAILURE_MSG("Faile to write string data");
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -206,18 +206,18 @@ bool ProcessTTF(ots::OpenTypeFile *heade
   // entry_selector is Log2(maximum power of 2 <= numTables)
   if (header->entry_selector != max_pow2) {
     return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
   }
 
   // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
   // doesn't over flow because we range checked it above. Also, we know that
   // it's > header->search_range by construction of search_range.
-  const uint32_t expected_range_shift
-      = 16 * header->num_tables - header->search_range;
+  const uint16_t expected_range_shift =
+      16 * header->num_tables - header->search_range;
   if (header->range_shift != expected_range_shift) {
     OTS_FAILURE_MSG_HDR("bad range shift");
     header->range_shift = expected_range_shift;  // the same as above.
   }
 
   // Next up is the list of tables.
   std::vector<OpenTypeTable> tables;
 
@@ -606,17 +606,17 @@ bool ProcessGeneric(ots::OpenTypeFile *h
   } else {
     if (!header->glyf || !header->loca) {
       // No TrueType glyph found.
       // Note: bitmap-only fonts are not supported.
       return OTS_FAILURE_MSG_HDR("neither PS nor TT glyphs present");
     }
   }
 
-  unsigned num_output_tables = 0;
+  uint16_t num_output_tables = 0;
   for (unsigned i = 0; ; ++i) {
     if (table_parsers[i].parse == NULL) {
       break;
     }
 
     if (table_parsers[i].should_serialise(header)) {
       num_output_tables++;
     }
@@ -625,17 +625,17 @@ bool ProcessGeneric(ots::OpenTypeFile *h
   for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
        it != table_map.end(); ++it) {
     ots::TableAction action = GetTableAction(header, it->first);
     if (action == ots::TABLE_ACTION_PASSTHRU) {
       num_output_tables++;
     }
   }
 
-  unsigned max_pow2 = 0;
+  uint16_t max_pow2 = 0;
   while (1u << (max_pow2 + 1) <= num_output_tables) {
     max_pow2++;
   }
   const uint16_t output_search_range = (1u << max_pow2) << 4;
 
   // most of the errors here are highly unlikely - they'd only occur if the
   // output stream returns a failure, e.g. lack of space to write
   output->ResetChecksum();
@@ -826,16 +826,22 @@ bool OTSContext::Process(OTSStream *outp
 
   for (unsigned i = 0; ; ++i) {
     if (table_parsers[i].parse == NULL) break;
     table_parsers[i].free(&header);
   }
   return result;
 }
 
+// For backward compatibility
+bool Process(OTSStream *output, const uint8_t *data, size_t length) {
+  static OTSContext context;
+  return context.Process(output, data, length);
+}
+
 #if !defined(_MSC_VER) && defined(OTS_DEBUG)
 bool Failure(const char *f, int l, const char *fn) {
   if (g_debug_output) {
     std::fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
     std::fflush(stderr);
   }
   return false;
 }
--- a/gfx/ots/src/ots.h
+++ b/gfx/ots/src/ots.h
@@ -29,38 +29,41 @@ namespace ots {
 bool Failure(const char *f, int l, const char *fn);
 #endif
 
 // All OTS_FAILURE_* macros ultimately evaluate to 'false', just like the original
 // message-less OTS_FAILURE(), so that the current parser will return 'false' as
 // its result (indicating a failure).
 
 #if defined(_MSC_VER) || !defined(OTS_DEBUG)
-#define OTS_MESSAGE_(otf_,...) \
-  (otf_)->context->Message(__VA_ARGS__)
+#define OTS_MESSAGE_(level,otf_,...) \
+  (otf_)->context->Message(level,__VA_ARGS__)
 #else
-#define OTS_MESSAGE_(otf_,...) \
+#define OTS_MESSAGE_(level,otf_,...) \
   OTS_FAILURE(), \
-  (otf_)->context->Message(__VA_ARGS__)
+  (otf_)->context->Message(level,__VA_ARGS__)
 #endif
 
 // Generate a simple message
 #define OTS_FAILURE_MSG_(otf_,...) \
-  (OTS_MESSAGE_(otf_,__VA_ARGS__), false)
+  (OTS_MESSAGE_(0,otf_,__VA_ARGS__), false)
+
+#define OTS_WARNING_MSG_(otf_,...) \
+  OTS_MESSAGE_(1,otf_,__VA_ARGS__)
 
 // Generate a message with an associated table tag
 #define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
-  (OTS_MESSAGE_(otf_,"%4.4s: %s", tag_, msg_), false)
+  (OTS_MESSAGE_(0,otf_,"%4.4s: %s", tag_, msg_), false)
 
-// Convenience macro for use in files that only handle a single table tag,
+// Convenience macros for use in files that only handle a single table tag,
 // defined as TABLE_NAME at the top of the file; the 'file' variable is
 // expected to be the current OpenTypeFile pointer.
 #define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
 
-#define OTS_WARNING OTS_FAILURE_MSG
+#define OTS_WARNING(...) OTS_WARNING_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
 
 // -----------------------------------------------------------------------------
 // Buffer helper class
 //
 // This class perform some trival buffer operations while checking for
 // out-of-bounds errors. As a family they return false if anything is amiss,
 // updating the current offset otherwise.
 // -----------------------------------------------------------------------------
--- a/gfx/ots/src/post.cc
+++ b/gfx/ots/src/post.cc
@@ -143,31 +143,35 @@ bool ots_post_serialise(OTSStream *out, 
       !out->WriteU32(0)) {
     return OTS_FAILURE_MSG("Failed to write post header");
   }
 
   if (post->version != 0x00020000) {
     return true;  // v1.0 and v3.0 does not have glyph names.
   }
 
-  if (!out->WriteU16(post->glyph_name_index.size())) {
+  const uint16_t num_indexes =
+      static_cast<uint16_t>(post->glyph_name_index.size());
+  if (num_indexes != post->glyph_name_index.size() ||
+      !out->WriteU16(num_indexes)) {
     return OTS_FAILURE_MSG("Failed to write number of indices");
   }
 
-  for (unsigned i = 0; i < post->glyph_name_index.size(); ++i) {
+  for (uint16_t i = 0; i < num_indexes; ++i) {
     if (!out->WriteU16(post->glyph_name_index[i])) {
       return OTS_FAILURE_MSG("Failed to write name index %d", i);
     }
   }
 
   // Now we just have to write out the strings in the correct order
   for (unsigned i = 0; i < post->names.size(); ++i) {
     const std::string& s = post->names[i];
-    const uint8_t string_length = s.size();
-    if (!out->Write(&string_length, 1)) {
+    const uint8_t string_length = static_cast<uint8_t>(s.size());
+    if (string_length != s.size() ||
+        !out->Write(&string_length, 1)) {
       return OTS_FAILURE_MSG("Failed to write string %d", i);
     }
     // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
     // We allow them.
     if (string_length > 0 && !out->Write(s.data(), string_length)) {
       return OTS_FAILURE_MSG("Failed to write string length for string %d", i);
     }
   }
--- a/gfx/ots/src/vorg.cc
+++ b/gfx/ots/src/vorg.cc
@@ -70,25 +70,27 @@ bool ots_vorg_parse(OpenTypeFile *file, 
 
 bool ots_vorg_should_serialise(OpenTypeFile *file) {
   if (!file->cff) return false;  // this table is not for fonts with TT glyphs.
   return file->vorg != NULL;
 }
 
 bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
   OpenTypeVORG * const vorg = file->vorg;
-
-  if (!out->WriteU16(vorg->major_version) ||
+  
+  const uint16_t num_metrics = static_cast<uint16_t>(vorg->metrics.size());
+  if (num_metrics != vorg->metrics.size() ||
+      !out->WriteU16(vorg->major_version) ||
       !out->WriteU16(vorg->minor_version) ||
       !out->WriteS16(vorg->default_vert_origin_y) ||
-      !out->WriteU16(vorg->metrics.size())) {
+      !out->WriteU16(num_metrics)) {
     return OTS_FAILURE_MSG("Failed to write table header");
   }
 
-  for (unsigned i = 0; i < vorg->metrics.size(); ++i) {
+  for (uint16_t i = 0; i < num_metrics; ++i) {
     const OpenTypeVORGMetrics& rec = vorg->metrics[i];
     if (!out->WriteU16(rec.glyph_index) ||
         !out->WriteS16(rec.vert_origin_y)) {
       return OTS_FAILURE_MSG("Failed to write record %d", i);
     }
   }
 
   return true;
--- a/gfx/ots/src/woff2.cc
+++ b/gfx/ots/src/woff2.cc
@@ -16,22 +16,22 @@
 #include "opentype-sanitiser.h"
 #include "ots-memory-stream.h"
 #include "ots.h"
 #include "woff2.h"
 
 namespace {
 
 // simple glyph flags
-const int kGlyfOnCurve = 1 << 0;
-const int kGlyfXShort = 1 << 1;
-const int kGlyfYShort = 1 << 2;
-const int kGlyfRepeat = 1 << 3;
-const int kGlyfThisXIsSame = 1 << 4;
-const int kGlyfThisYIsSame = 1 << 5;
+const uint8_t kGlyfOnCurve = 1 << 0;
+const uint8_t kGlyfXShort = 1 << 1;
+const uint8_t kGlyfYShort = 1 << 2;
+const uint8_t kGlyfRepeat = 1 << 3;
+const uint8_t kGlyfThisXIsSame = 1 << 4;
+const uint8_t kGlyfThisYIsSame = 1 << 5;
 
 // composite glyph flags
 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
 const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
 const int FLAG_MORE_COMPONENTS = 1 << 5;
 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
@@ -117,18 +117,18 @@ const uint32_t kKnownTags[] = {
   TAG('S', 'i', 'l', 'f'),  // 58
   TAG('G', 'l', 'a', 't'),  // 59
   TAG('G', 'l', 'o', 'c'),  // 60
   TAG('F', 'e', 'a', 't'),  // 61
   TAG('S', 'i', 'l', 'l'),  // 62
 };
 
 struct Point {
-  int x;
-  int y;
+  int16_t x;
+  int16_t y;
   bool on_curve;
 };
 
 struct Table {
   uint32_t tag;
   uint32_t flags;
   uint32_t src_offset;
   uint32_t src_length;
@@ -144,21 +144,21 @@ struct Table {
         src_offset(0),
         src_length(0),
         transform_length(0),
         dst_offset(0),
         dst_length(0) {}
 };
 
 // Based on section 6.1.1 of MicroType Express draft spec
-bool Read255UShort(ots::Buffer* buf, unsigned int* value) {
-  static const int kWordCode = 253;
-  static const int kOneMoreByteCode2 = 254;
-  static const int kOneMoreByteCode1 = 255;
-  static const int kLowestUCode = 253;
+bool Read255UShort(ots::Buffer* buf, uint16_t* value) {
+  static const uint8_t kWordCode = 253;
+  static const uint8_t kOneMoreByteCode2 = 254;
+  static const uint8_t kOneMoreByteCode1 = 255;
+  static const uint8_t kLowestUCode = 253;
   uint8_t code = 0;
   if (!buf->ReadU8(&code)) {
     return OTS_FAILURE();
   }
   if (code == kWordCode) {
     uint16_t result = 0;
     if (!buf->ReadU16(&result)) {
       return OTS_FAILURE();
@@ -206,25 +206,25 @@ bool ReadBase128(ots::Buffer* buf, uint3
   return OTS_FAILURE();
 }
 
 // Caller must ensure that buffer overrun won't happen.
 // TODO(ksakamaoto): Consider creating 'writer' version of the Buffer class
 // and use it across the code.
 size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) {
   dst[offset] = x >> 24;
-  dst[offset + 1] = x >> 16;
-  dst[offset + 2] = x >> 8;
-  dst[offset + 3] = x;
+  dst[offset + 1] = (x >> 16) & 0xff;
+  dst[offset + 2] = (x >> 8) & 0xff;
+  dst[offset + 3] = x & 0xff;
   return offset + 4;
 }
 
-size_t Store16(uint8_t* dst, size_t offset, int x) {
+size_t StoreU16(uint8_t* dst, size_t offset, uint16_t x) {
   dst[offset] = x >> 8;
-  dst[offset + 1] = x;
+  dst[offset + 1] = x & 0xff;
   return offset + 2;
 }
 
 int WithSign(int flag, int baseval) {
   assert(0 <= baseval && baseval < 65536);
   return (flag & 1) ? baseval : -baseval;
 }
 
@@ -285,43 +285,43 @@ bool TripletDecode(const uint8_t* flags_
           (in[triplet_index + 2] << 8) + in[triplet_index + 3]);
     }
     triplet_index += n_data_bytes;
     // Possible overflow but coordinate values are not security sensitive
     x += dx;
     y += dy;
     result->push_back(Point());
     Point& back = result->back();
-    back.x = x;
-    back.y = y;
+    back.x = static_cast<int16_t>(x);
+    back.y = static_cast<int16_t>(y);
     back.on_curve = on_curve;
   }
   *in_bytes_consumed = triplet_index;
   return true;
 }
 
 // This function stores just the point data. On entry, dst points to the
 // beginning of a simple glyph. Returns true on success.
 bool StorePoints(const std::vector<Point>& points,
     unsigned int n_contours, unsigned int instruction_length,
     uint8_t* dst, size_t dst_size, size_t* glyph_size) {
   // I believe that n_contours < 65536, in which case this is safe. However, a
   // comment and/or an assert would be good.
   unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
     instruction_length;
-  int last_flag = -1;
-  int repeat_count = 0;
+  uint8_t last_flag = 0xff;
+  uint8_t repeat_count = 0;
   int last_x = 0;
   int last_y = 0;
   unsigned int x_bytes = 0;
   unsigned int y_bytes = 0;
 
   for (size_t i = 0; i < points.size(); ++i) {
     const Point& point = points.at(i);
-    int flag = point.on_curve ? kGlyfOnCurve : 0;
+    uint8_t flag = point.on_curve ? kGlyfOnCurve : 0;
     int dx = point.x - last_x;
     int dy = point.y - last_y;
     if (dx == 0) {
       flag |= kGlyfThisXIsSame;
     } else if (dx > -256 && dx < 256) {
       flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0);
       x_bytes += 1;
     } else {
@@ -374,57 +374,57 @@ bool StorePoints(const std::vector<Point
   int y_offset = flag_offset + x_bytes;
   last_x = 0;
   last_y = 0;
   for (size_t i = 0; i < points.size(); ++i) {
     int dx = points.at(i).x - last_x;
     if (dx == 0) {
       // pass
     } else if (dx > -256 && dx < 256) {
-      dst[x_offset++] = std::abs(dx);
+      dst[x_offset++] = static_cast<uint8_t>(std::abs(dx));
     } else {
       // will always fit for valid input, but overflow is harmless
-      x_offset = Store16(dst, x_offset, dx);
+      x_offset = StoreU16(dst, x_offset, static_cast<uint16_t>(dx));
     }
     last_x += dx;
     int dy = points.at(i).y - last_y;
     if (dy == 0) {
       // pass
     } else if (dy > -256 && dy < 256) {
-      dst[y_offset++] = std::abs(dy);
+      dst[y_offset++] = static_cast<uint8_t>(std::abs(dy));
     } else {
-      y_offset = Store16(dst, y_offset, dy);
+      y_offset = StoreU16(dst, y_offset, static_cast<uint16_t>(dy));
     }
     last_y += dy;
   }
   *glyph_size = y_offset;
   return true;
 }
 
 // Compute the bounding box of the coordinates, and store into a glyf buffer.
 // A precondition is that there are at least 10 bytes available.
 void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) {
-  int x_min = 0;
-  int y_min = 0;
-  int x_max = 0;
-  int y_max = 0;
+  int16_t x_min = 0;
+  int16_t y_min = 0;
+  int16_t x_max = 0;
+  int16_t y_max = 0;
 
   for (size_t i = 0; i < points.size(); ++i) {
-    int x = points.at(i).x;
-    int y = points.at(i).y;
+    int16_t x = points.at(i).x;
+    int16_t y = points.at(i).y;
     if (i == 0 || x < x_min) x_min = x;
     if (i == 0 || x > x_max) x_max = x;
     if (i == 0 || y < y_min) y_min = y;
     if (i == 0 || y > y_max) y_max = y;
   }
   size_t offset = 2;
-  offset = Store16(dst, offset, x_min);
-  offset = Store16(dst, offset, y_min);
-  offset = Store16(dst, offset, x_max);
-  offset = Store16(dst, offset, y_max);
+  offset = StoreU16(dst, offset, x_min);
+  offset = StoreU16(dst, offset, y_min);
+  offset = StoreU16(dst, offset, x_max);
+  offset = StoreU16(dst, offset, y_max);
 }
 
 // Process entire bbox stream. This is done as a separate pass to allow for
 // composite bbox computations (an optional more aggressive transform).
 bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs,
     const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf,
     size_t glyf_buf_length) {
   const uint8_t* buf = bbox_stream->buffer();
@@ -481,17 +481,17 @@ bool ProcessComposite(ots::Buffer* compo
     if (!composite_stream->Skip(arg_size)) {
       return OTS_FAILURE();
     }
   }
   size_t composite_glyph_size = composite_stream->offset() - start_offset;
   if (composite_glyph_size + kCompositeGlyphBegin > dst_size) {
     return OTS_FAILURE();
   }
-  Store16(dst, 0, 0xffff);  // nContours = -1 for composite glyph
+  StoreU16(dst, 0, 0xffff);  // nContours = -1 for composite glyph
   std::memcpy(dst + kCompositeGlyphBegin,
       composite_stream->buffer() + start_offset,
       composite_glyph_size);
   *glyph_size = kCompositeGlyphBegin + composite_glyph_size;
   *have_instructions = we_have_instructions;
   return true;
 }
 
@@ -508,17 +508,17 @@ bool StoreLoca(const std::vector<uint32_
     return OTS_FAILURE();
   }
   size_t offset = 0;
   for (size_t i = 0; i < loca_values.size(); ++i) {
     uint32_t value = loca_values.at(i);
     if (index_format) {
       offset = StoreU32(dst, offset, value);
     } else {
-      offset = Store16(dst, offset, value >> 1);
+      offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1));
     }
   }
   return true;
 }
 
 // Reconstruct entire glyf table based on transformed original
 bool ReconstructGlyf(const uint8_t* data, size_t data_size,
     uint8_t* dst, size_t dst_size,
@@ -559,67 +559,67 @@ bool ReconstructGlyf(const uint8_t* data
   ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second);
   ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second);
   ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second);
   ots::Buffer instruction_stream(substreams.at(6).first,
                                  substreams.at(6).second);
 
   std::vector<uint32_t> loca_values;
   loca_values.reserve(num_glyphs + 1);
-  std::vector<unsigned int> n_points_vec;
+  std::vector<uint16_t> n_points_vec;
   std::vector<Point> points;
   uint32_t loca_offset = 0;
   for (unsigned int i = 0; i < num_glyphs; ++i) {
     size_t glyph_size = 0;
     uint16_t n_contours = 0;
     if (!n_contour_stream.ReadU16(&n_contours)) {
       return OTS_FAILURE();
     }
     uint8_t* glyf_dst = dst + loca_offset;
     size_t glyf_dst_size = dst_size - loca_offset;
     if (n_contours == 0xffff) {
       // composite glyph
       bool have_instructions = false;
-      unsigned int instruction_size = 0;
+      uint16_t instruction_size = 0;
       if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
             &glyph_size, &have_instructions)) {
         return OTS_FAILURE();
       }
       if (have_instructions) {
         if (!Read255UShort(&glyph_stream, &instruction_size)) {
           return OTS_FAILURE();
         }
         // No integer overflow here (instruction_size < 2^16).
-        if (instruction_size + 2 > glyf_dst_size - glyph_size) {
+        if (instruction_size + 2U > glyf_dst_size - glyph_size) {
           return OTS_FAILURE();
         }
-        Store16(glyf_dst, glyph_size, instruction_size);
+        StoreU16(glyf_dst, glyph_size, instruction_size);
         if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
               instruction_size)) {
           return OTS_FAILURE();
         }
         glyph_size += instruction_size + 2;
       }
     } else if (n_contours > 0) {
       // simple glyph
       n_points_vec.clear();
       points.clear();
-      unsigned int total_n_points = 0;
-      unsigned int n_points_contour;
-      for (unsigned int j = 0; j < n_contours; ++j) {
+      uint32_t total_n_points = 0;
+      uint16_t n_points_contour;
+      for (uint32_t j = 0; j < n_contours; ++j) {
         if (!Read255UShort(&n_points_stream, &n_points_contour)) {
           return OTS_FAILURE();
         }
         n_points_vec.push_back(n_points_contour);
         if (total_n_points + n_points_contour < total_n_points) {
           return OTS_FAILURE();
         }
         total_n_points += n_points_contour;
       }
-      unsigned int flag_size = total_n_points;
+      uint32_t flag_size = total_n_points;
       if (flag_size > flag_stream.length() - flag_stream.offset()) {
         return OTS_FAILURE();
       }
       const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset();
       const uint8_t* triplet_buf = glyph_stream.buffer() +
         glyph_stream.offset();
       size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
       size_t triplet_bytes_consumed = 0;
@@ -627,44 +627,44 @@ bool ReconstructGlyf(const uint8_t* data
             &points, &triplet_bytes_consumed)) {
         return OTS_FAILURE();
       }
       const uint32_t header_and_endpts_contours_size =
           kEndPtsOfContoursOffset + 2 * n_contours;
       if (glyf_dst_size < header_and_endpts_contours_size) {
         return OTS_FAILURE();
       }
-      Store16(glyf_dst, 0, n_contours);
+      StoreU16(glyf_dst, 0, n_contours);
       ComputeBbox(points, glyf_dst);
       size_t endpts_offset = kEndPtsOfContoursOffset;
       int end_point = -1;
       for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
         end_point += n_points_vec.at(contour_ix);
         if (end_point >= 65536) {
           return OTS_FAILURE();
         }
-        endpts_offset = Store16(glyf_dst, endpts_offset, end_point);
+        endpts_offset = StoreU16(glyf_dst, endpts_offset, static_cast<uint16_t>(end_point));
       }
       if (!flag_stream.Skip(flag_size)) {
         return OTS_FAILURE();
       }
       if (!glyph_stream.Skip(triplet_bytes_consumed)) {
         return OTS_FAILURE();
       }
-      unsigned int instruction_size;
+      uint16_t instruction_size;
       if (!Read255UShort(&glyph_stream, &instruction_size)) {
         return OTS_FAILURE();
       }
       // No integer overflow here (instruction_size < 2^16).
       if (glyf_dst_size - header_and_endpts_contours_size <
-          instruction_size + 2) {
+          instruction_size + 2U) {
         return OTS_FAILURE();
       }
       uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
-      Store16(instruction_dst, 0, instruction_size);
+      StoreU16(instruction_dst, 0, instruction_size);
       if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) {
         return OTS_FAILURE();
       }
       if (!StorePoints(points, n_contours, instruction_size,
             glyf_dst, glyf_dst_size, &glyph_size)) {
         return OTS_FAILURE();
       }
     } else {
@@ -910,24 +910,24 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
     return OTS_FAILURE();
   }
   uint64_t src_offset = file.offset();
   uint64_t dst_offset = kSfntHeaderSize +
       kSfntEntrySize * static_cast<uint64_t>(num_tables);
   uint64_t uncompressed_sum = 0;
   for (uint16_t i = 0; i < num_tables; ++i) {
     Table* table = &tables.at(i);
-    table->src_offset = src_offset;
+    table->src_offset = static_cast<uint32_t>(src_offset);
     table->src_length = (i == 0 ? compressed_length : 0);
     src_offset += table->src_length;
     if (src_offset > std::numeric_limits<uint32_t>::max()) {
       return OTS_FAILURE();
     }
     src_offset = ots::Round4(src_offset);
-    table->dst_offset = dst_offset;
+    table->dst_offset = static_cast<uint32_t>(dst_offset);
     dst_offset += table->dst_length;
     if (dst_offset > std::numeric_limits<uint32_t>::max()) {
       return OTS_FAILURE();
     }
     dst_offset = ots::Round4(dst_offset);
     if ((table->flags & kCompressionTypeMask) != kCompressionTypeNone) {
       uncompressed_sum += table->src_length;
       if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) {
@@ -946,25 +946,25 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
   const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
   if (sfnt_header_and_table_directory_size > result_length) {
     return OTS_FAILURE();
   }
 
   // Start building the font
   size_t offset = 0;
   offset = StoreU32(result, offset, flavor);
-  offset = Store16(result, offset, num_tables);
-  unsigned max_pow2 = 0;
+  offset = StoreU16(result, offset, num_tables);
+  uint8_t max_pow2 = 0;
   while (1u << (max_pow2 + 1) <= num_tables) {
     max_pow2++;
   }
   const uint16_t output_search_range = (1u << max_pow2) << 4;
-  offset = Store16(result, offset, output_search_range);
-  offset = Store16(result, offset, max_pow2);
-  offset = Store16(result, offset, (num_tables << 4) - output_search_range);
+  offset = StoreU16(result, offset, output_search_range);
+  offset = StoreU16(result, offset, max_pow2);
+  offset = StoreU16(result, offset, (num_tables << 4) - output_search_range);
   for (uint16_t i = 0; i < num_tables; ++i) {
     const Table* table = &tables.at(i);
     offset = StoreU32(result, offset, table->tag);
     offset = StoreU32(result, offset, 0);  // checksum, to fill in later
     offset = StoreU32(result, offset, table->dst_offset);
     offset = StoreU32(result, offset, table->dst_length);
   }
   std::vector<uint8_t> uncompressed_buf;
@@ -996,18 +996,19 @@ bool ConvertWOFF2ToTTF(uint8_t* result, 
         if (total_size > std::numeric_limits<uint32_t>::max()) {
           return OTS_FAILURE();
         }
       }
       // Enforce same 30M limit on uncompressed tables as OTS
       if (total_size > 30 * 1024 * 1024) {
         return OTS_FAILURE();
       }
-      uncompressed_buf.resize(total_size);
-      if (!Woff2Uncompress(&uncompressed_buf[0], total_size,
+      const size_t total_size_size_t = static_cast<size_t>(total_size);
+      uncompressed_buf.resize(total_size_size_t);
+      if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
           src_buf, compressed_length, compression_type)) {
         return OTS_FAILURE();
       }
       transform_buf = &uncompressed_buf[0];
       continue_valid = true;
     } else {
       return OTS_FAILURE();
     }
--- a/gfx/ots/sync.sh
+++ b/gfx/ots/sync.sh
@@ -7,22 +7,25 @@ if [ $# = 0 ] ; then
     exit 1
 fi
 
 echo "Updating LICENSE..."
 cp $1/LICENSE .
 
 echo "Updating src..."
 cd src
-ls --ignore moz.build | xargs rm -rf
+ls | fgrep -v moz.build | xargs rm -rf
 cp -r $1/src/* .
 cd ..
 
 echo "Updating include..."
 rm -rf include/
 cp -r $1/include .
 
 echo "Updating README.mozilla..."
 REVISION=`cd $1; git log | head -1 | sed "s/commit //"`
-sed "s/\(Current revision: \).*/\1$REVISION/" -i README.mozilla
+sed -e "s/\(Current revision: \).*/\1$REVISION/" -i "" README.mozilla
 
 echo "Applying ots-visibility.patch..."
 patch -p3 < ots-visibility.patch
+
+echo "Applying ots-brotli-path.patch..."
+patch -p3 < ots-brotli-path.patch
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -701,26 +701,26 @@ gfxFontUtils::MapCharToGlyphFormat12(con
     return 0;
 }
 
 namespace {
 
 struct Format14CmapWrapper
 {
     const Format14Cmap& mCmap14;
-    Format14CmapWrapper(const Format14Cmap& cmap14) : mCmap14(cmap14) {}
+    explicit Format14CmapWrapper(const Format14Cmap& cmap14) : mCmap14(cmap14) {}
     uint32_t operator[](size_t index) const {
         return mCmap14.varSelectorRecords[index].varSelector;
     }
 };
 
 struct NonDefUVSTableWrapper
 {
     const NonDefUVSTable& mTable;
-    NonDefUVSTableWrapper(const NonDefUVSTable& table) : mTable(table) {}
+    explicit NonDefUVSTableWrapper(const NonDefUVSTable& table) : mTable(table) {}
     uint32_t operator[](size_t index) const {
         return mTable.uvsMappings[index].unicodeValue;
     }
 };
 
 } // namespace
 
 uint16_t
@@ -1332,17 +1332,17 @@ const char* gfxFontUtils::gMSFontNameCha
     /* [9] reserved */                          nullptr      ,
     /*[10] ENCODING_ID_MICROSOFT_UNICODEFULL */ ""
 };
 
 struct MacCharsetMappingComparator
 {
     typedef gfxFontUtils::MacFontNameCharsetMapping MacFontNameCharsetMapping;
     const MacFontNameCharsetMapping& mSearchValue;
-    MacCharsetMappingComparator(const MacFontNameCharsetMapping& aSearchValue)
+    explicit MacCharsetMappingComparator(const MacFontNameCharsetMapping& aSearchValue)
       : mSearchValue(aSearchValue) {}
     int operator()(const MacFontNameCharsetMapping& aEntry) const {
         if (mSearchValue < aEntry) {
             return -1;
         }
         if (aEntry < mSearchValue) {
             return 1;
         }
--- a/gfx/thebes/gfxMathTable.cpp
+++ b/gfx/thebes/gfxMathTable.cpp
@@ -356,27 +356,27 @@ gfxMathTable::GetGlyphAssembly(uint32_t 
   return reinterpret_cast<const GlyphAssembly*>(start);
 }
 
 namespace {
 
 struct GlyphArrayWrapper
 {
   const GlyphID* const mGlyphArray;
-  GlyphArrayWrapper(const GlyphID* const aGlyphArray) : mGlyphArray(aGlyphArray)
+  explicit GlyphArrayWrapper(const GlyphID* const aGlyphArray) : mGlyphArray(aGlyphArray)
   {}
   uint16_t operator[](size_t index) const {
     return mGlyphArray[index];
   }
 };
 
 struct RangeRecordComparator
 {
   const uint32_t mGlyph;
-  RangeRecordComparator(uint32_t aGlyph) : mGlyph(aGlyph) {}
+  explicit RangeRecordComparator(uint32_t aGlyph) : mGlyph(aGlyph) {}
   int operator()(const RangeRecord& aRecord) const {
     if (mGlyph < static_cast<uint16_t>(aRecord.mStart)) {
       return -1;
     }
     if (mGlyph > static_cast<uint16_t>(aRecord.mEnd)) {
       return 1;
     }
     return 0;
--- a/gfx/thebes/gfxSkipChars.cpp
+++ b/gfx/thebes/gfxSkipChars.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxSkipChars.h"
 #include "mozilla/BinarySearch.h"
 
 struct SkippedRangeStartComparator
 {
     const uint32_t mOffset;
-    SkippedRangeStartComparator(const uint32_t aOffset) : mOffset(aOffset) {}
+    explicit SkippedRangeStartComparator(const uint32_t aOffset) : mOffset(aOffset) {}
     int operator()(const gfxSkipChars::SkippedRange& aRange) const {
         return (mOffset < aRange.Start()) ? -1 : 1;
     }
 };
 
 void
 gfxSkipCharsIterator::SetOriginalOffset(int32_t aOffset)
 {
@@ -64,17 +64,17 @@ gfxSkipCharsIterator::SetOriginalOffset(
     }
 
     mSkippedStringOffset = aOffset - r.NextDelta();
 }
 
 struct SkippedRangeOffsetComparator
 {
     const uint32_t mOffset;
-    SkippedRangeOffsetComparator(const uint32_t aOffset) : mOffset(aOffset) {}
+    explicit SkippedRangeOffsetComparator(const uint32_t aOffset) : mOffset(aOffset) {}
     int operator()(const gfxSkipChars::SkippedRange& aRange) const {
         return (mOffset < aRange.SkippedOffset()) ? -1 : 1;
     }
 };
 
 void
 gfxSkipCharsIterator::SetSkippedOffset(uint32_t aOffset)
 {
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -189,17 +189,18 @@ public:
             aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') ||
             aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') ||
             aTag == TRUETYPE_TAG('C', 'P', 'A', 'L')) {
             return ots::TABLE_ACTION_PASSTHRU;
         }
         return ots::TABLE_ACTION_DEFAULT;
     }
 
-    virtual void Message(const char* format, ...) MSGFUNC_FMT_ATTR MOZ_OVERRIDE {
+    virtual void Message(int level, const char* format,
+                         ...) MSGFUNC_FMT_ATTR MOZ_OVERRIDE {
         va_list va;
         va_start(va, format);
 
         // buf should be more than adequate for any message OTS generates,
         // so we don't worry about checking the result of vsnprintf()
         char buf[512];
         (void)vsnprintf(buf, sizeof(buf), format, va);
 
--- a/ipc/ril/Ril.cpp
+++ b/ipc/ril/Ril.cpp
@@ -87,51 +87,55 @@ PostToRIL(JSContext *aCx,
     if (args.length() != 2) {
         JS_ReportError(aCx, "Expecting two arguments with the RIL message");
         return false;
     }
 
     int clientId = args[0].toInt32();
     JS::Value v = args[1];
 
-    JSAutoByteString abs;
-    void *data;
-    size_t size;
+    UnixSocketRawData* raw = nullptr;
+
     if (v.isString()) {
+        JSAutoByteString abs;
         JS::Rooted<JSString*> str(aCx, v.toString());
         if (!abs.encodeUtf8(aCx, str)) {
             return false;
         }
 
-        data = abs.ptr();
-        size = abs.length();
+        raw = new UnixSocketRawData(abs.ptr(), abs.length());
     } else if (!v.isPrimitive()) {
         JSObject *obj = v.toObjectOrNull();
         if (!JS_IsTypedArrayObject(obj)) {
             JS_ReportError(aCx, "Object passed in wasn't a typed array");
             return false;
         }
 
         uint32_t type = JS_GetArrayBufferViewType(obj);
         if (type != js::Scalar::Int8 &&
             type != js::Scalar::Uint8 &&
             type != js::Scalar::Uint8Clamped) {
             JS_ReportError(aCx, "Typed array data is not octets");
             return false;
         }
 
-        size = JS_GetTypedArrayByteLength(obj);
-        data = JS_GetArrayBufferViewData(obj);
+        JS::AutoCheckCannotGC nogc;
+        size_t size = JS_GetTypedArrayByteLength(obj);
+        void *data = JS_GetArrayBufferViewData(obj, nogc);
+        raw = new UnixSocketRawData(data, size);
     } else {
         JS_ReportError(aCx,
                        "Incorrect argument. Expecting a string or a typed array");
         return false;
     }
 
-    UnixSocketRawData* raw = new UnixSocketRawData(data, size);
+    if (!raw) {
+        JS_ReportError(aCx, "Unable to post to RIL");
+        return false;
+    }
 
     nsRefPtr<SendRilSocketDataTask> task =
         new SendRilSocketDataTask(clientId, raw);
     NS_DispatchToMainThread(task);
     return true;
 }
 
 bool
@@ -184,18 +188,21 @@ DispatchRILEvent::RunTask(JSContext *aCx
 {
     JS::Rooted<JSObject*> obj(aCx, JS::CurrentGlobalOrNull(aCx));
 
     JS::Rooted<JSObject*> array(aCx,
                                 JS_NewUint8Array(aCx, mMessage->GetSize()));
     if (!array) {
         return false;
     }
-    memcpy(JS_GetArrayBufferViewData(array),
-           mMessage->GetData(), mMessage->GetSize());
+    {
+        JS::AutoCheckCannotGC nogc;
+        memcpy(JS_GetArrayBufferViewData(array, nogc),
+               mMessage->GetData(), mMessage->GetSize());
+    }
 
     JS::AutoValueArray<2> args(aCx);
     args[0].setNumber((uint32_t)mClientId);
     args[1].setObject(*array);
 
     JS::Rooted<JS::Value> rval(aCx);
     return JS_CallFunctionName(aCx, obj, "onRILMessage", args, &rval);
 }
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -13,18 +13,16 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "asmjs/AsmJSModule.h"
 
-#include <errno.h>
-
 #ifndef XP_WIN
 # include <sys/mman.h>
 #endif
 
 #include "mozilla/BinarySearch.h"
 #include "mozilla/Compression.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/TaggedAnonymousMemory.h"
@@ -52,47 +50,27 @@ using namespace jit;
 using namespace frontend;
 using mozilla::BinarySearch;
 using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::Compression::LZ4;
 using mozilla::Swap;
 
 static uint8_t *
-AllocateExecutableMemory(ExclusiveContext *cx, size_t totalBytes)
-{
-    MOZ_ASSERT(totalBytes % AsmJSPageSize == 0);
-
-#ifdef XP_WIN
-    void *p = VirtualAlloc(nullptr, totalBytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
-    if (!p) {
-        js_ReportOutOfMemory(cx);
-        return nullptr;
-    }
-#else  // assume Unix
-    void *p = MozTaggedAnonymousMmap(nullptr, totalBytes,
-                                     PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON,
-                                     -1, 0, "asm-js-code");
-    if (p == MAP_FAILED) {
-        js_ReportOutOfMemory(cx);
-        return nullptr;
-    }
-#endif
-
-    return (uint8_t *)p;
-}
-
-static void
-DeallocateExecutableMemory(uint8_t *code, size_t totalBytes)
+AllocateExecutableMemory(ExclusiveContext *cx, size_t bytes)
 {
 #ifdef XP_WIN
-    JS_ALWAYS_TRUE(VirtualFree(code, 0, MEM_RELEASE));
+    unsigned permissions = PAGE_EXECUTE_READWRITE;
 #else
-    JS_ALWAYS_TRUE(munmap(code, totalBytes) == 0 || errno == ENOMEM);
+    unsigned permissions = PROT_READ | PROT_WRITE | PROT_EXEC;
 #endif
+    void *p = AllocateExecutableMemory(nullptr, bytes, permissions, "asm-js-code", AsmJSPageSize);
+    if (!p)
+        js_ReportOutOfMemory(cx);
+    return (uint8_t *)p;
 }
 
 AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t srcStart, uint32_t srcBodyStart,
                          bool strict, bool canUseSignalHandlers)
   : srcStart_(srcStart),
     srcBodyStart_(srcBodyStart),
     scriptSource_(scriptSource),
     globalArgumentName_(nullptr),
@@ -124,17 +102,17 @@ AsmJSModule::~AsmJSModule()
             AsmJSModule::ExitDatum &exitDatum = exitIndexToGlobalDatum(i);
             if (!exitDatum.ionScript)
                 continue;
 
             jit::DependentAsmJSModuleExit exit(this, i);
             exitDatum.ionScript->removeDependentAsmJSModule(exit);
         }
 
-        DeallocateExecutableMemory(code_, pod.totalBytes_);
+        DeallocateExecutableMemory(code_, pod.totalBytes_, AsmJSPageSize);
     }
 
     for (size_t i = 0; i < numFunctionCounts(); i++)
         js_delete(functionCounts(i));
 }
 
 void
 AsmJSModule::trace(JSTracer *trc)
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -2456,33 +2456,44 @@ ImplicitConvert(JSContext* cx,
         (*char16Buffer)[sourceLength] = 0;
         break;
       }
       default:
         return TypeError(cx, "string pointer", val);
       }
       break;
     } else if (val.isObject() && JS_IsArrayBufferObject(valObj)) {
-      // Convert ArrayBuffer to pointer without any copy.
-      // Just as with C arrays, we make no effort to
-      // keep the ArrayBuffer alive.
-      void* p = JS_GetStableArrayBufferData(cx, valObj);
-      if (!p)
-          return false;
-      *static_cast<void**>(buffer) = p;
+      // Convert ArrayBuffer to pointer without any copy. Just as with C
+      // arrays, we make no effort to keep the ArrayBuffer alive. This
+      // functionality will be removed for all but arguments in bug 1080262.
+      void* ptr;
+      {
+          JS::AutoCheckCannotGC nogc;
+          ptr = JS_GetArrayBufferData(valObj, nogc);
+      }
+      if (!ptr) {
+        return TypeError(cx, "arraybuffer pointer", val);
+      }
+      *static_cast<void**>(buffer) = ptr;
       break;
     } if (val.isObject() && JS_IsTypedArrayObject(valObj)) {
+      // Same as ArrayBuffer, above, though note that this will take the offset
+      // of the view into account.
       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
         return TypeError(cx, "typed array with the appropriate type", val);
       }
-
-      // Convert TypedArray to pointer without any copy.
-      // Just as with C arrays, we make no effort to
-      // keep the TypedArray alive.
-      *static_cast<void**>(buffer) = JS_GetArrayBufferViewData(valObj);
+      void* ptr;
+      {
+          JS::AutoCheckCannotGC nogc;
+          ptr = JS_GetArrayBufferViewData(valObj, nogc);
+      }
+      if (!ptr) {
+        return TypeError(cx, "typed array pointer", val);
+      }
+      *static_cast<void**>(buffer) = ptr;
       break;
     }
     return TypeError(cx, "pointer", val);
   }
   case TYPE_array: {
     RootedObject baseType(cx, ArrayType::GetBaseType(targetType));
     size_t targetLength = ArrayType::GetLength(targetType);
 
@@ -2578,33 +2589,35 @@ ImplicitConvert(JSContext* cx,
       // copy the array.
       uint32_t sourceLength = JS_GetArrayBufferByteLength(valObj);
       size_t elementSize = CType::GetSize(baseType);
       size_t arraySize = elementSize * targetLength;
       if (arraySize != size_t(sourceLength)) {
         JS_ReportError(cx, "ArrayType length does not match source ArrayBuffer length");
         return false;
       }
-      memcpy(buffer, JS_GetArrayBufferData(valObj), sourceLength);
+      JS::AutoCheckCannotGC nogc;
+      memcpy(buffer, JS_GetArrayBufferData(valObj, nogc), sourceLength);
       break;
     } else if (val.isObject() && JS_IsTypedArrayObject(valObj)) {
       // Check that array is consistent with type, then
       // copy the array.
       if(!CanConvertTypedArrayItemTo(baseType, valObj, cx)) {
         return TypeError(cx, "typed array with the appropriate type", val);
       }
 
       uint32_t sourceLength = JS_GetTypedArrayByteLength(valObj);
       size_t elementSize = CType::GetSize(baseType);
       size_t arraySize = elementSize * targetLength;
       if (arraySize != size_t(sourceLength)) {
         JS_ReportError(cx, "typed array length does not match source TypedArray length");
         return false;
       }
-      memcpy(buffer, JS_GetArrayBufferViewData(valObj), sourceLength);
+      JS::AutoCheckCannotGC nogc;
+      memcpy(buffer, JS_GetArrayBufferViewData(valObj, nogc), sourceLength);
       break;
     } else {
       // Don't implicitly convert to string. Users can implicitly convert
       // with `String(x)` or `""+x`.
       return TypeError(cx, "array", val);
     }
     break;
   }
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -72,16 +72,17 @@ var ignoreCallees = {
     "js::Class.trace" : true,
     "js::Class.finalize" : true,
     "JSRuntime.destroyPrincipals" : true,
     "icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC
     "mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC.
     "mozilla::CycleCollectedJSRuntime.NoteCustomGCThingXPCOMChildren" : true, // During tracing, cannot GC.
     "PLDHashTableOps.hashKey" : true,
     "z_stream_s.zfree" : true,
+    "GrGLInterface.fCallback" : true,
 };
 
 function fieldCallCannotGC(csu, fullfield)
 {
     if (csu in ignoreClasses)
         return true;
     if (fullfield in ignoreCallees)
         return true;
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -1732,16 +1732,18 @@ bool TokenStream::getStringOrTemplateTok
                     reportError(JSMSG_UNTERMINATED_STRING);
                     return false;
                 }
                 if (c == '\r') {
                     c = '\n';
                     if (userbuf.peekRawChar() == '\n')
                         skipChars(1);
                 }
+                updateLineInfoForEOL();
+                updateFlagsForEOL();
             } else if (qc == '`' && c == '$') {
                 if ((nc = getCharIgnoreEOL()) == '{')
                     break;
                 ungetCharIgnoreEOL(nc);
             }
         }
         if (!tokenbuf.append(c))
             return false;
--- a/js/src/jit-test/tests/gc/bug-1053676.js
+++ b/js/src/jit-test/tests/gc/bug-1053676.js
@@ -1,9 +1,11 @@
 // |jit-test| ion-eager;
+if (typeof Symbol !== "function") quit(0);
+
 var x
 (function() {
     x
 }());
 verifyprebarriers();
 x = x * 0
 x = Symbol();
 gc();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1076283.js
@@ -0,0 +1,10 @@
+function f() {
+    assertEq(typeof this, "object");
+}
+this.f();
+function gg() {
+    for (var j = 0; j < 3; ++j) {
+        f();
+    }
+};
+gg();
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -924,18 +924,22 @@ function rregexp_m_literal_replace(i) {
 
     if (uceFault_regexp_m_literal_replace(i) || uceFault_regexp_m_literal_replace(i))
         assertEq(res, "abc\nabc");
     return i;
 }
 
 var uceFault_typeof = eval(uneval(uceFault).replace('uceFault', 'uceFault_typeof'))
 function rtypeof(i) {
-    var inputs = [ {}, [], 1, true, Symbol(), undefined, function(){}, null ];
-    var types = [ "object", "object", "number", "boolean", "symbol", "undefined", "function", "object"];
+    var inputs = [ {}, [], 1, true, undefined, function(){}, null ];
+    var types = [ "object", "object", "number", "boolean", "undefined", "function", "object"];
+    if (typeof Symbol === "function") {
+      inputs.push(Symbol());
+      types.push("symbol");
+    }
     var x = typeof (inputs[i % inputs.length]);
     var y = types[i % types.length];
 
     if (uceFault_typeof(i) || uceFault_typeof(i)) {
         assertEq(x, y);
     }
 
     return i;
--- a/js/src/jit/AliasAnalysis.cpp
+++ b/js/src/jit/AliasAnalysis.cpp
@@ -22,36 +22,36 @@ using mozilla::Array;
 namespace js {
 namespace jit {
 
 class LoopAliasInfo : public TempObject
 {
   private:
     LoopAliasInfo *outer_;
     MBasicBlock *loopHeader_;
-    MDefinitionVector invariantLoads_;
+    MInstructionVector invariantLoads_;
 
   public:
     LoopAliasInfo(TempAllocator &alloc, LoopAliasInfo *outer, MBasicBlock *loopHeader)
       : outer_(outer), loopHeader_(loopHeader), invariantLoads_(alloc)
     { }
 
     MBasicBlock *loopHeader() const {
         return loopHeader_;
     }
     LoopAliasInfo *outer() const {
         return outer_;
     }
-    bool addInvariantLoad(MDefinition *ins) {
+    bool addInvariantLoad(MInstruction *ins) {
         return invariantLoads_.append(ins);
     }
-    const MDefinitionVector& invariantLoads() const {
+    const MInstructionVector& invariantLoads() const {
         return invariantLoads_;
     }
-    MDefinition *firstInstruction() const {
+    MInstruction *firstInstruction() const {
         return *loopHeader_->begin();
     }
 };
 
 } // namespace jit
 } // namespace js
 
 namespace {
@@ -118,30 +118,30 @@ BlockMightReach(MBasicBlock *src, MBasic
           default:
             return true;
         }
     }
     return false;
 }
 
 static void
-IonSpewDependency(MDefinition *load, MDefinition *store, const char *verb, const char *reason)
+IonSpewDependency(MInstruction *load, MInstruction *store, const char *verb, const char *reason)
 {
     if (!JitSpewEnabled(JitSpew_Alias))
         return;
 
     fprintf(JitSpewFile, "Load ");
     load->printName(JitSpewFile);
     fprintf(JitSpewFile, " %s on store ", verb);
     store->printName(JitSpewFile);
     fprintf(JitSpewFile, " (%s)\n", reason);
 }
 
 static void
-IonSpewAliasInfo(const char *pre, MDefinition *ins, const char *post)
+IonSpewAliasInfo(const char *pre, MInstruction *ins, const char *post)
 {
     if (!JitSpewEnabled(JitSpew_Alias))
         return;
 
     fprintf(JitSpewFile, "%s ", pre);
     ins->printName(JitSpewFile);
     fprintf(JitSpewFile, " %s\n", post);
 }
@@ -158,22 +158,22 @@ IonSpewAliasInfo(const char *pre, MDefin
 // having an implicit dependency on the last instruction of the loop header, so that
 // it's never moved before the loop header.
 //
 // The algorithm depends on the invariant that both control instructions and effectful
 // instructions (stores) are never hoisted.
 bool
 AliasAnalysis::analyze()
 {
-    Vector<MDefinitionVector, AliasSet::NumCategories, IonAllocPolicy> stores(alloc());
+    Vector<MInstructionVector, AliasSet::NumCategories, IonAllocPolicy> stores(alloc());
 
     // Initialize to the first instruction.
-    MDefinition *firstIns = *graph_.entryBlock()->begin();
+    MInstruction *firstIns = *graph_.entryBlock()->begin();
     for (unsigned i = 0; i < AliasSet::NumCategories; i++) {
-        MDefinitionVector defs(alloc());
+        MInstructionVector defs(alloc());
         if (!defs.append(firstIns))
             return false;
         if (!stores.append(Move(defs)))
             return false;
     }
 
     // Type analysis may have inserted new instructions. Since this pass depends
     // on the instruction number ordering, all instructions are renumbered.
@@ -183,17 +183,23 @@ AliasAnalysis::analyze()
         if (mir->shouldCancel("Alias Analysis (main loop)"))
             return false;
 
         if (block->isLoopHeader()) {
             JitSpew(JitSpew_Alias, "Processing loop header %d", block->id());
             loop_ = new(alloc()) LoopAliasInfo(alloc(), loop_, *block);
         }
 
-        for (MDefinitionIterator def(*block); def; def++) {
+        for (MPhiIterator def(block->phisBegin()), end(block->phisEnd()); def != end; ++def)
+            def->setId(newId++);
+
+        for (MInstructionIterator def(block->begin()), end(block->begin(block->lastIns()));
+             def != end;
+             ++def)
+        {
             def->setId(newId++);
 
             AliasSet set = def->getAliasSet();
             if (set.isNone())
                 continue;
 
             if (set.isStore()) {
                 for (AliasSetIterator iter(set); iter; iter++) {
@@ -203,22 +209,22 @@ AliasAnalysis::analyze()
 
                 if (JitSpewEnabled(JitSpew_Alias)) {
                     fprintf(JitSpewFile, "Processing store ");
                     def->printName(JitSpewFile);
                     fprintf(JitSpewFile, " (flags %x)\n", set.flags());
                 }
             } else {
                 // Find the most recent store on which this instruction depends.
-                MDefinition *lastStore = firstIns;
+                MInstruction *lastStore = firstIns;
 
                 for (AliasSetIterator iter(set); iter; iter++) {
-                    MDefinitionVector &aliasedStores = stores[*iter];
+                    MInstructionVector &aliasedStores = stores[*iter];
                     for (int i = aliasedStores.length() - 1; i >= 0; i--) {
-                        MDefinition *store = aliasedStores[i];
+                        MInstruction *store = aliasedStores[i];
                         if (def->mightAlias(store) && BlockMightReach(store->block(), *block)) {
                             if (lastStore->id() < store->id())
                                 lastStore = store;
                             break;
                         }
                     }
                 }
 
@@ -240,28 +246,28 @@ AliasAnalysis::analyze()
 
         if (block->isLoopBackedge()) {
             MOZ_ASSERT(loop_->loopHeader() == block->loopHeaderOfBackedge());
             JitSpew(JitSpew_Alias, "Processing loop backedge %d (header %d)", block->id(),
                     loop_->loopHeader()->id());
             LoopAliasInfo *outerLoop = loop_->outer();
             MInstruction *firstLoopIns = *loop_->loopHeader()->begin();
 
-            const MDefinitionVector &invariant = loop_->invariantLoads();
+            const MInstructionVector &invariant = loop_->invariantLoads();
 
             for (unsigned i = 0; i < invariant.length(); i++) {
-                MDefinition *ins = invariant[i];
+                MInstruction *ins = invariant[i];
                 AliasSet set = ins->getAliasSet();
                 MOZ_ASSERT(set.isLoad());
 
                 bool hasAlias = false;
                 for (AliasSetIterator iter(set); iter; iter++) {
-                    MDefinitionVector &aliasedStores = stores[*iter];
+                    MInstructionVector &aliasedStores = stores[*iter];
                     for (int i = aliasedStores.length() - 1;; i--) {
-                        MDefinition *store = aliasedStores[i];
+                        MInstruction *store = aliasedStores[i];
                         if (store->id() < firstLoopIns->id())
                             break;
                         if (ins->mightAlias(store)) {
                             hasAlias = true;
                             IonSpewDependency(ins, store, "aliases", "store in loop body");
                             break;
                         }
                     }
--- a/js/src/jit/ExecutableAllocator.h
+++ b/js/src/jit/ExecutableAllocator.h
@@ -184,25 +184,30 @@ class ExecutableAllocator {
     DestroyCallback destroyCallback;
 
 public:
     ExecutableAllocator()
       : destroyCallback(NULL)
     {
         if (!pageSize) {
             pageSize = determinePageSize();
-            /*
-             * On Windows, VirtualAlloc effectively allocates in 64K chunks.
-             * (Technically, it allocates in page chunks, but the starting
-             * address is always a multiple of 64K, so each allocation uses up
-             * 64K of address space.)  So a size less than that would be
-             * pointless.  But it turns out that 64KB is a reasonable size for
-             * all platforms.  (This assumes 4KB pages.)
-             */
+            // On Windows, VirtualAlloc effectively allocates in 64K chunks.
+            // (Technically, it allocates in page chunks, but the starting
+            // address is always a multiple of 64K, so each allocation uses up
+            // 64K of address space.)  So a size less than that would be
+            // pointless.  But it turns out that 64KB is a reasonable size for
+            // all platforms.  (This assumes 4KB pages.) On 64-bit windows,
+            // AllocateExecutableMemory prepends an extra page for structured
+            // exception handling data (see comments in function) onto whatever
+            // is passed in, so subtract one page here.
+#if defined(JS_CPU_X64) && defined(XP_WIN)
+            largeAllocSize = pageSize * 15;
+#else
             largeAllocSize = pageSize * 16;
+#endif
         }
 
         MOZ_ASSERT(m_smallPools.empty());
     }
 
     ~ExecutableAllocator()
     {
         for (size_t i = 0; i < m_smallPools.length(); i++)
@@ -467,12 +472,19 @@ private:
     // its reference is removed from m_pools.
     typedef js::HashSet<ExecutablePool *, js::DefaultHasher<ExecutablePool *>, js::SystemAllocPolicy>
             ExecPoolHashSet;
     ExecPoolHashSet m_pools;    // All pools, just for stats purposes.
 
     static size_t determinePageSize();
 };
 
+extern void *
+AllocateExecutableMemory(void *addr, size_t bytes, unsigned permissions, const char *tag,
+                         size_t pageSize);
+
+extern void
+DeallocateExecutableMemory(void *addr, size_t bytes, size_t pageSize);
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_ExecutableAllocator_h */
--- a/js/src/jit/ExecutableAllocatorPosix.cpp
+++ b/js/src/jit/ExecutableAllocatorPosix.cpp
@@ -21,42 +21,58 @@
  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/TaggedAnonymousMemory.h"
 
+#include <errno.h>
 #include <sys/mman.h>
 #include <unistd.h>
 
 #include "jit/ExecutableAllocator.h"
 #include "js/Utility.h"
 
 using namespace js::jit;
 
 size_t ExecutableAllocator::determinePageSize()
 {
     return getpagesize();
 }
 
+void *
+js::jit::AllocateExecutableMemory(void *addr, size_t bytes, unsigned permissions, const char *tag,
+                                  size_t pageSize)
+{
+    MOZ_ASSERT(bytes % pageSize == 0);
+    void *p = MozTaggedAnonymousMmap(addr, bytes, permissions, MAP_PRIVATE | MAP_ANON, -1, 0, tag);
+    return p == MAP_FAILED ? nullptr : p;
+}
+
+void
+js::jit::DeallocateExecutableMemory(void *addr, size_t bytes, size_t pageSize)
+{
+    MOZ_ASSERT(bytes % pageSize == 0);
+    mozilla::DebugOnly<int> result = munmap(addr, bytes);
+    MOZ_ASSERT(!result || errno == ENOMEM);
+}
+
 ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n)
 {
-    void *allocation = MozTaggedAnonymousMmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, -1, 0, "js-jit-code");
-    if (allocation == MAP_FAILED)
-        allocation = NULL;
+    void *allocation = AllocateExecutableMemory(nullptr, n, INITIAL_PROTECTION_FLAGS,
+                                                "js-jit-code", pageSize);
     ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
     return alloc;
 }
 
 void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
 {
-    mozilla::DebugOnly<int> result = munmap(alloc.pages, alloc.size);
-    MOZ_ASSERT(!result);
+    DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize);
 }
 
 #if WTF_ENABLE_ASSEMBLER_WX_EXCLUSIVE
 void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting)
 {
     if (!pageSize)
         intializePageSize();
 
--- a/js/src/jit/ExecutableAllocatorWin.cpp
+++ b/js/src/jit/ExecutableAllocatorWin.cpp
@@ -20,22 +20,22 @@
  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "mozilla/WindowsVersion.h"
 
+#include "jsfriendapi.h"
 #include "jsmath.h"
+#include "jswin.h"
 
 #include "jit/ExecutableAllocator.h"
 
-#include "jswin.h"
-
 using namespace js::jit;
 
 uint64_t ExecutableAllocator::rngSeed;
 
 size_t ExecutableAllocator::determinePageSize()
 {
     SYSTEM_INFO system_info;
     GetSystemInfo(&system_info);
@@ -80,37 +80,180 @@ static bool
 RandomizeIsBroken()
 {
     // Use the compiler's intrinsic guards for |static type value = expr| to avoid some potential
     // races if runtimes are created from multiple threads.
     static int result = RandomizeIsBrokenImpl();
     return !!result;
 }
 
+#ifdef JS_CPU_X64
+static js::JitExceptionHandler sJitExceptionHandler;
+
+JS_FRIEND_API(void)
+js::SetJitExceptionHandler(JitExceptionHandler handler)
+{
+    MOZ_ASSERT(!sJitExceptionHandler);
+    sJitExceptionHandler = handler;
+}
+
+// From documentation for UNWIND_INFO on
+// http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
+struct UnwindInfo
+{
+    uint8_t version : 3;
+    uint8_t flags : 5;
+    uint8_t sizeOfPrologue;
+    uint8_t countOfUnwindCodes;
+    uint8_t frameRegister : 4;
+    uint8_t frameOffset : 4;
+    ULONG exceptionHandler;
+};
+
+static const unsigned ThunkLength = 12;
+
+struct ExceptionHandlerRecord
+{
+    RUNTIME_FUNCTION runtimeFunction;
+    UnwindInfo unwindInfo;
+    uint8_t thunk[ThunkLength];
+};
+
+// This function must match the function pointer type PEXCEPTION_HANDLER
+// mentioned in:
+//   http://msdn.microsoft.com/en-us/library/ssa62fwe.aspx.
+// This type is rather elusive in documentation; Wine is the best I've found:
+//   http://source.winehq.org/source/include/winnt.h
+static DWORD
+ExceptionHandler(PEXCEPTION_RECORD exceptionRecord, _EXCEPTION_REGISTRATION_RECORD *,
+                 PCONTEXT context, _EXCEPTION_REGISTRATION_RECORD **)
+{
+    return sJitExceptionHandler(exceptionRecord, context);
+}
+
+// For an explanation of the problem being solved here, see
+// SetJitExceptionFilter in jsfriendapi.h.
+static bool
+RegisterExecutableMemory(void *p, size_t bytes, size_t pageSize)
+{
+    ExceptionHandlerRecord *r = reinterpret_cast<ExceptionHandlerRecord*>(p);
+
+    // All these fields are specified to be offsets from the base of the
+    // executable code (which is 'p'), even if they have 'Address' in their
+    // names. In particular, exceptionHandler is a ULONG offset which is a
+    // 32-bit integer. Since 'p' can be farther than INT32_MAX away from
+    // sJitExceptionHandler, we must generate a little thunk inside the
+    // record. The record is put on its own page so that we can take away write
+    // access to protect against accidental clobbering.
+
+    r->runtimeFunction.BeginAddress = pageSize;
+    r->runtimeFunction.EndAddress = (DWORD)bytes;
+    r->runtimeFunction.UnwindData = offsetof(ExceptionHandlerRecord, unwindInfo);
+
+    r->unwindInfo.version = 1;
+    r->unwindInfo.flags = UNW_FLAG_EHANDLER;
+    r->unwindInfo.sizeOfPrologue = 0;
+    r->unwindInfo.countOfUnwindCodes = 0;
+    r->unwindInfo.frameRegister = 0;
+    r->unwindInfo.frameOffset = 0;
+    r->unwindInfo.exceptionHandler = offsetof(ExceptionHandlerRecord, thunk);
+
+    // mov imm64, rax
+    r->thunk[0]  = 0x48;
+    r->thunk[1]  = 0xb8;
+    void *handler = &ExceptionHandler;
+    memcpy(&r->thunk[2], &handler, 8);
+
+    // jmp rax
+    r->thunk[10] = 0xff;
+    r->thunk[11] = 0xe0;
+
+    DWORD oldProtect;
+    if (!VirtualProtect(p, pageSize, PAGE_EXECUTE_READ, &oldProtect))
+        return false;
+
+    return RtlAddFunctionTable(&r->runtimeFunction, 1, reinterpret_cast<DWORD64>(p));
+}
+
+static void
+UnregisterExecutableMemory(void *p, size_t bytes, size_t pageSize)
+{
+    ExceptionHandlerRecord *r = reinterpret_cast<ExceptionHandlerRecord*>(p);
+    RtlDeleteFunctionTable(&r->runtimeFunction);
+}
+#endif
+
+void *
+js::jit::AllocateExecutableMemory(void *addr, size_t bytes, unsigned permissions, const char *tag,
+                                  size_t pageSize)
+{
+    MOZ_ASSERT(bytes % pageSize == 0);
+    MOZ_ASSERT(permissions == PAGE_EXECUTE_READWRITE);
+
+#ifdef JS_CPU_X64
+    if (sJitExceptionHandler)
+        bytes += pageSize;
+#endif
+
+    void *p = VirtualAlloc(addr, bytes, MEM_COMMIT | MEM_RESERVE, permissions);
+    if (!p)
+        return nullptr;
+
+#ifdef JS_CPU_X64
+    if (sJitExceptionHandler) {
+        if (!RegisterExecutableMemory(p, bytes, pageSize)) {
+            VirtualFree(p, 0, MEM_RELEASE);
+            return nullptr;
+        }
+
+        p = (uint8_t*)p + pageSize;
+    }
+#endif
+
+    return p;
+}
+
+void
+js::jit::DeallocateExecutableMemory(void *addr, size_t bytes, size_t pageSize)
+{
+    MOZ_ASSERT(bytes % pageSize == 0);
+
+#ifdef JS_CPU_X64
+    if (sJitExceptionHandler) {
+        addr = (uint8_t*)addr - pageSize;
+        UnregisterExecutableMemory(addr, bytes, pageSize);
+    }
+#endif
+
+    VirtualFree(addr, 0, MEM_RELEASE);
+}
+
 ExecutablePool::Allocation ExecutableAllocator::systemAlloc(size_t n)
 {
     void *allocation = NULL;
     // Randomization disabled to avoid a performance fault on x64 builds.
     // See bug 728623.
 #ifndef JS_CPU_X64
     if (!RandomizeIsBroken()) {
         void *randomAddress = computeRandomAllocationAddress();
-        allocation = VirtualAlloc(randomAddress, n, MEM_COMMIT | MEM_RESERVE,
-                                  PAGE_EXECUTE_READWRITE);
+        allocation = AllocateExecutableMemory(randomAddress, n, PAGE_EXECUTE_READWRITE,
+                                              "js-jit-code", pageSize);
     }
 #endif
-    if (!allocation)
-        allocation = VirtualAlloc(0, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+    if (!allocation) {
+        allocation = AllocateExecutableMemory(nullptr, n, PAGE_EXECUTE_READWRITE,
+                                              "js-jit-code", pageSize);
+    }
     ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n };
     return alloc;
 }
 
 void ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc)
 {
-    VirtualFree(alloc.pages, 0, MEM_RELEASE);
+    DeallocateExecutableMemory(alloc.pages, alloc.size, pageSize);
 }
 
 void
 ExecutablePool::toggleAllCodeAsAccessible(bool accessible)
 {
     char* begin = m_allocation.pages;
     size_t size = m_freePtr - begin;
 
--- a/js/src/jit/FixedList.h
+++ b/js/src/jit/FixedList.h
@@ -73,14 +73,21 @@ class FixedList
     T &operator[](size_t index) {
         MOZ_ASSERT(index < length_);
         return list_[index];
     }
     const T &operator [](size_t index) const {
         MOZ_ASSERT(index < length_);
         return list_[index];
     }
+
+    T *begin() {
+        return list_;
+    }
+    T *end() {
+        return list_ + length_;
+    }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_FixedList_h */
--- a/js/src/jit/InlineList.h
+++ b/js/src/jit/InlineList.h
@@ -62,32 +62,23 @@ class InlineForwardList : protected Inli
 
   public:
     iterator begin() const {
         return iterator(this);
     }
     iterator end() const {
         return iterator(nullptr);
     }
-    iterator removeAt(iterator &where) {
+    void removeAt(iterator where) {
         iterator iter(where);
         iter++;
-        iter.prev = where.prev;
 #ifdef DEBUG
         iter.modifyCount_++;
 #endif
-
-        // Once the element 'where' points at has been removed, it is no longer
-        // safe to do any operations that would touch 'iter', as the element
-        // may be added to another list, etc. This nullptr ensures that any
-        // improper uses of this function will fail quickly and loudly.
         removeAfter(where.prev, where.iter);
-        where.prev = where.iter = nullptr;
-
-        return iter;
     }
     void pushFront(Node *t) {
         insertAfter(this, t);
     }
     void pushBack(Node *t) {
         MOZ_ASSERT(t->next == nullptr);
 #ifdef DEBUG
         modifyCount_++;
@@ -215,17 +206,36 @@ class InlineListNode : public InlineForw
   public:
     InlineListNode() : InlineForwardListNode<T>(nullptr), prev(nullptr)
     { }
     InlineListNode(InlineListNode<T> *n, InlineListNode<T> *p)
       : InlineForwardListNode<T>(n),
         prev(p)
     { }
 
+    // Move constructor. Nodes may be moved without being removed from their
+    // containing lists. For example, this allows list nodes to be safely
+    // stored in a resizable Vector -- when the Vector resizes, the new storage
+    // is initialized by this move constructor. |other| is a reference to the
+    // old node which the |this| node here is replacing.
+    InlineListNode(InlineListNode<T> &&other)
+      : InlineForwardListNode<T>(other.next)
+    {
+        InlineListNode<T> *newNext = static_cast<InlineListNode<T> *>(other.next);
+        InlineListNode<T> *newPrev = other.prev;
+        prev = newPrev;
+
+        // Update the pointers in the adjacent nodes to point to this node's new
+        // location.
+        newNext->prev = this;
+        newPrev->next = this;
+    }
+
     InlineListNode(const InlineListNode<T> &) MOZ_DELETE;
+    void operator=(const InlineListNode<T> &) MOZ_DELETE;
 
   protected:
     friend class InlineList<T>;
     friend class InlineListIterator<T>;
     friend class InlineListReverseIterator<T>;
 
     InlineListNode<T> *prev;
 };
@@ -257,30 +267,16 @@ class InlineList : protected InlineListN
         return reverse_iterator(this->prev);
     }
     reverse_iterator rbegin(Node *t) const {
         return reverse_iterator(t);
     }
     reverse_iterator rend() const {
         return reverse_iterator(this);
     }
-    template <typename itertype>
-    itertype removeAt(itertype &where) {
-        itertype iter(where);
-        iter++;
-
-        // Once the element 'where' points at has been removed, it is no longer
-        // safe to do any operations that would touch 'iter', as the element
-        // may be added to another list, etc. This nullptr ensures that any
-        // improper uses of this function will fail quickly and loudly.
-        remove(where.iter);
-        where.iter = nullptr;
-
-        return iter;
-    }
     void pushFront(Node *t) {
         insertAfter(this, t);
     }
     void pushFrontUnchecked(Node *t) {
         insertAfterUnchecked(this, t);
     }
     void pushBack(Node *t) {
         insertBefore(this, t);
@@ -332,16 +328,28 @@ class InlineList : protected InlineListN
     void remove(Node *t) {
         Node *tNext = static_cast<Node *>(t->next);
         Node *tPrev = t->prev;
         tPrev->next = tNext;
         tNext->prev = tPrev;
         t->next = nullptr;
         t->prev = nullptr;
     }
+    // Remove |old| from the list and insert |now| in its place.
+    void replace(Node *old, Node *now) {
+        MOZ_ASSERT(now->next == nullptr && now->prev == nullptr);
+        Node *listNext = static_cast<Node *>(old->next);
+        Node *listPrev = old->prev;
+        listPrev->next = now;
+        listNext->prev = now;
+        now->next = listNext;
+        now->prev = listPrev;
+        old->next = nullptr;
+        old->prev = nullptr;
+    }
     void clear() {
         this->next = this->prev = this;
     }
     bool empty() const {
         return begin() == end();
     }
     void takeElements(InlineList &l) {
         MOZ_ASSERT(&l != this, "cannot takeElements from this");
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -244,18 +244,17 @@ MaybeFoldConditionBlock(MIRGraph &graph,
         return;
 
     if (trueResult != trueBranch->peek(-1) || falseResult != falseBranch->peek(-1))
         return;
 
     // OK, we found the desired pattern, now transform the graph.
 
     // Remove the phi and its inputs from testBlock.
-    MPhiIterator phis = testBlock->phisBegin();
-    testBlock->discardPhiAt(phis);
+    testBlock->discardPhi(*testBlock->phisBegin());
     trueBranch->pop();
     falseBranch->pop();
 
     // If either trueBranch or falseBranch just computes a constant for the
     // test, determine the block that branch will end up jumping to and eliminate
     // the branch. Otherwise, change the end of the block to a test that jumps
     // directly to successors of testBlock, rather than to testBlock itself.
 
@@ -358,18 +357,17 @@ MaybeFoldAndOrBlock(MIRGraph &graph, MBa
         return;
 
     if (branchResult != branchBlock->peek(-1) || initialResult != initialBlock->peek(-1))
         return;
 
     // OK, we found the desired pattern, now transform the graph.
 
     // Remove the phi and its inputs from testBlock.
-    MPhiIterator phis = testBlock->phisBegin();
-    testBlock->discardPhiAt(phis);
+    testBlock->discardPhi(*testBlock->phisBegin());
     branchBlock->pop();
     initialBlock->pop();
 
     // Change the end of the initial and branch blocks to a test that jumps
     // directly to successors of testBlock, rather than to testBlock itself.
 
     UpdateTestSuccessors(graph.alloc(), initialBlock, initialResult,
                          branchIsTrue ? branchBlock : finalTest->ifTrue(),
@@ -546,29 +544,27 @@ jit::EliminateDeadCode(MIRGenerator *mir
 {
     // Traverse in postorder so that we hit uses before definitions.
     // Traverse instruction list backwards for the same reason.
     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
         if (mir->shouldCancel("Eliminate Dead Code (main loop)"))
             return false;
 
         // Remove unused instructions.
-        for (MInstructionReverseIterator inst = block->rbegin(); inst != block->rend(); ) {
+        for (MInstructionReverseIterator iter = block->rbegin(); iter != block->rend(); ) {
+            MInstruction *inst = *iter++;
             if (!inst->isEffectful() && !inst->resumePoint() &&
                 !inst->hasUses() && !inst->isGuard() &&
                 !inst->isControlInstruction())
             {
-                inst = block->discardAt(inst);
+                block->discard(inst);
             } else if (!inst->isRecoveredOnBailout() && !inst->isGuard() &&
                        !inst->hasLiveDefUses() && inst->canRecoverOnBailout())
             {
                 inst->setRecoveredOnBailout();
-                inst++;
-            } else {
-                inst++;
             }
         }
     }
 
     return true;
 }
 
 static inline bool
@@ -654,34 +650,35 @@ jit::EliminatePhis(MIRGenerator *mir, MI
     // Add all observable phis to a worklist. We use the "in worklist" bit to
     // mean "this phi is live".
     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
         if (mir->shouldCancel("Eliminate Phis (populate loop)"))
             return false;
 
         MPhiIterator iter = block->phisBegin();
         while (iter != block->phisEnd()) {
+            MPhi *phi = *iter++;
+
             // Flag all as unused, only observable phis would be marked as used
             // when processed by the work list.
-            iter->setUnused();
+            phi->setUnused();
 
             // If the phi is redundant, remove it here.
-            if (MDefinition *redundant = IsPhiRedundant(*iter)) {
-                iter->justReplaceAllUsesWith(redundant);
-                iter = block->discardPhiAt(iter);
+            if (MDefinition *redundant = IsPhiRedundant(phi)) {
+                phi->justReplaceAllUsesWith(redundant);
+                block->discardPhi(phi);
                 continue;
             }
 
             // Enqueue observable Phis.
-            if (IsPhiObservable(*iter, observe)) {
-                iter->setInWorklist();
-                if (!worklist.append(*iter))
+            if (IsPhiObservable(phi, observe)) {
+                phi->setInWorklist();
+                if (!worklist.append(phi))
                     return false;
             }
-            iter++;
         }
     }
 
     // Iteratively mark all phis reachable from live phis.
     while (!worklist.empty()) {
         if (mir->shouldCancel("Eliminate Phis (worklist)"))
             return false;
 
@@ -719,20 +716,19 @@ jit::EliminatePhis(MIRGenerator *mir, MI
                 return false;
         }
     }
 
     // Sweep dead phis.
     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
         MPhiIterator iter = block->phisBegin();
         while (iter != block->phisEnd()) {
-            if (iter->isUnused())
-                iter = block->discardPhiAt(iter);
-            else
-                iter++;
+            MPhi *phi = *iter++;
+            if (phi->isUnused())
+                block->discardPhi(phi);
         }
     }
 
     return true;
 }
 
 namespace {
 
@@ -1117,28 +1113,28 @@ TypeAnalyzer::insertConversions()
 {
     // Instructions are processed in reverse postorder: all uses are defs are
     // seen before uses. This ensures that output adjustment (which may rewrite
     // inputs of uses) does not conflict with input adjustment.
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
         if (mir->shouldCancel("Insert Conversions"))
             return false;
 
-        for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd();) {
+        for (MPhiIterator iter(block->phisBegin()), end(block->phisEnd()); iter != end; ) {
+            MPhi *phi = *iter++;
             if (phi->type() == MIRType_Undefined ||
                 phi->type() == MIRType_Null ||
                 phi->type() == MIRType_MagicOptimizedArguments ||
                 phi->type() == MIRType_MagicOptimizedOut ||
                 phi->type() == MIRType_MagicUninitializedLexical)
             {
-                replaceRedundantPhi(*phi);
-                phi = block->discardPhiAt(phi);
+                replaceRedundantPhi(phi);
+                block->discardPhi(phi);
             } else {
-                adjustPhiInputs(*phi);
-                phi++;
+                adjustPhiInputs(phi);
             }
         }
         for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) {
             if (!adjustInputs(*iter))
                 return false;
         }
     }
     return true;
@@ -1843,16 +1839,17 @@ jit::AssertBasicGraphCoherency(MIRGraph 
                 MOZ_ASSERT(iter->getUseFor(i)->hasProducer());
                 MOZ_ASSERT(CheckOperandImpliesUse(*iter, iter->getOperand(i)));
             }
         }
         for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
             MOZ_ASSERT(phi->numOperands() == block->numPredecessors());
             MOZ_ASSERT(!phi->isRecoveredOnBailout());
             MOZ_ASSERT(phi->type() != MIRType_None);
+            MOZ_ASSERT(phi->dependency() == nullptr);
         }
         for (MDefinitionIterator iter(*block); iter; iter++) {
             MOZ_ASSERT(iter->block() == *block);
             MOZ_ASSERT_IF(iter->hasUses(), iter->type() != MIRType_None);
             MOZ_ASSERT(!iter->isDiscarded());
             MOZ_ASSERT_IF(iter->isStart(),
                           *block == graph.entryBlock() || *block == graph.osrBlock());
             MOZ_ASSERT_IF(iter->isParameter(),
@@ -1976,16 +1973,30 @@ jit::AssertGraphCoherency(MIRGraph &grap
 #ifdef DEBUG
     if (!js_JitOptions.checkGraphConsistency)
         return;
     AssertBasicGraphCoherency(graph);
     AssertReversePostorder(graph);
 #endif
 }
 
+static void
+AssertResumePointDominatedByOperands(MResumePoint *resume)
+{
+#ifdef DEBUG
+    for (size_t i = 0, e = resume->numOperands(); i < e; ++i) {
+        MDefinition *op = resume->getOperand(i);
+        if (op->type() == MIRType_MagicOptimizedArguments)
+            continue;
+        MOZ_ASSERT(op->block()->dominates(resume->block()),
+                   "Resume point is not dominated by its operands");
+    }
+#endif
+}
+
 void
 jit::AssertExtendedGraphCoherency(MIRGraph &graph)
 {
     // Checks the basic GraphCoherency but also other conditions that
     // do not hold immediately (such as the fact that critical edges
     // are split)
 
 #ifdef DEBUG
@@ -2060,17 +2071,25 @@ jit::AssertExtendedGraphCoherency(MIRGra
                     MInstructionIterator opIter = block->begin(op->toInstruction());
                     do {
                         ++opIter;
                         MOZ_ASSERT(opIter != block->end(),
                                    "Operand in same block as instruction does not precede");
                     } while (*opIter != ins);
                 }
             }
+            if (MResumePoint *resume = ins->resumePoint())
+                AssertResumePointDominatedByOperands(resume);
         }
+
+        // Verify that the block resume points are dominated by their operands.
+        if (MResumePoint *resume = block->entryResumePoint())
+            AssertResumePointDominatedByOperands(resume);
+        if (MResumePoint *resume = block->outerResumePoint())
+            AssertResumePointDominatedByOperands(resume);
     }
 #endif
 }
 
 
 struct BoundsCheckInfo
 {
     MBoundsCheck *check;
@@ -2432,36 +2451,36 @@ jit::EliminateRedundantChecks(MIRGraph &
 
         // Add all immediate dominators to the front of the worklist.
         if (!worklist.append(block->immediatelyDominatedBlocksBegin(),
                              block->immediatelyDominatedBlocksEnd())) {
             return false;
         }
 
         for (MDefinitionIterator iter(block); iter; ) {
+            MDefinition *def = *iter++;
+
             bool eliminated = false;
 
-            if (iter->isBoundsCheck()) {
-                if (!TryEliminateBoundsCheck(checks, index, iter->toBoundsCheck(), &eliminated))
+            if (def->isBoundsCheck()) {
+                if (!TryEliminateBoundsCheck(checks, index, def->toBoundsCheck(), &eliminated))
                     return false;
-            } else if (iter->isTypeBarrier()) {
-                if (!TryEliminateTypeBarrier(iter->toTypeBarrier(), &eliminated))
+            } else if (def->isTypeBarrier()) {
+                if (!TryEliminateTypeBarrier(def->toTypeBarrier(), &eliminated))
                     return false;
             } else {
                 // Now that code motion passes have finished, replace
                 // instructions which pass through one of their operands
                 // (and perform additional checks) with that operand.
-                if (MDefinition *passthrough = PassthroughOperand(*iter))
-                    iter->replaceAllUsesWith(passthrough);
+                if (MDefinition *passthrough = PassthroughOperand(def))
+                    def->replaceAllUsesWith(passthrough);
             }
 
             if (eliminated)
-                iter = block->discardDefAt(iter);
-            else
-                iter++;
+                block->discardDef(def);
         }
         index++;
     }
 
     MOZ_ASSERT(index == graph.numBlocks());
     return true;
 }
 
@@ -3190,22 +3209,22 @@ jit::MarkLoopBlocks(MIRGraph &graph, MBa
     // entry.
     MBasicBlock *backedge = header->backedge();
     backedge->mark();
     size_t numMarked = 1;
     for (PostorderIterator i = graph.poBegin(backedge); ; ++i) {
         MOZ_ASSERT(i != graph.poEnd(),
                    "Reached the end of the graph while searching for the loop header");
         MBasicBlock *block = *i;
+        // If we've reached the loop header, we're done.
+        if (block == header)
+            break;
         // A block not marked by the time we reach it is not in the loop.
         if (!block->isMarked())
             continue;
-        // If we've reached the loop header, we're done.
-        if (block == header)
-            break;
         // This block is in the loop; trace to its predecessors.
         for (size_t p = 0, e = block->numPredecessors(); p != e; ++p) {
             MBasicBlock *pred = block->getPredecessor(p);
             if (pred->isMarked())
                 continue;
 
             // Blocks dominated by the OSR entry are not part of the loop
             // (unless they aren't reachable from the normal entry).
@@ -3238,17 +3257,25 @@ jit::MarkLoopBlocks(MIRGraph &graph, MBa
                     if (backedge->id() > block->id()) {
                         i = graph.poBegin(innerBackedge);
                         --i;
                     }
                 }
             }
         }
     }
-    MOZ_ASSERT(header->isMarked(), "Loop header should be part of the loop");
+
+    // If there's no path connecting the header to the backedge, then this isn't
+    // actually a loop. This can happen when the code starts with a loop but GVN
+    // folds some branches away.
+    if (!header->isMarked()) {
+        jit::UnmarkLoopBlocks(graph, header);
+        return 0;
+    }
+
     return numMarked;
 }
 
 // Unmark all the blocks that are in the loop with the given header.
 void
 jit::UnmarkLoopBlocks(MIRGraph &graph, MBasicBlock *header)
 {
     MBasicBlock *backedge = header->backedge();
@@ -3323,15 +3350,19 @@ jit::MakeLoopsContiguous(MIRGraph &graph
         MBasicBlock *header = *i;
         if (!header->isLoopHeader())
             continue;
 
         // Mark all blocks that are actually part of the loop.
         bool canOsr;
         size_t numMarked = MarkLoopBlocks(graph, header, &canOsr);
 
+        // If the loop isn't a loop, don't try to optimize it.
+        if (numMarked == 0)
+            continue;
+
         // Move all blocks between header and backedge that aren't marked to
         // the end of the loop, making the loop itself contiguous.
         MakeLoopContiguous(graph, header, numMarked);
     }
 
     return true;
 }
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -621,16 +621,24 @@ bool
 IonBuilder::init()
 {
     if (!types::TypeScript::FreezeTypeSets(constraints(), script(),
                                            &thisTypes, &argTypes, &typeArray))
     {
         return false;
     }
 
+    if (inlineCallInfo_) {
+        // If we're inlining, the actual this/argument types are not necessarily
+        // a subset of the script's observed types. |argTypes| is never accessed
+        // for inlined scripts, so we just null it.
+        thisTypes = inlineCallInfo_->thisArg()->resultTypeSet();
+        argTypes = nullptr;
+    }
+
     if (!analysis().init(alloc(), gsn))
         return false;
 
     // The baseline script normally has the bytecode type map, but compute
     // it ourselves if we do not have a baseline script.
     if (script()->hasBaselineScript()) {
         bytecodeTypeMap = script()->baselineScript()->bytecodeTypeMap();
     } else {
@@ -802,21 +810,21 @@ IonBuilder::processIterators()
 
     return true;
 }
 
 bool
 IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint,
                         CallInfo &callInfo)
 {
+    inlineCallInfo_ = &callInfo;
+
     if (!init())
         return false;
 
-    inlineCallInfo_ = &callInfo;
-
     JitSpew(JitSpew_IonScripts, "Inlining script %s:%d (%p)",
             script()->filename(), script()->lineno(), (void *)script());
 
     callerBuilder_ = callerBuilder;
     callerResumePoint_ = callerResumePoint;
 
     if (callerBuilder->failedBoundsCheck_)
         failedBoundsCheck_ = true;
@@ -5721,17 +5729,17 @@ IonBuilder::jsop_eval(uint32_t argc)
 
         if (!info().funMaybeLazy())
             return abort("Direct eval in global code");
 
         // The 'this' value for the outer and eval scripts must be the
         // same. This is not guaranteed if a primitive string/number/etc.
         // is passed through to the eval invoke as the primitive may be
         // boxed into different objects if accessed via 'this'.
-        MIRType type = thisTypes->getKnownMIRType();
+        MIRType type = thisTypes ? thisTypes->getKnownMIRType() : MIRType_Value;
         if (type != MIRType_Object && type != MIRType_Null && type != MIRType_Undefined)
             return abort("Direct eval from script with maybe-primitive 'this'");
 
         CallInfo callInfo(alloc(), /* constructing = */ false);
         if (!callInfo.init(current, argc))
             return false;
         callInfo.setImplicitlyUsedUnchecked();
 
@@ -10395,18 +10403,18 @@ IonBuilder::jsop_this()
     }
 
     if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) {
         // No need to wrap primitive |this| in strict mode or self-hosted code.
         current->pushSlot(info().thisSlot());
         return true;
     }
 
-    if (thisTypes->getKnownMIRType() == MIRType_Object ||
-        (thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject()))
+    if (thisTypes && (thisTypes->getKnownMIRType() == MIRType_Object ||
+        (thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject())))
     {
         // This is safe, because if the entry type of |this| is an object, it
         // will necessarily be an object throughout the entire function. OSR
         // can introduce a phi, but this phi will be specialized.
         current->pushSlot(info().thisSlot());
         return true;
     }
 
--- a/js/src/jit/LICM.cpp
+++ b/js/src/jit/LICM.cpp
@@ -118,17 +118,17 @@ IsHoistableIgnoringDependency(MInstructi
            !HasOperandInLoop(ins, hasCalls);
 }
 
 // Test whether the given instruction has a memory dependency inside the loop.
 static bool
 HasDependencyInLoop(MInstruction *ins, MBasicBlock *header)
 {
     // Don't hoist if this instruction depends on a store inside the loop.
-    if (MDefinition *dep = ins->dependency())
+    if (MInstruction *dep = ins->dependency())
         return !IsBeforeLoop(dep, header);
     return false;
 }
 
 // Test whether the given instruction is hoistable.
 static bool
 IsHoistable(MInstruction *ins, MBasicBlock *header, bool hasCalls)
 {
@@ -242,17 +242,22 @@ jit::LICM(MIRGenerator *mir, MIRGraph &g
     // Iterate in RPO to visit outer loops before inner loops. We'd hoist the
     // same things either way, but outer first means we do a little less work.
     for (auto i(graph.rpoBegin()), e(graph.rpoEnd()); i != e; ++i) {
         MBasicBlock *header = *i;
         if (!header->isLoopHeader())
             continue;
 
         bool canOsr;
-        MarkLoopBlocks(graph, header, &canOsr);
+        size_t numBlocks = MarkLoopBlocks(graph, header, &canOsr);
+
+        if (numBlocks == 0) {
+            JitSpew(JitSpew_LICM, "  Loop with header block%u isn't actually a loop", header->id());
+            continue;
+        }
 
         // Hoisting out of a loop that has an entry from the OSR block in
         // addition to its normal entry is tricky. In theory we could clone
         // the instruction and insert phis.
         if (!canOsr)
             VisitLoop(graph, header);
         else
             JitSpew(JitSpew_LICM, "  Skipping loop with header block%u due to OSR", header->id());
--- a/js/src/jit/LinearScan.cpp
+++ b/js/src/jit/LinearScan.cpp
@@ -99,43 +99,39 @@ LinearScanAllocator::allocateRegisters()
                 current->end().bits(), current->requirement()->priority());
 
         // Shift active intervals to the inactive or handled sets as appropriate
         if (position != prevPosition) {
             MOZ_ASSERT(position > prevPosition);
             prevPosition = position;
 
             for (IntervalIterator i(active.begin()); i != active.end(); ) {
-                LiveInterval *it = *i;
+                LiveInterval *it = *i++;
                 MOZ_ASSERT(it->numRanges() > 0);
 
                 if (it->end() <= position) {
-                    i = active.removeAt(i);
+                    active.remove(it);
                     finishInterval(it);
                 } else if (!it->covers(position)) {
-                    i = active.removeAt(i);
+                    active.remove(it);
                     inactive.pushBack(it);
-                } else {
-                    i++;
                 }
             }
 
             // Shift inactive intervals to the active or handled sets as appropriate
             for (IntervalIterator i(inactive.begin()); i != inactive.end(); ) {
-                LiveInterval *it = *i;
+                LiveInterval *it = *i++;
                 MOZ_ASSERT(it->numRanges() > 0);
 
                 if (it->end() <= position) {
-                    i = inactive.removeAt(i);
+                    inactive.remove(it);
                     finishInterval(it);
                 } else if (it->covers(position)) {
-                    i = inactive.removeAt(i);
+                    inactive.remove(it);
                     active.pushBack(it);
-                } else {
-                    i++;
                 }
             }
         }
 
         // Sanity check all intervals in all sets
         validateIntervals();
 
         // If the interval has a hard requirement, grant it.
@@ -699,58 +695,55 @@ LinearScanAllocator::splitBlockingInterv
             if (!splitInterval(current, fixedPos))
                 return false;
         }
     }
 
     // Split the blocking interval if it exists.
 
     for (IntervalIterator i(active.begin()); i != active.end();) {
-        if (i->getAllocation()->isRegister() &&
-            i->getAllocation()->toRegister().aliases(allocatedReg))
+        LiveInterval *it = *i++;
+        if (it->getAllocation()->isRegister() &&
+            it->getAllocation()->toRegister().aliases(allocatedReg))
         {
             JitSpew(JitSpew_RegAlloc, " Splitting active interval %u = [%u, %u]",
-                    vregs[i->vreg()].ins()->id(), i->start().bits(), i->end().bits());
+                    vregs[it->vreg()].ins()->id(), it->start().bits(), it->end().bits());
 
-            MOZ_ASSERT(i->start() != current->start());
-            MOZ_ASSERT(i->covers(current->start()));
-            MOZ_ASSERT(i->start() != current->start());
+            MOZ_ASSERT(it->start() != current->start());
+            MOZ_ASSERT(it->covers(current->start()));
+            MOZ_ASSERT(it->start() != current->start());
 
-            if (!splitInterval(*i, current->start()))
+            if (!splitInterval(it, current->start()))
                 return false;
 
-            LiveInterval *it = *i;
-            i = active.removeAt(i);
+            active.remove(it);
             finishInterval(it);
             if (allocatedReg.numAliased() == 1)
                 break;
         } else {
             JitSpew(JitSpew_RegAlloc, " Not touching active interval %u = [%u, %u]",
-                    vregs[i->vreg()].ins()->id(), i->start().bits(), i->end().bits());
-            i++;
+                    vregs[it->vreg()].ins()->id(), it->start().bits(), it->end().bits());
         }
     }
     // Split any inactive intervals at the next live point.
     for (IntervalIterator i(inactive.begin()); i != inactive.end(); ) {
-        if (i->getAllocation()->isRegister() &&
-            i->getAllocation()->toRegister().aliases(allocatedReg))
+        LiveInterval *it = *i++;
+        if (it->getAllocation()->isRegister() &&
+            it->getAllocation()->toRegister().aliases(allocatedReg))
         {
             JitSpew(JitSpew_RegAlloc, " Splitting inactive interval %u = [%u, %u]",
-                    vregs[i->vreg()].ins()->id(), i->start().bits(), i->end().bits());
+                    vregs[it->vreg()].ins()->id(), it->start().bits(), it->end().bits());
 
-            LiveInterval *it = *i;
             CodePosition nextActive = it->nextCoveredAfter(current->start());
             MOZ_ASSERT(nextActive != CodePosition::MIN);
 
             if (!splitInterval(it, nextActive))
                 return false;
-            i = inactive.removeAt(i);
+            inactive.remove(it);
             finishInterval(it);
-        } else {
-            i++;
         }
     }
 
     return true;
 }
 
 /*
  * Assign the current interval the given allocation, splitting conflicting
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -184,17 +184,17 @@ MDefinition::addU32ToHash(HashNumber has
 }
 
 HashNumber
 MDefinition::valueHash() const
 {
     HashNumber out = op();
     for (size_t i = 0, e = numOperands(); i < e; i++)
         out = addU32ToHash(out, getOperand(i)->id());
-    if (MDefinition *dep = dependency())
+    if (MInstruction *dep = dependency())
         out = addU32ToHash(out, dep->id());
     return out;
 }
 
 bool
 MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const
 {
     if (op() != ins->op())
@@ -533,17 +533,17 @@ MDefinition::replaceAllUsesWith(MDefinit
 }
 
 void
 MDefinition::justReplaceAllUsesWith(MDefinition *dom)
 {
     MOZ_ASSERT(dom != nullptr);
     MOZ_ASSERT(dom != this);
 
-    for (MUseIterator i(usesBegin()); i != usesEnd(); i++)
+    for (MUseIterator i(usesBegin()), e(usesEnd()); i != e; ++i)
         i->setProducerUnchecked(dom);
     dom->uses_.takeElements(uses_);
 }
 
 bool
 MDefinition::emptyResultTypeSet() const
 {
     return resultTypeSet() && resultTypeSet()->empty();
@@ -1187,30 +1187,34 @@ MPhi::removeOperand(size_t index)
 {
     MOZ_ASSERT(index < numOperands());
     MOZ_ASSERT(getUseFor(index)->index() == index);
     MOZ_ASSERT(getUseFor(index)->consumer() == this);
 
     // If we have phi(..., a, b, c, d, ..., z) and we plan
     // on removing a, then first shift downward so that we have
     // phi(..., b, c, d, ..., z, z):
-    size_t length = inputs_.length();
-    for (size_t i = index; i < length - 1; i++)
-        inputs_[i].replaceProducer(inputs_[i + 1].producer());
+    MUse *p = inputs_.begin() + index;
+    MUse *e = inputs_.end();
+    p->producer()->removeUse(p);
+    for (; p < e - 1; ++p) {
+        MDefinition *producer = (p + 1)->producer();
+        p->setProducerUnchecked(producer);
+        producer->replaceUse(p + 1, p);
+    }
 
     // truncate the inputs_ list:
-    inputs_[length - 1].releaseProducer();
-    inputs_.shrinkBy(1);
+    inputs_.popBack();
 }
 
 void
 MPhi::removeAllOperands()
 {
-    for (size_t i = 0; i < inputs_.length(); i++)
-        inputs_[i].releaseProducer();
+    for (MUse *p = inputs_.begin(), *e = inputs_.end(); p < e; ++p)
+        p->producer()->removeUse(p);
     inputs_.clear();
 }
 
 MDefinition *
 MPhi::foldsTernary()
 {
     /* Look if this MPhi is a ternary construct.
      * This is a very loose term as it actually only checks for
@@ -1352,29 +1356,16 @@ MPhi::congruentTo(const MDefinition *ins
     //
     // For now, consider phis in different blocks incongruent.
     if (ins->block() != block())
         return false;
 
     return congruentIfOperandsEqual(ins);
 }
 
-bool
-MPhi::reserveLength(size_t length)
-{
-    // Initializes a new MPhi to have an Operand vector of at least the given
-    // capacity. This permits use of addInput() instead of addInputSlow(), the
-    // latter of which may call pod_realloc().
-    MOZ_ASSERT(numOperands() == 0);
-#if DEBUG
-    capacity_ = length;
-#endif
-    return inputs_.reserve(length);
-}
-
 static inline types::TemporaryTypeSet *
 MakeMIRTypeSet(MIRType type)
 {
     MOZ_ASSERT(type != MIRType_Value);
     types::Type ntype = type == MIRType_Object
                         ? types::Type::AnyObjectType()
                         : types::Type::PrimitiveType(ValueTypeFromMIRType(type));
     LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
@@ -1493,75 +1484,30 @@ MPhi::typeIncludes(MDefinition *def)
         // This phi must be able to be any value.
         return this->type() == MIRType_Value
             && (!this->resultTypeSet() || this->resultTypeSet()->unknown());
     }
 
     return this->mightBeType(def->type());
 }
 
-void
-MPhi::addInput(MDefinition *ins)
-{
-    // This can only been done if the length was reserved through reserveLength,
-    // else the slower addInputSlow need to get called.
-    MOZ_ASSERT(inputs_.length() < capacity_);
-
-    inputs_.append(MUse());
-    inputs_.back().init(ins, this);
-}
-
 bool
-MPhi::addInputSlow(MDefinition *ins, bool *ptypeChange)
-{
-    // The list of inputs to an MPhi is given as a vector of MUse nodes,
-    // each of which is in the list of the producer MDefinition.
-    // Because appending to a vector may reallocate the vector, it is possible
-    // that this operation may cause the producers' linked lists to reference
-    // invalid memory. Therefore, in the event of moving reallocation, each
-    // MUse must be removed and reinserted from/into its producer's use chain.
-    uint32_t index = inputs_.length();
-    bool performingRealloc = !inputs_.canAppendWithoutRealloc(1);
-
-    // Remove all MUses from all use lists, in case pod_realloc() moves.
-    if (performingRealloc) {
-        for (uint32_t i = 0; i < index; i++) {
-            MUse *use = &inputs_[i];
-            use->producer()->removeUse(use);
-        }
+MPhi::checkForTypeChange(MDefinition *ins, bool *ptypeChange)
+{
+    MIRType resultType = this->type();
+    types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
+
+    if (!MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet()))
+        return false;
+
+    if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
+        *ptypeChange = true;
+        setResultType(resultType);
+        setResultTypeSet(resultTypeSet);
     }
-
-    // Insert the new input.
-    if (!inputs_.append(MUse()))
-        return false;
-
-    inputs_.back().init(ins, this);
-
-    if (ptypeChange) {
-        MIRType resultType = this->type();
-        types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
-
-        if (!MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet()))
-            return false;
-
-        if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
-            *ptypeChange = true;
-            setResultType(resultType);
-            setResultTypeSet(resultTypeSet);
-        }
-    }
-
-    // Add all previously-removed MUses back.
-    if (performingRealloc) {
-        for (uint32_t i = 0; i < index; i++) {
-            MUse *use = &inputs_[i];
-            use->producer()->addUse(use);
-        }
-    }
-
     return true;
 }
 
 void
 MCall::addArg(size_t argnum, MDefinition *arg)
 {
     // The operand vector is initialized in reverse order by the IonBuilder.
     // It cannot be checked for consistency until all arguments are added.
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -107,53 +107,58 @@ MIRType MIRTypeFromValue(const js::Value
      */                                                                         \
     _(Discarded)
 
 class MDefinition;
 class MInstruction;
 class MBasicBlock;
 class MNode;
 class MUse;
+class MPhi;
 class MIRGraph;
 class MResumePoint;
 class MControlInstruction;
 
 // Represents a use of a node.
 class MUse : public TempObject, public InlineListNode<MUse>
 {
+    // Grant access to setProducerUnchecked.
     friend class MDefinition;
+    friend class MPhi;
 
     MDefinition *producer_; // MDefinition that is being used.
     MNode *consumer_;       // The node that is using this operand.
 
-    MUse(MDefinition *producer, MNode *consumer)
-      : producer_(producer),
-        consumer_(consumer)
-    { }
-
-    // Low-level unchecked edit method for replaceAllUsesWith. This doesn't
-    // update use lists! replaceAllUsesWith does that manually.
+    // Low-level unchecked edit method for replaceAllUsesWith and
+    // MPhi::removeOperand. This doesn't update use lists!
+    // replaceAllUsesWith and MPhi::removeOperand do that manually.
     void setProducerUnchecked(MDefinition *producer) {
         MOZ_ASSERT(consumer_);
         MOZ_ASSERT(producer_);
         MOZ_ASSERT(producer);
         producer_ = producer;
     }
 
   public:
     // Default constructor for use in vectors.
     MUse()
       : producer_(nullptr), consumer_(nullptr)
     { }
 
-    // MUses can only be copied when they are not in a use list.
-    explicit MUse(const MUse &other)
-      : producer_(other.producer_), consumer_(other.consumer_)
-    {
-        MOZ_ASSERT(!other.next && !other.prev);
+    // Move constructor for use in vectors. When an MUse is moved, it stays
+    // in its containing use list.
+    MUse(MUse &&other)
+      : InlineListNode<MUse>(mozilla::Move(other)),
+        producer_(other.producer_), consumer_(other.consumer_)
+    { }
+
+    // Construct an MUse initialized with |producer| and |consumer|.
+    MUse(MDefinition *producer, MNode *consumer)
+    {
+        initUnchecked(producer, consumer);
     }
 
     // Set this use, which was previously clear.
     inline void init(MDefinition *producer, MNode *consumer);
     // Like init, but works even when the use contains uninitialized data.
     inline void initUnchecked(MDefinition *producer, MNode *consumer);
     // Like initUnchecked, but set the producer to nullptr.
     inline void initUncheckedWithoutProducer(MNode *consumer);
@@ -337,19 +342,19 @@ class MDefinition : public MNode
     InlineList<MUse> uses_;        // Use chain.
     uint32_t id_;                  // Instruction ID, which after block re-ordering
                                    // is sorted within a basic block.
     uint32_t flags_;               // Bit flags.
     Range *range_;                 // Any computed range for this def.
     MIRType resultType_;           // Representation of result type.
     types::TemporaryTypeSet *resultTypeSet_; // Optional refinement of the result type.
     union {
-        MDefinition *dependency_;  // Implicit dependency (store, call, etc.) of this instruction.
+        MInstruction *dependency_; // Implicit dependency (store, call, etc.) of this instruction.
                                    // Used by alias analysis, GVN and LICM.
-        uint32_t virtualRegister_;   // Used by lowering to map definitions to virtual registers.
+        uint32_t virtualRegister_; // Used by lowering to map definitions to virtual registers.
     };
 
     // Track bailouts by storing the current pc in MIR instruction. Also used
     // for profiling and keeping track of what the last known pc was.
     BytecodeSite trackedSite_;
 
   private:
     enum Flag {
@@ -658,21 +663,27 @@ class MDefinition : public MNode
     // (only counting MDefinitions, ignoring MResumePoints)
     bool hasLiveDefUses() const;
 
     bool hasUses() const {
         return !uses_.empty();
     }
 
     void addUse(MUse *use) {
+        MOZ_ASSERT(use->producer() == this);
         uses_.pushFront(use);
     }
     void addUseUnchecked(MUse *use) {
+        MOZ_ASSERT(use->producer() == this);
         uses_.pushFrontUnchecked(use);
     }
+    void replaceUse(MUse *old, MUse *now) {
+        MOZ_ASSERT(now->producer() == this);
+        uses_.replace(old, now);
+    }
     void replaceAllUsesWith(MDefinition *dom);
 
     // Like replaceAllUsesWith, but doesn't set UseRemoved on |this|'s operands.
     void justReplaceAllUsesWith(MDefinition *dom);
 
     // Mark this instruction as having replaced all uses of ins, as during GVN,
     // returning false if the replacement should not be performed. For use when
     // GVN eliminates instructions which are not equivalent to one another.
@@ -730,20 +741,20 @@ class MDefinition : public MNode
 
     void setResultType(MIRType type) {
         resultType_ = type;
     }
     void setResultTypeSet(types::TemporaryTypeSet *types) {
         resultTypeSet_ = types;
     }
 
-    MDefinition *dependency() const {
+    MInstruction *dependency() const {
         return dependency_;
     }
-    void setDependency(MDefinition *dependency) {
+    void setDependency(MInstruction *dependency) {
         dependency_ = dependency;
     }
     virtual AliasSet getAliasSet() const {
         // Instructions are effectful by default.
         return AliasSet::Store(AliasSet::Any);
     }
     bool isEffectful() const {
         return getAliasSet().isStore();
@@ -809,16 +820,17 @@ class MUseDefIterator
         return *current_;
     }
     MDefinition *def() const {
         return current_->consumer()->toDefinition();
     }
 };
 
 typedef Vector<MDefinition *, 8, IonAllocPolicy> MDefinitionVector;
+typedef Vector<MInstruction *, 6, IonAllocPolicy> MInstructionVector;
 
 // An instruction is an SSA name that is inserted into a basic block's IR
 // stream.
 class MInstruction
   : public MDefinition,
     public InlineListNode<MInstruction>
 {
     MResumePoint *resumePoint_;
@@ -5889,17 +5901,16 @@ class MPhi MOZ_FINAL : public MDefinitio
     bool hasBackedgeType_;
     bool triedToSpecialize_;
     bool isIterator_;
     bool canProduceFloat32_;
     bool canConsumeFloat32_;
 
 #if DEBUG
     bool specialized_;
-    uint32_t capacity_;
 #endif
 
   protected:
     MUse *getUseFor(size_t index) {
         // Note: after the initial IonBuilder pass, it is OK to change phi
         // operands such that they do not include the type sets of their
         // operands. This can arise during e.g. value numbering, where
         // definitions producing the same value may have different type sets.
@@ -5918,17 +5929,16 @@ class MPhi MOZ_FINAL : public MDefinitio
         truncateKind_(NoTruncate),
         hasBackedgeType_(false),
         triedToSpecialize_(false),
         isIterator_(false),
         canProduceFloat32_(false),
         canConsumeFloat32_(false)
 #if DEBUG
         , specialized_(false)
-        , capacity_(0)
 #endif
     {
         setResultType(resultType);
     }
 
     static MPhi *New(TempAllocator &alloc, MIRType resultType = MIRType_Value) {
         return new(alloc) MPhi(alloc, resultType);
     }
@@ -5988,24 +5998,46 @@ class MPhi MOZ_FINAL : public MDefinitio
     bool typeIncludes(MDefinition *def);
 
     // Add types for this phi which speculate about new inputs that may come in
     // via a loop backedge.
     bool addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet);
 
     // Initializes the operands vector to the given capacity,
     // permitting use of addInput() instead of addInputSlow().
-    bool reserveLength(size_t length);
+    bool reserveLength(size_t length) {
+        return inputs_.reserve(length);
+    }
 
     // Use only if capacity has been reserved by reserveLength
-    void addInput(MDefinition *ins);
-
-    // Appends a new input to the input vector. May call pod_realloc().
+    void addInput(MDefinition *ins) {
+        // Use infallibleGrowByUninitialized and placement-new instead of just
+        // infallibleAppend to avoid creating a temporary MUse which will get
+        // linked into |ins|'s use list and then unlinked in favor of the
+        // MUse in the Vector. We'd ideally like to use an emplace method here,
+        // once Vector supports that.
+        inputs_.infallibleGrowByUninitialized(1);
+        new (&inputs_.back()) MUse(ins, this);
+    }
+
+    // Appends a new input to the input vector. May perform reallocation.
     // Prefer reserveLength() and addInput() instead, where possible.
-    bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);
+    bool addInputSlow(MDefinition *ins) {
+        // Use growByUninitialized and placement-new instead of just append,
+        // similar to what addInput does.
+        if (!inputs_.growByUninitialized(1))
+            return false;
+
+        new (&inputs_.back()) MUse(ins, this);
+        return true;
+    }
+
+    // Update the type of this phi after adding |ins| as an input. Set
+    // |*ptypeChange| to true if the type changed.
+    bool checkForTypeChange(MDefinition *ins, bool *ptypeChange);
 
     MDefinition *foldsTo(TempAllocator &alloc);
     MDefinition *foldsTernary();
 
     bool congruentTo(const MDefinition *ins) const;
 
     bool isIterator() const {
         return isIterator_;
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -330,17 +330,16 @@ MBasicBlock::NewAsmJS(MIRGraph &graph, C
 
             // Note: Phis are inserted in the same order as the slots.
             for (size_t i = 0; i < nphis; i++) {
                 MDefinition *predSlot = pred->getSlot(i);
 
                 MOZ_ASSERT(predSlot->type() != MIRType_Value);
                 MPhi *phi = new(phis + i) MPhi(alloc, predSlot->type());
 
-                JS_ALWAYS_TRUE(phi->reserveLength(2));
                 phi->addInput(predSlot);
 
                 // Add append Phis in the block.
                 block->addPhi(phi);
                 block->setSlot(i, phi);
             }
         } else {
             block->copySlots(pred);
@@ -402,18 +401,20 @@ MBasicBlock::ensureHasSlots(size_t num)
     return true;
 }
 
 void
 MBasicBlock::copySlots(MBasicBlock *from)
 {
     MOZ_ASSERT(stackPosition_ <= from->stackPosition_);
 
-    for (uint32_t i = 0; i < stackPosition_; i++)
-        slots_[i] = from->slots_[i];
+    MDefinition **thisSlots = slots_.begin();
+    MDefinition **fromSlots = from->slots_.begin();
+    for (size_t i = 0, e = stackPosition_; i < e; ++i)
+        thisSlots[i] = fromSlots[i];
 }
 
 bool
 MBasicBlock::inherit(TempAllocator &alloc, BytecodeAnalysis *analysis, MBasicBlock *pred,
                      uint32_t popped, unsigned stackPhiCount)
 {
     if (pred) {
         stackPosition_ = pred->stackPosition_;
@@ -442,18 +443,17 @@ MBasicBlock::inherit(TempAllocator &allo
     if (pred) {
         if (!predecessors_.append(pred))
             return false;
 
         if (kind_ == PENDING_LOOP_HEADER) {
             size_t i = 0;
             for (i = 0; i < info().firstStackSlot(); i++) {
                 MPhi *phi = MPhi::New(alloc);
-                if (!phi->addInputSlow(pred->getSlot(i)))
-                    return false;
+                phi->addInput(pred->getSlot(i));
                 addPhi(phi);
                 setSlot(i, phi);
                 entryResumePoint()->initOperand(i, phi);
             }
 
             MOZ_ASSERT(stackPhiCount <= stackDepth());
             MOZ_ASSERT(info().firstStackSlot() <= stackDepth() - stackPhiCount);
 
@@ -463,18 +463,17 @@ MBasicBlock::inherit(TempAllocator &allo
             for (; i < stackDepth() - stackPhiCount; i++) {
                 MDefinition *val = pred->getSlot(i);
                 setSlot(i, val);
                 entryResumePoint()->initOperand(i, val);
             }
 
             for (; i < stackDepth(); i++) {
                 MPhi *phi = MPhi::New(alloc);
-                if (!phi->addInputSlow(pred->getSlot(i)))
-                    return false;
+                phi->addInput(pred->getSlot(i));
                 addPhi(phi);
                 setSlot(i, phi);
                 entryResumePoint()->initOperand(i, phi);
             }
         } else {
             for (size_t i = 0; i < stackDepth(); i++)
                 entryResumePoint()->initOperand(i, getSlot(i));
         }
@@ -834,70 +833,53 @@ MBasicBlock::discardIgnoreOperands(MInst
     for (size_t i = 0, e = ins->numOperands(); i < e; i++)
         MOZ_ASSERT(!ins->hasOperand(i));
 #endif
 
     prepareForDiscard(ins, RefType_IgnoreOperands);
     instructions_.remove(ins);
 }
 
-MInstructionIterator
-MBasicBlock::discardAt(MInstructionIterator &iter)
-{
-    prepareForDiscard(*iter);
-    return instructions_.removeAt(iter);
-}
-
-MInstructionReverseIterator
-MBasicBlock::discardAt(MInstructionReverseIterator &iter)
+void
+MBasicBlock::discardDef(MDefinition *at)
 {
-    prepareForDiscard(*iter);
-    return instructions_.removeAt(iter);
-}
-
-MDefinitionIterator
-MBasicBlock::discardDefAt(MDefinitionIterator &old)
-{
-    MDefinitionIterator iter(old);
-
-    if (iter.atPhi())
-        iter.phiIter_ = iter.block_->discardPhiAt(iter.phiIter_);
+    if (at->isPhi())
+        at->block_->discardPhi(at->toPhi());
     else
-        iter.iter_ = iter.block_->discardAt(iter.iter_);
-
-    return iter;
+        at->block_->discard(at->toInstruction());
 }
 
 void
 MBasicBlock::discardAllInstructions()
 {
     MInstructionIterator iter = begin();
     discardAllInstructionsStartingAt(iter);
 }
 
 void
-MBasicBlock::discardAllInstructionsStartingAt(MInstructionIterator &iter)
+MBasicBlock::discardAllInstructionsStartingAt(MInstructionIterator iter)
 {
     while (iter != end()) {
         // Discard operands and resume point operands and flag the instruction
         // as discarded.  Also we do not assert that we have no uses as blocks
         // might be removed in reverse post order.
-        prepareForDiscard(*iter, RefType_DefaultNoAssert);
-        iter = instructions_.removeAt(iter);
+        MInstruction *ins = *iter++;
+        prepareForDiscard(ins, RefType_DefaultNoAssert);
+        instructions_.remove(ins);
     }
 }
 
 void
 MBasicBlock::discardAllPhiOperands()
 {
     for (MPhiIterator iter = phisBegin(); iter != phisEnd(); iter++)
         iter->removeAllOperands();
 
     for (MBasicBlock **pred = predecessors_.begin(); pred != predecessors_.end(); pred++)
-        (*pred)->setSuccessorWithPhis(nullptr, 0);
+        (*pred)->clearSuccessorWithPhis();
 }
 
 void
 MBasicBlock::discardAllPhis()
 {
     discardAllPhiOperands();
     phis_.clear();
 }
@@ -975,31 +957,30 @@ MBasicBlock::end(MControlInstruction *in
 void
 MBasicBlock::addPhi(MPhi *phi)
 {
     phis_.pushBack(phi);
     phi->setBlock(this);
     graph().allocDefinitionId(phi);
 }
 
-MPhiIterator
-MBasicBlock::discardPhiAt(MPhiIterator &at)
+void
+MBasicBlock::discardPhi(MPhi *phi)
 {
     MOZ_ASSERT(!phis_.empty());
 
-    at->removeAllOperands();
-    at->setDiscarded();
+    phi->removeAllOperands();
+    phi->setDiscarded();
 
-    MPhiIterator result = phis_.removeAt(at);
+    phis_.remove(phi);
 
     if (phis_.empty()) {
-        for (MBasicBlock **pred = predecessors_.begin(); pred != predecessors_.end(); pred++)
-            (*pred)->setSuccessorWithPhis(nullptr, 0);
+        for (MBasicBlock **pred = predecessors_.begin(), **end = predecessors_.end(); pred < end; ++pred)
+            (*pred)->clearSuccessorWithPhis();
     }
-    return result;
 }
 
 void
 MBasicBlock::flagOperandsOfPrunedBranches(MInstruction *ins)
 {
     // Find the previous resume point which would be used for bailing out.
     MResumePoint *rp = nullptr;
     for (MInstructionReverseIterator iter = rbegin(ins); iter != rend(); iter++) {
@@ -1038,17 +1019,17 @@ MBasicBlock::addPredecessorPopN(TempAllo
 {
     MOZ_ASSERT(pred);
     MOZ_ASSERT(predecessors_.length() > 0);
 
     // Predecessors must be finished, and at the correct stack depth.
     MOZ_ASSERT(pred->hasLastIns());
     MOZ_ASSERT(pred->stackPosition_ == stackPosition_ + popped);
 
-    for (uint32_t i = 0; i < stackPosition_; i++) {
+    for (uint32_t i = 0, e = stackPosition_; i < e; ++i) {
         MDefinition *mine = getSlot(i);
         MDefinition *other = pred->getSlot(i);
 
         if (mine != other) {
             // If the current instruction is a phi, and it was created in this
             // basic block, then we have already placed this phi and should
             // instead append to its operands.
             if (mine->isPhi() && mine->block() == this) {
@@ -1064,17 +1045,17 @@ MBasicBlock::addPredecessorPopN(TempAllo
                     phi = MPhi::New(alloc);
                 addPhi(phi);
 
                 // Prime the phi for each predecessor, so input(x) comes from
                 // predecessor(x).
                 if (!phi->reserveLength(predecessors_.length() + 1))
                     return false;
 
-                for (size_t j = 0; j < predecessors_.length(); j++) {
+                for (size_t j = 0, numPreds = predecessors_.length(); j < numPreds; ++j) {
                     MOZ_ASSERT(predecessors_[j]->getSlot(i) == mine);
                     phi->addInput(mine);
                 }
                 phi->addInput(other);
 
                 setSlot(i, phi);
                 if (entryResumePoint())
                     entryResumePoint()->replaceOperand(i, phi);
@@ -1210,17 +1191,17 @@ MBasicBlock::setBackedgeAsmJS(MBasicBloc
             // know that that's just the first input.
             //
             // Note that we eliminate later rather than now, to avoid any
             // weirdness around pending continue edges which might still hold
             // onto phis.
             exitDef = entryDef->getOperand(0);
         }
 
-        // MBasicBlock::NewAsmJS calls reserveLength(2) for loop header phis.
+        // Phis always have room for 2 operands, so we can use addInput.
         entryDef->addInput(exitDef);
 
         MOZ_ASSERT(slot < pred->stackDepth());
         setSlot(slot, entryDef);
     }
 
     // We are now a loop header proper
     kind_ = LOOP_HEADER;
@@ -1355,17 +1336,17 @@ MBasicBlock::removePredecessorWithoutPhi
     if (isLoopHeader() && hasUniqueBackedge() && backedge() == pred)
         clearLoopHeader();
 
     // Adjust phis.  Note that this can leave redundant phis behind.
     // Don't adjust successorWithPhis() if we haven't constructed this
     // information yet.
     if (pred->successorWithPhis()) {
         MOZ_ASSERT(pred->positionInPhiSuccessor() == predIndex);
-        pred->setSuccessorWithPhis(nullptr, 0);
+        pred->clearSuccessorWithPhis();
         for (size_t j = predIndex+1; j < numPredecessors(); j++)
             getPredecessor(j)->setSuccessorWithPhis(this, j - 1);
     }
 
     // Remove from pred list.
     predecessors_.erase(predecessors_.begin() + predIndex);
 }
 
@@ -1449,19 +1430,20 @@ MBasicBlock::inheritPhisFromBackedge(MBa
             // Note that we eliminate later rather than now, to avoid any
             // weirdness around pending continue edges which might still hold
             // onto phis.
             exitDef = entryDef->getOperand(0);
         }
 
         bool typeChange = false;
 
-        if (!entryDef->addInputSlow(exitDef, &typeChange))
+        if (!entryDef->addInputSlow(exitDef))
             return false;
-
+        if (!entryDef->checkForTypeChange(exitDef, &typeChange))
+            return false;
         *hadTypeChange |= typeChange;
         setSlot(slot, entryDef);
     }
 
     return true;
 }
 
 bool
--- a/js/src/jit/MIRGraph.h
+++ b/js/src/jit/MIRGraph.h
@@ -284,31 +284,29 @@ class MBasicBlock : public TempObject, p
     void addFromElsewhere(MInstruction *ins);
 
     // Move an instruction. Movement may cross block boundaries.
     void moveBefore(MInstruction *at, MInstruction *ins);
 
     // Removes an instruction with the intention to discard it.
     void discard(MInstruction *ins);
     void discardLastIns();
-    MInstructionIterator discardAt(MInstructionIterator &iter);
-    MInstructionReverseIterator discardAt(MInstructionReverseIterator &iter);
-    MDefinitionIterator discardDefAt(MDefinitionIterator &iter);
+    void discardDef(MDefinition *def);
     void discardAllInstructions();
-    void discardAllInstructionsStartingAt(MInstructionIterator &iter);
+    void discardAllInstructionsStartingAt(MInstructionIterator iter);
     void discardAllPhiOperands();
     void discardAllPhis();
     void discardAllResumePoints(bool discardEntry = true);
 
     // Same as |void discard(MInstruction *ins)| but assuming that
     // all operands are already discarded.
     void discardIgnoreOperands(MInstruction *ins);
 
     // Discards a phi instruction and updates predecessor successorWithPhis.
-    MPhiIterator discardPhiAt(MPhiIterator &at);
+    void discardPhi(MPhi *phi);
 
     // Some instruction which are guarding against some MIRType value, or
     // against a type expectation should be considered as removing a potenatial
     // branch where the guard does not hold.  We need to register such
     // instructions in order to do destructive optimizations correctly, such as
     // Range Analysis.
     void flagOperandsOfPrunedBranches(MInstruction *ins);
 
@@ -561,16 +559,19 @@ class MBasicBlock : public TempObject, p
     uint32_t positionInPhiSuccessor() const {
         MOZ_ASSERT(successorWithPhis());
         return positionInPhiSuccessor_;
     }
     void setSuccessorWithPhis(MBasicBlock *successor, uint32_t id) {
         successorWithPhis_ = successor;
         positionInPhiSuccessor_ = id;
     }
+    void clearSuccessorWithPhis() {
+        successorWithPhis_ = nullptr;
+    }
     size_t numSuccessors() const;
     MBasicBlock *getSuccessor(size_t index) const;
     size_t getSuccessorIndex(MBasicBlock *) const;
     size_t getPredecessorIndex(MBasicBlock *) const;
 
     void setLoopDepth(uint32_t loopDepth) {
         loopDepth_ = loopDepth;
     }
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -263,23 +263,23 @@ RangeAnalysis::addBetaNodes()
 bool
 RangeAnalysis::removeBetaNodes()
 {
     JitSpew(JitSpew_Range, "Removing beta nodes");
 
     for (PostorderIterator i(graph_.poBegin()); i != graph_.poEnd(); i++) {
         MBasicBlock *block = *i;
         for (MDefinitionIterator iter(*i); iter; ) {
-            MDefinition *def = *iter;
+            MDefinition *def = *iter++;
             if (def->isBeta()) {
                 MDefinition *op = def->getOperand(0);
                 JitSpew(JitSpew_Range, "Removing beta node %d for %d",
                         def->id(), op->id());
                 def->justReplaceAllUsesWith(op);
-                iter = block->discardDefAt(iter);
+                block->discardDef(def);
             } else {
                 // We only place Beta nodes at the beginning of basic
                 // blocks, so if we see something else, we can move on
                 // to the next block.
                 break;
             }
         }
     }
@@ -1597,17 +1597,21 @@ RangeAnalysis::analyzeLoop(MBasicBlock *
     // an edge leaving the loop body.
     MBasicBlock *backedge = header->backedge();
 
     // Ignore trivial infinite loops.
     if (backedge == header)
         return true;
 
     bool canOsr;
-    MarkLoopBlocks(graph_, header, &canOsr);
+    size_t numBlocks = MarkLoopBlocks(graph_, header, &canOsr);
+
+    // Ignore broken loops.
+    if (numBlocks == 0)
+        return true;
 
     LoopIterationBound *iterationBound = nullptr;
 
     MBasicBlock *block = backedge;
     do {
         BranchDirection direction;
         MTest *branch = block->immediateDominatorBranch(&direction);
 
--- a/js/src/jit/ValueNumbering.cpp
+++ b/js/src/jit/ValueNumbering.cpp
@@ -51,17 +51,23 @@ bool
 ValueNumberer::VisibleValues::ValueHasher::match(Key k, Lookup l)
 {
     // If one of the instructions depends on a store, and the other instruction
     // does not depend on the same store, the instructions are not congruent.
     if (k->dependency() != l->dependency())
         return false;
 
     bool congruent = k->congruentTo(l); // Ask the values themselves what they think.
-    MOZ_ASSERT(congruent == l->congruentTo(k), "congruentTo relation is not symmetric");
+#ifdef DEBUG
+    if (congruent != l->congruentTo(k)) {
+       JitSpew(JitSpew_GVN, "      congruentTo relation is not symmetric between %s%u and %s%u!!",
+               k->opName(), k->id(),
+               l->opName(), l->id());
+    }
+#endif
     return congruent;
 }
 
 void
 ValueNumberer::VisibleValues::ValueHasher::rekey(Key &k, Key newKey)
 {
     k = newKey;
 }
@@ -360,18 +366,17 @@ ValueNumberer::discardDef(MDefinition *d
     }
 #endif
 
     MBasicBlock *block = def->block();
     if (def->isPhi()) {
         MPhi *phi = def->toPhi();
         if (!releaseAndRemovePhiOperands(phi))
              return false;
-        MPhiIterator at(block->phisBegin(phi));
-        block->discardPhiAt(at);
+        block->discardPhi(phi);
     } else {
         MInstruction *ins = def->toInstruction();
         if (MResumePoint *resume = ins->resumePoint()) {
             if (!releaseResumePointOperands(resume))
                 return false;
         }
         if (!releaseOperands(ins))
              return false;
@@ -693,17 +698,17 @@ ValueNumberer::loopHasOptimizablePhi(MBa
 }
 
 // Visit |def|.
 bool
 ValueNumberer::visitDefinition(MDefinition *def)
 {
     // If this instruction has a dependency() into an unreachable block, we'll
     // need to update AliasAnalysis.
-    MDefinition *dep = def->dependency();
+    MInstruction *dep = def->dependency();
     if (dep != nullptr && (dep->isDiscarded() || dep->block()->isDead())) {
         JitSpew(JitSpew_GVN, "      AliasAnalysis invalidated");
         if (updateAliasAnalysis_ && !dependenciesBroken_) {
             // TODO: Recomputing alias-analysis could theoretically expose more
             // GVN opportunities.
             JitSpew(JitSpew_GVN, "        Will recompute!");
             dependenciesBroken_ = true;
         }
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -420,16 +420,17 @@ MSG_DEF(JSMSG_TYPEDOBJECT_STRUCTTYPE_BAD
 MSG_DEF(JSMSG_TYPEDOBJECT_TOO_BIG,     0, JSEXN_ERR, "Type is too large to allocate")
 
 // Typed array
 MSG_DEF(JSMSG_BAD_INDEX,               0, JSEXN_RANGEERR, "invalid or out-of-range index")
 MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS,    0, JSEXN_ERR, "invalid arguments")
 MSG_DEF(JSMSG_TYPED_ARRAY_BAD_OBJECT,  0, JSEXN_TYPEERR, "invalid object argument")
 MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX,   0, JSEXN_ERR, "invalid or out-of-range index")
 MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_ERR, "argument {0} must be >= 0")
+MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED,    0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer")
 
 // Shared array buffer
 MSG_DEF(JSMSG_SHARED_ARRAY_BAD_OBJECT,  0, JSEXN_TYPEERR, "invalid object argument")
 MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH,  0, JSEXN_RANGEERR, "length argument out of range")
 
 // Shared typed array
 MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_OBJECT,  0, JSEXN_TYPEERR, "invalid object argument")
 MSG_DEF(JSMSG_SHARED_TYPED_ARRAY_BAD_ARGS,    0, JSEXN_RANGEERR, "bad combination of offset, length, and element size")
--- a/js/src/jsapi-tests/testArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testArrayBuffer.cpp
@@ -39,26 +39,28 @@ BEGIN_TEST(testArrayBuffer_bug720949_ste
         CHECK(JS_IsArrayBufferObject(obj));
         CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), size);
         JS_GetProperty(cx, obj, "byteLength", &v);
         CHECK_SAME(v, INT_TO_JSVAL(size));
         JS_GetProperty(cx, view, "byteLength", &v);
         CHECK_SAME(v, INT_TO_JSVAL(size));
 
         // Modifying the underlying data should update the value returned through the view
-        uint8_t *data = JS_GetStableArrayBufferData(cx, obj);
-        CHECK(data != nullptr);
-        *reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
+        {
+            JS::AutoCheckCannotGC nogc;
+            uint8_t *data = JS_GetArrayBufferData(obj, nogc);
+            CHECK(data != nullptr);
+            *reinterpret_cast<uint32_t*>(data) = MAGIC_VALUE_2;
+        }
         CHECK(JS_GetElement(cx, view, 0, &v));
         CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
 
         // Steal the contents
         void *contents = JS_StealArrayBufferContents(cx, obj);
         CHECK(contents != nullptr);
-        CHECK(data != nullptr);
 
         // Check that the original ArrayBuffer is neutered
         CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u);
         CHECK(JS_GetProperty(cx, obj, "byteLength", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
         CHECK(JS_GetProperty(cx, view, "byteLength", &v));
         CHECK_SAME(v, INT_TO_JSVAL(0));
         CHECK(JS_GetProperty(cx, view, "byteOffset", &v));
@@ -68,25 +70,31 @@ BEGIN_TEST(testArrayBuffer_bug720949_ste
         CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), 0u);
         v = JSVAL_VOID;
         JS_GetElement(cx, obj, 0, &v);
         CHECK_SAME(v, JSVAL_VOID);
 
         // Transfer to a new ArrayBuffer
         JS::RootedObject dst(cx, JS_NewArrayBufferWithContents(cx, size, contents));
         CHECK(JS_IsArrayBufferObject(dst));
-        data = JS_GetStableArrayBufferData(cx, obj);
+        {
+            JS::AutoCheckCannotGC nogc;
+            (void) JS_GetArrayBufferData(obj, nogc);
+        }
 
         JS::RootedObject dstview(cx, JS_NewInt32ArrayWithBuffer(cx, dst, 0, -1));
         CHECK(dstview != nullptr);
 
         CHECK_EQUAL(JS_GetArrayBufferByteLength(dst), size);
-        data = JS_GetStableArrayBufferData(cx, dst);
-        CHECK(data != nullptr);
-        CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
+        {
+            JS::AutoCheckCannotGC nogc;
+            uint8_t *data = JS_GetArrayBufferData(dst, nogc);
+            CHECK(data != nullptr);
+            CHECK_EQUAL(*reinterpret_cast<uint32_t*>(data), MAGIC_VALUE_2);
+        }
         CHECK(JS_GetElement(cx, dstview, 0, &v));
         CHECK_SAME(v, INT_TO_JSVAL(MAGIC_VALUE_2));
     }
 
     return true;
 }
 END_TEST(testArrayBuffer_bug720949_steal)
 
--- a/js/src/jsapi-tests/testMappedArrayBuffer.cpp
+++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp
@@ -69,24 +69,26 @@ JSObject *CreateNewObject(const int offs
         JS_ReleaseMappedArrayBufferContents(ptr, length);
         return nullptr;
     }
     return obj;
 }
 
 bool VerifyObject(JS::HandleObject obj, uint32_t offset, uint32_t length, const bool mapped)
 {
+    JS::AutoCheckCannotGC nogc;
+
     CHECK(obj);
     CHECK(JS_IsArrayBufferObject(obj));
     CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
     if (mapped)
         CHECK(JS_IsMappedArrayBufferObject(obj));
     else
         CHECK(!JS_IsMappedArrayBufferObject(obj));
-    const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj));
+    const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj, nogc));
     CHECK(data);
     CHECK(memcmp(data, test_data + offset, length) == 0);
 
     return true;
 }
 
 bool TestCreateObject(uint32_t offset, uint32_t length)
 {
--- a/js/src/jsapi-tests/testTypedArrays.cpp
+++ b/js/src/jsapi-tests/testTypedArrays.cpp
@@ -31,18 +31,21 @@ BEGIN_TEST(testTypedArrays)
     CHECK(JS_IsArrayBufferObject(buffer));
 
     RootedObject proto(cx);
     JS_GetPrototype(cx, buffer, &proto);
     CHECK(!JS_IsArrayBufferObject(proto));
     RootedObject dummy(cx, JS_GetParent(proto));
     CHECK(!JS_IsArrayBufferObject(dummy));
 
-    CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer), nbytes);
-    memset(JS_GetStableArrayBufferData(cx, buffer), 1, nbytes);
+    {
+        JS::AutoCheckCannotGC nogc;
+        CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer), nbytes);
+        memset(JS_GetArrayBufferData(buffer, nogc), 1, nbytes);
+    }
 
     ok = ok &&
         TestArrayFromBuffer<JS_NewInt8ArrayWithBuffer, JS_NewInt8ArrayFromArray, int8_t, JS_GetInt8ArrayData>(cx) &&
         TestArrayFromBuffer<JS_NewUint8ArrayWithBuffer, JS_NewUint8ArrayFromArray, uint8_t, JS_GetUint8ArrayData>(cx) &&
         TestArrayFromBuffer<JS_NewUint8ClampedArrayWithBuffer, JS_NewUint8ClampedArrayFromArray, uint8_t, JS_GetUint8ClampedArrayData>(cx) &&
         TestArrayFromBuffer<JS_NewInt16ArrayWithBuffer, JS_NewInt16ArrayFromArray, int16_t, JS_GetInt16ArrayData>(cx) &&
         TestArrayFromBuffer<JS_NewUint16ArrayWithBuffer, JS_NewUint16ArrayFromArray, uint16_t, JS_GetUint16ArrayData>(cx) &&
         TestArrayFromBuffer<JS_NewInt32ArrayWithBuffer, JS_NewInt32ArrayFromArray, int32_t, JS_GetInt32ArrayData>(cx) &&
@@ -50,17 +53,17 @@ BEGIN_TEST(testTypedArrays)
         TestArrayFromBuffer<JS_NewFloat32ArrayWithBuffer, JS_NewFloat32ArrayFromArray, float, JS_GetFloat32ArrayData>(cx) &&
         TestArrayFromBuffer<JS_NewFloat64ArrayWithBuffer, JS_NewFloat64ArrayFromArray, double, JS_GetFloat64ArrayData>(cx);
 
     return ok;
 }
 
 template<JSObject *Create(JSContext *, uint32_t),
          typename Element,
-         Element *GetData(JSObject *)>
+         Element *GetData(JSObject *, const JS::AutoCheckCannotGC&)>
 bool
 TestPlainTypedArray(JSContext *cx)
 {
     {
         RootedObject notArray(cx, Create(cx, UINT32_MAX));
         CHECK(!notArray);
     }
 
@@ -71,58 +74,64 @@ TestPlainTypedArray(JSContext *cx)
     CHECK(!JS_IsTypedArrayObject(proto));
     RootedObject dummy(cx, JS_GetParent(proto));
     CHECK(!JS_IsTypedArrayObject(dummy));
 
     CHECK_EQUAL(JS_GetTypedArrayLength(array), 7u);
     CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(array), sizeof(Element) * 7);
 
-    Element *data;
-    CHECK(data = GetData(array));
-    *data = 13;
+    {
+        JS::AutoCheckCannotGC nogc;
+        Element *data;
+        CHECK(data = GetData(array, nogc));
+        *data = 13;
+    }
     RootedValue v(cx);
     CHECK(JS_GetElement(cx, array, 0, &v));
     CHECK_SAME(v, INT_TO_JSVAL(13));
 
     return true;
 }
 
 template<JSObject *CreateWithBuffer(JSContext *, JS::HandleObject, uint32_t, int32_t),
          JSObject *CreateFromArray(JSContext *, JS::HandleObject),
          typename Element,
-         Element *GetData(JSObject *)>
+         Element *GetData(JSObject *, const JS::AutoCheckCannotGC&)>
 bool
 TestArrayFromBuffer(JSContext *cx)
 {
     size_t elts = 8;
     size_t nbytes = elts * sizeof(Element);
     RootedObject buffer(cx, JS_NewArrayBuffer(cx, nbytes));
-    uint8_t *bufdata;
-    CHECK(bufdata = JS_GetStableArrayBufferData(cx, buffer));
-    memset(bufdata, 1, nbytes);
+    {
+        JS::AutoCheckCannotGC nogc;
+        memset(JS_GetArrayBufferData(buffer, nogc), 1, nbytes);
+    }
 
     {
         RootedObject notArray(cx, CreateWithBuffer(cx, buffer, UINT32_MAX, -1));
         CHECK(!notArray);
     }
 
     RootedObject array(cx, CreateWithBuffer(cx, buffer, 0, -1));
     CHECK_EQUAL(JS_GetTypedArrayLength(array), elts);
     CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(array), nbytes);
     CHECK_EQUAL(JS_GetArrayBufferViewBuffer(cx, array), (JSObject*) buffer);
 
-    Element *data;
-    CHECK(data = GetData(array));
-    CHECK(bufdata = JS_GetStableArrayBufferData(cx, buffer));
-    CHECK_EQUAL((void*) data, (void*) bufdata);
+    {
+        JS::AutoCheckCannotGC nogc;
+        Element *data;
+        CHECK(data = GetData(array, nogc));
+        CHECK_EQUAL((void*) data, (void*) JS_GetArrayBufferData(buffer, nogc));
 
-    CHECK_EQUAL(*bufdata, 1u);
-    CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1u);
+        CHECK_EQUAL(*reinterpret_cast<uint8_t*>(JS_GetArrayBufferData(buffer, nogc)), 1u);
+        CHECK_EQUAL(*reinterpret_cast<uint8_t*>(data), 1u);
+    }
 
     RootedObject shortArray(cx, CreateWithBuffer(cx, buffer, 0, elts / 2));
     CHECK_EQUAL(JS_GetTypedArrayLength(shortArray), elts / 2);
     CHECK_EQUAL(JS_GetTypedArrayByteOffset(shortArray), 0u);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(shortArray), nbytes / 2);
 
     RootedObject ofsArray(cx, CreateWithBuffer(cx, buffer, nbytes / 2, -1));
     CHECK_EQUAL(JS_GetTypedArrayLength(ofsArray), elts / 2);
@@ -132,33 +141,48 @@ TestArrayFromBuffer(JSContext *cx)
     // Make sure all 3 views reflect the same buffer at the expected locations
     JS::RootedValue v(cx, INT_TO_JSVAL(39));
     JS_SetElement(cx, array, 0, v);
     JS::RootedValue v2(cx);
     CHECK(JS_GetElement(cx, array, 0, &v2));
     CHECK_SAME(v, v2);
     CHECK(JS_GetElement(cx, shortArray, 0, &v2));
     CHECK_SAME(v, v2);
-    CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[0]));
+    {
+        JS::AutoCheckCannotGC nogc;
+        Element *data;
+        CHECK(data = GetData(array, nogc));
+        CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[0]));
+    }
 
     v = INT_TO_JSVAL(40);
     JS_SetElement(cx, array, elts / 2, v);
     CHECK(JS_GetElement(cx, array, elts / 2, &v2));
     CHECK_SAME(v, v2);
     CHECK(JS_GetElement(cx, ofsArray, 0, &v2));
     CHECK_SAME(v, v2);
-    CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts / 2]));
+    {
+        JS::AutoCheckCannotGC nogc;
+        Element *data;
+        CHECK(data = GetData(array, nogc));
+        CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts / 2]));
+    }
 
     v = INT_TO_JSVAL(41);
     JS_SetElement(cx, array, elts - 1, v);
     CHECK(JS_GetElement(cx, array, elts - 1, &v2));
     CHECK_SAME(v, v2);
     CHECK(JS_GetElement(cx, ofsArray, elts / 2 - 1, &v2));
     CHECK_SAME(v, v2);
-    CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts - 1]));
+    {
+        JS::AutoCheckCannotGC nogc;
+        Element *data;
+        CHECK(data = GetData(array, nogc));
+        CHECK_EQUAL(long(v.toInt32()), long(reinterpret_cast<Element*>(data)[elts - 1]));
+    }
 
     JS::RootedObject copy(cx, CreateFromArray(cx, array));
     CHECK(JS_GetElement(cx, array, 0, &v));
     CHECK(JS_GetElement(cx, copy, 0, &v2));
     CHECK_SAME(v, v2);
 
     /* The copy should not see changes in the original */
     v2 = INT_TO_JSVAL(42);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1947,49 +1947,42 @@ JS_GetArrayBufferViewByteLength(JSObject
  * care not to hold on across anything that could GC.
  *
  * |obj| must have passed a JS_Is*Array test, or somehow be known that it would
  * pass such a test: it is a typed array or a wrapper of a typed array, and the
  * unwrapping will succeed.
  */
 
 extern JS_FRIEND_API(uint8_t *)
-JS_GetArrayBufferData(JSObject *obj);
+JS_GetArrayBufferData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(int8_t *)
-JS_GetInt8ArrayData(JSObject *obj);
+JS_GetInt8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(uint8_t *)
-JS_GetUint8ArrayData(JSObject *obj);
+JS_GetUint8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(uint8_t *)
-JS_GetUint8ClampedArrayData(JSObject *obj);
+JS_GetUint8ClampedArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(int16_t *)
-JS_GetInt16ArrayData(JSObject *obj);
+JS_GetInt16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(uint16_t *)
-JS_GetUint16ArrayData(JSObject *obj);
+JS_GetUint16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(int32_t *)
-JS_GetInt32ArrayData(JSObject *obj);
+JS_GetInt32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(uint32_t *)
-JS_GetUint32ArrayData(JSObject *obj);
+JS_GetUint32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(float *)
-JS_GetFloat32ArrayData(JSObject *obj);
+JS_GetFloat32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 extern JS_FRIEND_API(double *)
-JS_GetFloat64ArrayData(JSObject *obj);
-
-/*
- * Stable versions of the above functions where the buffer remains valid as long
- * as the object is live.
- */
-extern JS_FRIEND_API(uint8_t *)
-JS_GetStableArrayBufferData(JSContext *cx, JS::HandleObject obj);
+JS_GetFloat64ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&);
 
 /*
  * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
  * versions when possible.
  */
 extern JS_FRIEND_API(void *)
-JS_GetArrayBufferViewData(JSObject *obj);
+JS_GetArrayBufferViewData(JSObject *obj, const JS::AutoCheckCannotGC&);
 
 /*
  * Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been
  * neutered, this will still return the neutered buffer. |obj| must be an
  * object that would return true for JS_IsArrayBufferViewObject().
  */
 extern JS_FRIEND_API(JSObject *)
 JS_GetArrayBufferViewBuffer(JSContext *cx, JS::HandleObject obj);
@@ -2052,17 +2045,17 @@ JS_GetDataViewByteLength(JSObject *obj);
  * Return a pointer to the beginning of the data referenced by a DataView.
  *
  * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
  * it would pass such a test: it is a data view or a wrapper of a data view,
  * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be
  * unable to assert when unwrapping should be disallowed.
  */
 JS_FRIEND_API(void *)
-JS_GetDataViewData(JSObject *obj);
+JS_GetDataViewData(JSObject *obj, const JS::AutoCheckCannotGC&);
 
 namespace js {
 
 /*
  * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the
  * property |id|, using the callable object |callable| as the function to be
  * called for notifications.
  *
@@ -2661,16 +2654,44 @@ SetPropertyIgnoringNamedGetter(JSContext
 JS_FRIEND_API(void)
 ReportErrorWithId(JSContext *cx, const char *msg, JS::HandleId id);
 
 // This function is for one specific use case, please don't use this for anything else!
 extern JS_FRIEND_API(bool)
 ExecuteInGlobalAndReturnScope(JSContext *cx, JS::HandleObject obj, JS::HandleScript script,
                               JS::MutableHandleObject scope);
 
+#if defined(XP_WIN) && defined(_WIN64)
+// Parameters use void* types to avoid #including windows.h. The return value of
+// this function is returned from the exception handler.
+typedef long
+(*JitExceptionHandler)(void *exceptionRecord,  // PEXECTION_RECORD
+                       void *context);         // PCONTEXT
+
+// Windows uses "structured exception handling" to handle faults. When a fault
+// occurs, the stack is searched for a handler (similar to C++ exception
+// handling). If the search does not find a handler, the "unhandled exception
+// filter" is called. Breakpad uses the unhandled exception filter to do crash
+// reporting. Unfortunately, on Win64, JIT code on the stack completely throws
+// off this unwinding process and prevents the unhandled exception filter from
+// being called. The reason is that Win64 requires unwind information be
+// registered for all code regions and JIT code has none. While it is possible
+// to register full unwind information for JIT code, this is a lot of work (one
+// has to be able to recover the frame pointer at any PC) so instead we register
+// a handler for all JIT code that simply calls breakpad's unhandled exception
+// filter (which will perform crash reporting and then terminate the process).
+// This would be wrong if there was an outer __try block that expected to handle
+// the fault, but this is not generally allowed.
+//
+// Gecko must call SetJitExceptionFilter before any JIT code is compiled and
+// only once per process.
+extern JS_FRIEND_API(void)
+SetJitExceptionHandler(JitExceptionHandler handler);
+#endif
+
 } /* namespace js */
 
 extern JS_FRIEND_API(bool)
 js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
                      JS::Handle<JSPropertyDescriptor> descriptor, bool *bp);
 
 extern JS_FRIEND_API(bool)
 js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v);
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -873,22 +873,28 @@ js::math_round(JSContext *cx, unsigned a
     }
 
     return math_round_handle(cx, args[0], args.rval());
 }
 
 double
 js::math_sin_impl(MathCache *cache, double x)
 {
-    return cache->lookup(sin, x, MathCache::Sin);
+    return cache->lookup(math_sin_uncached, x, MathCache::Sin);
 }
 
 double
 js::math_sin_uncached(double x)
 {
+#ifdef _WIN64
+    // Workaround MSVC bug where sin(-0) is +0 instead of -0 on x64 on
+    // CPUs without FMA3 (pre-Haswell). See bug 1076670.
+    if (IsNegativeZero(x))
+        return -0.0;
+#endif
     return sin(x);
 }
 
 bool
 js::math_sin(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1061,21 +1061,21 @@ CacheEntry_getBytecode(HandleObject cach
     *length = arrayBuffer->byteLength();
     return arrayBuffer->dataPointer();
 }
 
 static bool
 CacheEntry_setBytecode(JSContext *cx, HandleObject cache, uint8_t *buffer, uint32_t length)
 {
     MOZ_ASSERT(CacheEntry_isCacheEntry(cache));
+
     ArrayBufferObject::BufferContents contents =
         ArrayBufferObject::BufferContents::create<ArrayBufferObject::PLAIN_BUFFER>(buffer);
     Rooted<ArrayBufferObject*> arrayBuffer(cx, ArrayBufferObject::create(cx, length, contents));
-
-    if (!arrayBuffer || !ArrayBufferObject::ensureNonInline(cx, arrayBuffer))
+    if (!arrayBuffer)
         return false;
 
     SetReservedSlot(cache, CacheEntry_BYTECODE, OBJECT_TO_JSVAL(arrayBuffer));
     return true;
 }
 
 class AutoSaveFrameChain
 {
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TemplateStrings/debugLineNumber.js
@@ -0,0 +1,50 @@
+// 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/.
+
+// TEST BEGIN
+
+// verify debugger line numbers are accurate
+try {
+    `
+    a
+    b
+    c
+    `;
+    throw Error("error");
+} catch (e) {
+    assertEq(e.lineNumber, 14);
+}
+
+try {
+    function tagThatThrows(...args) { throw new Error(); }
+
+    tagThatThrows`
+        multi-line
+        template
+        string`;
+} catch (e) {
+    var stackLines = e.stack.split('\n');
+    var firstLine = stackLines[0].split(':');
+    var secondLine = stackLines[1].split(':');
+    var firstLineSize = firstLine.length;
+    var secondLineSize = secondLine.length;
+    assertEq(firstLine[firstLineSize - 2], "20");
+    assertEq(firstLine[firstLineSize - 1], "45");
+    assertEq(secondLine[secondLineSize - 2], "22");
+    assertEq(secondLine[secondLineSize - 1], "5");
+}
+
+try {
+    ` multi-line
+        template
+        with
+        ${substitutionThatThrows()}`
+
+} catch (e) {
+    assertEq(e.lineNumber, 42);
+}
+
+
+
+reportCompare(0, 0, "ok");
--- a/js/src/tests/js1_8_5/extensions/reflect-parse.js
+++ b/js/src/tests/js1_8_5/extensions/reflect-parse.js
@@ -464,16 +464,27 @@ assertExpr("func`hey${\"4\"}there${5}`",
                   lit("4"), lit(5))));
 assertExpr("func`hey\r\n`", taggedTemplate(ident("func"), template(["hey\n"], ["hey\n"])));
 assertExpr("func`hey${4}``${5}there``mine`",
            taggedTemplate(taggedTemplate(taggedTemplate(
                ident("func"), template(["hey", ""], ["hey", ""], lit(4))),
                template(["", "there"], ["", "there"], lit(5))),
                template(["mine"], ["mine"])));
 
+// multi-line template string - line numbers
+var node = Reflect.parse("`\n\n   ${2}\n\n\n`");
+Pattern({loc:{start:{line:1, column:0}, end:{line:6, column:1}, source:null}, type:"Program",
+body:[{loc:{start:{line:1, column:0}, end:{line:6, column:1}, source:null},
+type:"ExpressionStatement", expression:{loc:{start:{line:1, column:0}, end:{line:6, column:1},
+source:null}, type:"TemplateLiteral", elements:[{loc:{start:{line:1, column:0}, end:{line:3,
+column:5}, source:null}, type:"Literal", value:"\n\n   "}, {loc:{start:{line:3, column:5},
+end:{line:3, column:6}, source:null}, type:"Literal", value:2}, {loc:{start:{line:3, column:6},
+end:{line:6, column:1}, source:null}, type:"Literal", value:"\n\n\n"}]}}]}).match(node);
+
+
 assertStringExpr("\"hey there\"", literal("hey there"));
 
 assertStmt("foo: for(;;) break foo;", labStmt(ident("foo"), forStmt(null, null, null, breakStmt(ident("foo")))));
 assertStmt("foo: for(;;) continue foo;", labStmt(ident("foo"), forStmt(null, null, null, continueStmt(ident("foo")))));
 assertStmt("with (obj) { }", withStmt(ident("obj"), blockStmt([])));
 assertStmt("with (obj) { obj; }", withStmt(ident("obj"), blockStmt([exprStmt(ident("obj"))])));
 assertStmt("while (foo) { }", whileStmt(ident("foo"), blockStmt([])));
 assertStmt("while (foo) { foo; }", whileStmt(ident("foo"), blockStmt([exprStmt(ident("foo"))])));
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -372,18 +372,23 @@ ArrayBufferObject::changeContents(JSCont
 }
 
 /* static */ bool
 ArrayBufferObject::prepareForAsmJSNoSignals(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
     if (buffer->isAsmJSArrayBuffer())
         return true;
 
-    if (!ensureNonInline(cx, buffer))
-        return false;
+    if (!buffer->ownsData()) {
+        BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
+        if (!contents)
+            return false;
+        memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
+        buffer->changeContents(cx, contents);
+    }
 
     buffer->setIsAsmJSArrayBuffer();
     return true;
 }
 
 void
 ArrayBufferObject::releaseAsmJSArrayNoSignals(FreeOp *fop)
 {
@@ -692,44 +697,33 @@ ArrayBufferObject::createDataViewForThis
 
 bool
 ArrayBufferObject::createDataViewForThis(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsArrayBuffer, createDataViewForThisImpl>(cx, args);
 }
 
-/* static */ bool
-ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
+/* static */ ArrayBufferObject::BufferContents
+ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer,
+                                 bool hasStealableContents)
 {
-    if (!buffer->ownsData()) {
-        BufferContents contents = AllocateArrayBufferContents(cx, buffer->byteLength());
-        if (!contents)
-            return false;
-        memcpy(contents.data(), buffer->dataPointer(), buffer->byteLength());
-        buffer->changeContents(cx, contents);
-    }
+    MOZ_ASSERT_IF(hasStealableContents, buffer->hasStealableContents());
 
-    return true;
-}
-
-/* static */ ArrayBufferObject::BufferContents
-ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer)
-{
     if (!buffer->canNeuter(cx)) {
         js_ReportOverRecursed(cx);
         return BufferContents::createUnowned(nullptr);
     }
 
     BufferContents oldContents(buffer->dataPointer(), buffer->bufferKind());
     BufferContents newContents = AllocateArrayBufferContents(cx, buffer->byteLength());
     if (!newContents)
         return BufferContents::createUnowned(nullptr);
 
-    if (buffer->hasStealableContents()) {
+    if (hasStealableContents) {
         // Return the old contents and give the neutered buffer a pointer to
         // freshly allocated memory that we will never write to and should
         // never get committed.
         buffer->setOwnsData(DoesntOwnData);
         ArrayBufferObject::neuter(cx, buffer, newContents);
         return oldContents;
     }
 
@@ -1049,38 +1043,24 @@ js::UnwrapArrayBufferView(JSObject *obj)
 JS_FRIEND_API(uint32_t)
 JS_GetArrayBufferByteLength(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     return obj ? AsArrayBuffer(obj).byteLength() : 0;
 }
 
 JS_FRIEND_API(uint8_t *)
-JS_GetArrayBufferData(JSObject *obj)
+JS_GetArrayBufferData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     return AsArrayBuffer(obj).dataPointer();
 }
 
-JS_FRIEND_API(uint8_t *)
-JS_GetStableArrayBufferData(JSContext *cx, HandleObject objArg)
-{
-    JSObject *obj = CheckedUnwrap(objArg);
-    if (!obj)
-        return nullptr;
-
-    Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(obj));
-    if (!ArrayBufferObject::ensureNonInline(cx, buffer))
-        return nullptr;
-
-    return buffer->dataPointer();
-}
-
 JS_FRIEND_API(bool)
 JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj,
                      NeuterDataDisposition changeData)
 {
     if (!obj->is<ArrayBufferObject>()) {
         JS_ReportError(cx, "ArrayBuffer object required");
         return false;
     }
@@ -1162,17 +1142,29 @@ JS_StealArrayBufferContents(JSContext *c
         return nullptr;
 
     if (!obj->is<ArrayBufferObject>()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return nullptr;
     }
 
     Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
-    return ArrayBufferObject::stealContents(cx, buffer).data();
+    if (buffer->isNeutered()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+        return nullptr;
+    }
+
+    // The caller assumes that a plain malloc'd buffer is returned.
+    // hasStealableContents is true for mapped buffers, so we must additionally
+    // require that the buffer is plain. In the future, we could consider
+    // returning something that handles releasing the memory.
+    bool hasStealableContents = buffer->hasStealableContents() &&
+                                buffer->bufferKind() == ArrayBufferObject::PLAIN_BUFFER;
+
+    return ArrayBufferObject::stealContents(cx, buffer, hasStealableContents).data();
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *data)
 {
     MOZ_ASSERT(data);
     ArrayBufferObject::BufferContents contents =
         ArrayBufferObject::BufferContents::create<ArrayBufferObject::MAPPED_BUFFER>(data);
@@ -1199,17 +1191,17 @@ JS_IsMappedArrayBufferObject(JSObject *o
         return false;
 
     return obj->is<ArrayBufferObject>()
            ? obj->as<ArrayBufferObject>().isMappedArrayBuffer()
            : false;
 }
 
 JS_FRIEND_API(void *)
-JS_GetArrayBufferViewData(JSObject *obj)
+JS_GetArrayBufferViewData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
                                      : obj->as<TypedArrayObject>().viewData();
 }
 
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -189,17 +189,19 @@ class ArrayBufferObject : public ArrayBu
     template<typename T>
     static bool createTypedArrayFromBufferImpl(JSContext *cx, CallArgs args);
 
     template<typename T>
     static bool createTypedArrayFromBuffer(JSContext *cx, unsigned argc, Value *vp);
 
     static void objectMoved(JSObject *obj, const JSObject *old);
 
-    static BufferContents stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer);
+    static BufferContents stealContents(JSContext *cx,
+                                        Handle<ArrayBufferObject*> buffer,
+                                        bool hasStealableContents);
 
     bool hasStealableContents() const {
         // Inline elements strictly adhere to the corresponding buffer.
         if (!ownsData())
             return false;
 
         // asm.js buffer contents are transferred by copying, just like inline
         // elements.
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1164,18 +1164,19 @@ JSStructuredCloneWriter::transferOwnersh
         MOZ_ASSERT(ownership == JS::SCTAG_TMO_UNFILLED);
 #endif
 
         if (ObjectClassIs(obj, ESClass_ArrayBuffer, context())) {
             // The current setup of the array buffer inheritance hierarchy doesn't
             // lend itself well to generic manipulation via proxies.
             Rooted<ArrayBufferObject *> arrayBuffer(context(), &CheckedUnwrap(obj)->as<ArrayBufferObject>());
             size_t nbytes = arrayBuffer->byteLength();
+            bool hasStealableContents = arrayBuffer->hasStealableContents();
             ArrayBufferObject::BufferContents bufContents =
-                ArrayBufferObject::stealContents(context(), arrayBuffer);
+                ArrayBufferObject::stealContents(context(), arrayBuffer, hasStealableContents);
             if (!bufContents)
                 return false; // Destructor will clean up the already-transferred data.
             content = bufContents.data();
             tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
             if (bufContents.kind() & ArrayBufferObject::MAPPED_BUFFER)
                 ownership = JS::SCTAG_TMO_MAPPED_DATA;
             else
                 ownership = JS::SCTAG_TMO_ALLOC_DATA;
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -2146,105 +2146,105 @@ JS_GetArrayBufferViewType(JSObject *obj)
     if (obj->is<TypedArrayObject>())
         return obj->as<TypedArrayObject>().type();
     else if (obj->is<DataViewObject>())
         return Scalar::TypeMax;
     MOZ_CRASH("invalid ArrayBufferView type");
 }
 
 JS_FRIEND_API(int8_t *)
-JS_GetInt8ArrayData(JSObject *obj)
+JS_GetInt8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int8);
     return static_cast<int8_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint8_t *)
-JS_GetUint8ArrayData(JSObject *obj)
+JS_GetUint8ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8);
     return static_cast<uint8_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint8_t *)
-JS_GetUint8ClampedArrayData(JSObject *obj)
+JS_GetUint8ClampedArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8Clamped);
     return static_cast<uint8_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(int16_t *)
-JS_GetInt16ArrayData(JSObject *obj)
+JS_GetInt16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int16);
     return static_cast<int16_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint16_t *)
-JS_GetUint16ArrayData(JSObject *obj)
+JS_GetUint16ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint16);
     return static_cast<uint16_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(int32_t *)
-JS_GetInt32ArrayData(JSObject *obj)
+JS_GetInt32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int32);
     return static_cast<int32_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(uint32_t *)
-JS_GetUint32ArrayData(JSObject *obj)
+JS_GetUint32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint32);
     return static_cast<uint32_t *>(tarr->viewData());
 }
 
 JS_FRIEND_API(float *)
-JS_GetFloat32ArrayData(JSObject *obj)
+JS_GetFloat32ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float32);
     return static_cast<float *>(tarr->viewData());
 }
 
 JS_FRIEND_API(double *)
-JS_GetFloat64ArrayData(JSObject *obj)
+JS_GetFloat64ArrayData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
     MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float64);
     return static_cast<double *>(tarr->viewData());
 }
@@ -2261,17 +2261,17 @@ JS_GetDataViewByteOffset(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return 0;
     return obj->as<DataViewObject>().byteOffset();
 }
 
 JS_FRIEND_API(void *)
-JS_GetDataViewData(JSObject *obj)
+JS_GetDataViewData(JSObject *obj, const JS::AutoCheckCannotGC&)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     return obj->as<DataViewObject>().dataPointer();
 }
 
 JS_FRIEND_API(uint32_t)
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1361,17 +1361,18 @@ CheckTargetAndPopulate(const nsXPTType& 
     size_t byteSize = count * typeSize;
     if (count > max || !(*output = nsMemory::Alloc(byteSize))) {
         if (pErr)
             *pErr = NS_ERROR_OUT_OF_MEMORY;
 
         return false;
     }
 
-    memcpy(*output, JS_GetArrayBufferViewData(tArr), byteSize);
+    JS::AutoCheckCannotGC nogc;
+    memcpy(*output, JS_GetArrayBufferViewData(tArr, nogc), byteSize);
     return true;
 }
 
 // Fast conversion of typed arrays to native using memcpy.
 // No float or double canonicalization is done. Called by
 // JSarray2Native whenever a TypedArray is met. ArrayBuffers
 // are not accepted; create a properly typed array view on them
 // first. The element type of array must match the XPCOM
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -64,16 +64,17 @@ RestyleManager::RestyleManager(nsPresCon
   , mRebuildAllStyleData(false)
   , mObservingRefreshDriver(false)
   , mInStyleRefresh(false)
   , mSkipAnimationRules(false)
   , mPostAnimationRestyles(false)
   , mIsProcessingAnimationStyleChange(false)
   , mHoverGeneration(0)
   , mRebuildAllExtraHint(nsChangeHint(0))
+  , mRebuildAllRestyleHint(nsRestyleHint(0))
   , mLastUpdateForThrottledAnimations(aPresContext->RefreshDriver()->
                                         MostRecentRefresh())
   , mAnimationGeneration(0)
   , mReframingStyleContexts(nullptr)
   , mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
                      ELEMENT_IS_POTENTIAL_RESTYLE_ROOT)
   , mPendingAnimationRestyles(ELEMENT_HAS_PENDING_ANIMATION_RESTYLE |
                               ELEMENT_IS_POTENTIAL_ANIMATION_RESTYLE_ROOT)
@@ -1404,25 +1405,28 @@ RestyleManager::RestyleForRemove(Element
       if (content == aFollowingSibling) {
         reachedFollowingSibling = true;
       }
     }
   }
 }
 
 void
-RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint)
+RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
+                                    nsRestyleHint aRestyleHint)
 {
   NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
                "Should not reconstruct the root of the frame tree.  "
                "Use ReconstructDocElementHierarchy instead.");
 
   mRebuildAllStyleData = false;
   NS_UpdateHint(aExtraHint, mRebuildAllExtraHint);
+  aRestyleHint |= mRebuildAllRestyleHint;
   mRebuildAllExtraHint = nsChangeHint(0);
+  mRebuildAllRestyleHint = nsRestyleHint(0);
 
   nsIPresShell* presShell = mPresContext->GetPresShell();
   if (!presShell || !presShell->GetRootFrame())
     return;
 
   // Make sure that the viewmanager will outlive the presshell
   nsRefPtr<nsViewManager> vm = presShell->GetViewManager();
 
@@ -1443,23 +1447,17 @@ RestyleManager::RebuildAllStyleData(nsCh
 
   // Until we get rid of these phases in bug 960465, we need to skip
   // animation restyles during the non-animation phase, and post
   // animation restyles so that we restyle those elements again in the
   // animation phase.
   mSkipAnimationRules = true;
   mPostAnimationRestyles = true;
 
-  // FIXME (bug 1047928): Many of the callers probably don't need
-  // eRestyle_Subtree because they're changing things that affect data
-  // computation rather than selector matching; we could have a restyle
-  // hint passed in, and substantially improve the performance of things
-  // like pref changes and the restyling that we do for downloadable
-  // font loads.
-  DoRebuildAllStyleData(mPendingRestyles, aExtraHint, eRestyle_Subtree);
+  DoRebuildAllStyleData(mPendingRestyles, aExtraHint, aRestyleHint);
 
   mPostAnimationRestyles = false;
   mSkipAnimationRules = false;
 #ifdef DEBUG
   mIsProcessingRestyles = false;
 #endif
 
   // Make sure that we process any pending animation restyles from the
@@ -1584,17 +1582,17 @@ RestyleManager::ProcessPendingRestyles()
   NS_POSTCONDITION(mPendingRestyles.Count() == oldPendingRestyleCount,
                    "We should not have posted new non-animation restyles while "
                    "processing animation restyles");
 
   if (mRebuildAllStyleData) {
     // We probably wasted a lot of work up above, but this seems safest
     // and it should be rarely used.
     // This might add us as a refresh observer again; that's ok.
-    RebuildAllStyleData(nsChangeHint(0));
+    RebuildAllStyleData(nsChangeHint(0), nsRestyleHint(0));
   }
 }
 
 void
 RestyleManager::BeginProcessingRestyles()
 {
   // Make sure to not rebuild quote or counter lists while we're
   // processing restyles
@@ -1686,24 +1684,26 @@ RestyleManager::PostRestyleEventInternal
 
   // Unconditionally flag our document as needing a flush.  The other
   // option here would be a dedicated boolean to track whether we need
   // to do so (set here and unset in ProcessPendingRestyles).
   presShell->GetDocument()->SetNeedStyleFlush();
 }
 
 void
-RestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
+RestyleManager::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
+                                             nsRestyleHint aRestyleHint)
 {
   NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame),
                "Should not reconstruct the root of the frame tree.  "
                "Use ReconstructDocElementHierarchy instead.");
 
   mRebuildAllStyleData = true;
   NS_UpdateHint(mRebuildAllExtraHint, aExtraHint);
+  mRebuildAllRestyleHint |= aRestyleHint;
 
   // Get a restyle event posted if necessary
   PostRestyleEventInternal(false);
 }
 
 #ifdef DEBUG
 static void
 DumpContext(nsIFrame* aFrame, nsStyleContext* aContext)
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -300,17 +300,27 @@ public:
   bool ThrottledAnimationStyleIsUpToDate() const {
     return mLastUpdateForThrottledAnimations ==
              mPresContext->RefreshDriver()->MostRecentRefresh();
   }
 
   // Rebuilds all style data by throwing out the old rule tree and
   // building a new one, and additionally applying aExtraHint (which
   // must not contain nsChangeHint_ReconstructFrame) to the root frame.
-  void RebuildAllStyleData(nsChangeHint aExtraHint);
+  //
+  // aRestyleHint says which restyle hint to use for the computation;
+  // the only sensible values to use are eRestyle_Subtree (which says
+  // that the rebuild must run selector matching) and nsRestyleHint(0)
+  // (which says that rerunning selector matching is not required.  (The
+  // method adds eRestyle_ForceDescendants internally, and including it
+  // in the restyle hint is harmless; some callers (e.g.,
+  // nsPresContext::MediaFeatureValuesChanged) might do this for their
+  // own reasons.)
+  void RebuildAllStyleData(nsChangeHint aExtraHint,
+                           nsRestyleHint aRestyleHint);
 
   // Helper that does part of the work of RebuildAllStyleData, shared by
   // RestyleElement for 'rem' handling.
   void DoRebuildAllStyleData(RestyleTracker& aRestyleTracker,
                              nsChangeHint aExtraHint,
                              nsRestyleHint aRestyleHint);
 
   // See PostRestyleEventCommon below.
@@ -374,18 +384,21 @@ public:
    * Asynchronously clear style data from the root frame downwards and ensure
    * it will all be rebuilt. This is safe to call anytime; it will schedule
    * a restyle and take effect next time style changes are flushed.
    * This method is used to recompute the style data when some change happens
    * outside of any style rules, like a color preference change or a change
    * in a system font size, or to fix things up when an optimization in the
    * style data has become invalid. We assume that the root frame will not
    * need to be reframed.
+   *
+   * For parameters, see RebuildAllStyleData.
    */
-  void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint);
+  void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
+                                    nsRestyleHint aRestyleHint);
 
 #ifdef RESTYLE_LOGGING
   /**
    * Returns whether a restyle event currently being processed by this
    * RestyleManager should be logged.
    */
   bool ShouldLogRestyle() {
     return ShouldLogRestyle(mPresContext);
@@ -457,16 +470,17 @@ private:
   // mSkipAnimationRules is also true.
   bool mPostAnimationRestyles : 1;
   // Whether we're currently in the animation phase of restyle
   // processing (to be eliminated in bug 960465)
   bool mIsProcessingAnimationStyleChange : 1;
 
   uint32_t mHoverGeneration;
   nsChangeHint mRebuildAllExtraHint;
+  nsRestyleHint mRebuildAllRestyleHint;
 
   mozilla::TimeStamp mLastUpdateForThrottledAnimations;
 
   OverflowChangedTracker mOverflowChangedTracker;
 
   // The total number of animation flushes by this frame constructor.
   // Used to keep the layer and animation manager in sync.
   uint64_t mAnimationGeneration;
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -285,16 +285,19 @@ inline nsChangeHint NS_HintsNotHandledFo
 enum nsRestyleHint {
   // Rerun selector matching on the element.  If a new style context
   // results, update the style contexts of descendants.  (Irrelevant if
   // eRestyle_Subtree is also set, since that implies a superset of the
   // work.)
   eRestyle_Self = (1<<0),
 
   // Rerun selector matching on the element and all of its descendants.
+  // (Implies eRestyle_ForceDescendants, which ensures that we continue
+  // the restyling process for all descendants, but doesn't cause
+  // selector matching.)
   eRestyle_Subtree = (1<<1),
 
   // Rerun selector matching on all later siblings of the element and
   // all of their descendants.
   eRestyle_LaterSiblings = (1<<2),
 
   // Replace the style data coming from CSS transitions without updating
   // any other style data.  If a new style context results, update style
@@ -337,17 +340,19 @@ enum nsRestyleHint {
   eRestyle_ChangeAnimationPhase = (1 << 7),
 
   // Continue the restyling process to the current frame's children even
   // if this frame's restyling resulted in no style changes.
   eRestyle_Force = (1<<8),
 
   // Continue the restyling process to all of the current frame's
   // descendants, even if any frame's restyling resulted in no style
-  // changes.  (Implies eRestyle_Force.)
+  // changes.  (Implies eRestyle_Force.)  Note that this is weaker than
+  // eRestyle_Subtree, which makes us rerun selector matching on all
+  // descendants rather than just continuing the restyling process.
   eRestyle_ForceDescendants = (1<<9),
 };
 
 // The functions below need an integral type to cast to to avoid
 // infinite recursion.
 typedef decltype(nsRestyleHint(0) + nsRestyleHint(0)) nsRestyleHint_size_t;
 
 inline nsRestyleHint operator|(nsRestyleHint aLeft, nsRestyleHint aRight)
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -1252,17 +1252,20 @@ public:
   static nsClassHashtable<nsUint32HashKey, PointerInfo>* gActivePointersIds;
 
   static void DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture,
                                                    uint32_t aPointerId,
                                                    nsIContent* aCaptureTarget);
   static void SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aContent);
   static void ReleasePointerCapturingContent(uint32_t aPointerId, nsIContent* aContent);
   static nsIContent* GetPointerCapturingContent(uint32_t aPointerId);
-  static void CheckPointerCaptureState(uint32_t aPointerId);
+  
+  // CheckPointerCaptureState checks cases, when got/lostpointercapture events should be fired.
+  // Function returns true, if any of events was fired; false, if no one event was fired.
+  static bool CheckPointerCaptureState(uint32_t aPointerId);
 
   // GetPointerInfo returns true if pointer with aPointerId is situated in device, false otherwise.
   // aActiveState is additional information, which shows state of pointer like button state for mouse.
   static bool GetPointerInfo(uint32_t aPointerId, bool& aActiveState);
 
   /**
    * When capturing content is set, it traps all mouse events and retargets
    * them at this content node. If capturing is not allowed
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -842,17 +842,17 @@ nsPresContext::AppUnitsPerDevPixelChange
   InvalidatePaintedLayers();
 
   if (mDeviceContext) {
     mDeviceContext->FlushFontCache();
   }
 
   if (HasCachedStyleData()) {
     // All cached style data must be recomputed.
-    MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
+    MediaFeatureValuesChanged(eRestyle_ForceDescendants, NS_STYLE_HINT_REFLOW);
   }
 
   mCurAppUnitsPerDevPixel = AppUnitsPerDevPixel();
 }
 
 void
 nsPresContext::PreferenceChanged(const char* aPrefName)
 {
@@ -940,17 +940,19 @@ nsPresContext::UpdateAfterPreferencesCha
   mDeviceContext->FlushFontCache();
 
   nsChangeHint hint = nsChangeHint(0);
 
   if (mPrefChangePendingNeedsReflow) {
     NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
   }
 
-  RebuildAllStyleData(hint);
+  // Preferences require rerunning selector matching because we rebuild
+  // the pref style sheet for some preference changes.
+  RebuildAllStyleData(hint, eRestyle_Subtree);
 }
 
 nsresult
 nsPresContext::Init(nsDeviceContext* aDeviceContext)
 {
   NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
   NS_ENSURE_ARG(aDeviceContext);
 
@@ -1167,17 +1169,17 @@ nsPresContext::SetShell(nsIPresShell* aS
   }
 }
 
 void
 nsPresContext::DoChangeCharSet(const nsCString& aCharSet)
 {
   UpdateCharSet(aCharSet);
   mDeviceContext->FlushFontCache();
-  RebuildAllStyleData(NS_STYLE_HINT_REFLOW);
+  RebuildAllStyleData(NS_STYLE_HINT_REFLOW, nsRestyleHint(0));
 }
 
 void
 nsPresContext::UpdateCharSet(const nsCString& aCharSet)
 {
   if (mLangService) {
     mLanguage = mLangService->LookupCharSet(aCharSet);
     // this will be a language group (or script) code rather than a true language code
@@ -1699,22 +1701,23 @@ nsPresContext::ThemeChangedInternal()
     // surfaces. (We could add a vector image only version of DiscardAll, but
     // in bug 940625 we decided theme changes are rare enough not to bother.)
     mozilla::image::SurfaceCache::DiscardAll();
   }
 
   // This will force the system metrics to be generated the next time they're used
   nsCSSRuleProcessor::FreeSystemMetrics();
 
-  // Changes to system metrics can change media queries on them.
+  // Changes to system metrics can change media queries on them, or
+  // :-moz-system-metric selectors (which requires eRestyle_Subtree).
   // Changes in theme can change system colors (whose changes are
   // properly reflected in computed style data), system fonts (whose
   // changes are not), and -moz-appearance (whose changes likewise are
   // not), so we need to reflow.
-  MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
+  MediaFeatureValuesChanged(eRestyle_Subtree, NS_STYLE_HINT_REFLOW);
 }
 
 void
 nsPresContext::SysColorChanged()
 {
   if (!mPendingSysColorChanged) {
     sLookAndFeelChanged = true;
     nsCOMPtr<nsIRunnable> ev =
@@ -1737,17 +1740,17 @@ nsPresContext::SysColorChangedInternal()
   }
 
   // Reset default background and foreground colors for the document since
   // they may be using system colors
   GetDocumentColorPreferences();
 
   // The system color values are computed to colors in the style data,
   // so normal style data comparison is sufficient here.
-  RebuildAllStyleData(nsChangeHint(0));
+  RebuildAllStyleData(nsChangeHint(0), nsRestyleHint(0));
 }
 
 void
 nsPresContext::UIResolutionChanged()
 {
   if (!mPendingUIResolutionChanged) {
     nsCOMPtr<nsIRunnable> ev =
       NS_NewRunnableMethod(this, &nsPresContext::UIResolutionChangedInternal);
@@ -1833,72 +1836,75 @@ nsPresContext::EmulateMedium(const nsASt
   nsIAtom* previousMedium = Medium();
   mIsEmulatingMedia = true;
 
   nsAutoString mediaType;
   nsContentUtils::ASCIIToLower(aMediaType, mediaType);
 
   mMediaEmulated = do_GetAtom(mediaType);
   if (mMediaEmulated != previousMedium && mShell) {
-    MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
+    MediaFeatureValuesChanged(nsRestyleHint(0), nsChangeHint(0));
   }
 }
 
 void nsPresContext::StopEmulatingMedium()
 {
   nsIAtom* previousMedium = Medium();
   mIsEmulatingMedia = false;
   if (Medium() != previousMedium) {
-    MediaFeatureValuesChanged(eRebuildStyleIfNeeded, nsChangeHint(0));
+    MediaFeatureValuesChanged(nsRestyleHint(0), nsChangeHint(0));
   }
 }
 
 void
-nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint)
+nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint,
+                                   nsRestyleHint aRestyleHint)
 {
   if (!mShell) {
     // We must have been torn down. Nothing to do here.
     return;
   }
 
   mUsesRootEMUnits = false;
   mUsesViewportUnits = false;
   RebuildUserFontSet();
   RebuildCounterStyles();
 
-  RestyleManager()->RebuildAllStyleData(aExtraHint);
+  RestyleManager()->RebuildAllStyleData(aExtraHint, aRestyleHint);
 }
 
 void
-nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint)
+nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
+                                            nsRestyleHint aRestyleHint)
 {
   if (!mShell) {
     // We must have been torn down. Nothing to do here.
     return;
   }
-  RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint);
+  RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint);
 }
 
 void
-nsPresContext::MediaFeatureValuesChanged(StyleRebuildType aShouldRebuild,
+nsPresContext::MediaFeatureValuesChanged(nsRestyleHint aRestyleHint,
                                          nsChangeHint aChangeHint)
 {
-  NS_ASSERTION(aShouldRebuild == eAlwaysRebuildStyle || aChangeHint == 0,
-               "If you don't know if we need a rebuild, how can you provide a hint?");
-
   mPendingMediaFeatureValuesChanged = false;
 
   // MediumFeaturesChanged updates the applied rules, so it always gets called.
-  bool mediaFeaturesDidChange = mShell ? mShell->StyleSet()->MediumFeaturesChanged(this)
-                                       : false;
-
-  if (aShouldRebuild == eAlwaysRebuildStyle ||
-      mediaFeaturesDidChange ||
-      (mUsesViewportUnits && mPendingViewportChange)) {
-    RebuildAllStyleData(aChangeHint);
+  if (mShell && mShell->StyleSet()->MediumFeaturesChanged(this)) {
+    aRestyleHint |= eRestyle_Subtree;
+  }
+
+  if (mUsesViewportUnits && mPendingViewportChange) {
+    // Rebuild all style data without rerunning selector matching.
+    aRestyleHint |= eRestyle_ForceDescendants;
+  }
+
+  if (aRestyleHint || aChangeHint) {
+    RebuildAllStyleData(aChangeHint, aRestyleHint);
   }
 
   mPendingViewportChange = false;
 
   if (mDocument->IsBeingUsedAsImage()) {
     MOZ_ASSERT(PR_CLIST_IS_EMPTY(&mDOMMediaQueryLists));
     return;
   }
@@ -1962,17 +1968,17 @@ nsPresContext::PostMediaFeatureValuesCha
 }
 
 void
 nsPresContext::HandleMediaFeatureValuesChangedEvent()
 {
   // Null-check mShell in case the shell has been destroyed (and the
   // event is the only thing holding the pres context alive).
   if (mPendingMediaFeatureValuesChanged && mShell) {
-    MediaFeatureValuesChanged(eRebuildStyleIfNeeded);
+    MediaFeatureValuesChanged(nsRestyleHint(0));
   }
 }
 
 already_AddRefed<MediaQueryList>
 nsPresContext::MatchMedia(const nsAString& aMediaQueryList)
 {
   nsRefPtr<MediaQueryList> result = new MediaQueryList(this, aMediaQueryList);
 
@@ -2173,17 +2179,17 @@ nsPresContext::UserFontSetUpdated()
   //      intrinsic widths, and any other parts of layout that depend on
   //      font metrics.  This requires a style change reflow to update.
   //
   //   2. Changing the value of the 'ex' and 'ch' units in style data,
   //      which also depend on font metrics.  Updating this information
   //      requires rebuilding the rule tree from the top, avoiding the
   //      reuse of cached data even when no style rules have changed.
 
-  PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
+  PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants);
 }
 
 FontFaceSet*
 nsPresContext::Fonts()
 {
   if (!mFontFaceSet) {
     mFontFaceSet = new FontFaceSet(mDocument->GetInnerWindow(), this);
     GetUserFontSet();  // this will cause the user font set to be created/updated
@@ -2201,17 +2207,18 @@ nsPresContext::FlushCounterStyles()
     // Still in its initial state, no need to clean.
     return;
   }
 
   if (mCounterStylesDirty) {
     bool changed = mCounterStyleManager->NotifyRuleChanged();
     if (changed) {
       PresShell()->NotifyCounterStylesAreDirty();
-      PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW);
+      PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW,
+                                   eRestyle_ForceDescendants);
     }
     mCounterStylesDirty = false;
   }
 }
 
 void
 nsPresContext::RebuildCounterStyles()
 {
@@ -2237,17 +2244,17 @@ nsPresContext::EnsureSafeToHandOutCSSRul
   CSSStyleSheet::EnsureUniqueInnerResult res =
     mShell->StyleSet()->EnsureUniqueInnerOnCSSSheets();
   if (res == CSSStyleSheet::eUniqueInner_AlreadyUnique) {
     // Nothing to do.
     return;
   }
 
   MOZ_ASSERT(res == CSSStyleSheet::eUniqueInner_ClonedInner);
-  RebuildAllStyleData(nsChangeHint(0));
+  RebuildAllStyleData(nsChangeHint(0), eRestyle_Subtree);
 }
 
 void
 nsPresContext::FireDOMPaintEvent(nsInvalidateRequestList* aList)
 {
   nsPIDOMWindow* ourWindow = mDocument->GetWindow();
   if (!ourWindow)
     return;
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -146,22 +146,16 @@ public:
 
   enum nsPresContextType {
     eContext_Galley,       // unpaginated screen presentation
     eContext_PrintPreview, // paginated screen presentation
     eContext_Print,        // paginated printer presentation
     eContext_PageLayout    // paginated & editable.
   };
 
-  // Policies for rebuilding style data.
-  enum StyleRebuildType {
-    eRebuildStyleIfNeeded,
-    eAlwaysRebuildStyle
-  };
-
   nsPresContext(nsIDocument* aDocument, nsPresContextType aType);
 
   /**
    * Initialize the presentation context from a particular device.
    */
   nsresult Init(nsDeviceContext* aDeviceContext);
 
   /**
@@ -249,32 +243,54 @@ public:
     return mCounterStyleManager;
   }
 #endif
 
   /**
    * Rebuilds all style data by throwing out the old rule tree and
    * building a new one, and additionally applying aExtraHint (which
    * must not contain nsChangeHint_ReconstructFrame) to the root frame.
+   * For aRestyleHint, see RestyleManager::RebuildAllStyleData.
    * Also rebuild the user font set and counter style manager.
    */
-  void RebuildAllStyleData(nsChangeHint aExtraHint);
+  void RebuildAllStyleData(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint);
   /**
    * Just like RebuildAllStyleData, except (1) asynchronous and (2) it
    * doesn't rebuild the user font set.
    */
-  void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint);
+  void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
+                                    nsRestyleHint aRestyleHint);
 
-  void MediaFeatureValuesChanged(StyleRebuildType aShouldRebuild,
+  /**
+   * Handle changes in the values of media features (used in media
+   * queries).
+   *
+   * There are three sensible values to use for aRestyleHint:
+   *  * nsRestyleHint(0) to rebuild style data, with rerunning of
+   *    selector matching, only if media features have changed
+   *  * eRestyle_ForceDescendants to force rebuilding of style data (but
+   *    still only rerun selector matching if media query results have
+   *    changed).  (RebuildAllStyleData always adds
+   *    eRestyle_ForceDescendants internally, so here we're only using
+   *    it to distinguish from nsRestyleHint(0) whether we need to call
+   *    RebuildAllStyleData at all.)
+   *  * eRestyle_Subtree to force rebuilding of style data with
+   *    rerunning of selector matching
+   *
+   * For aChangeHint, see RestyleManager::RebuildAllStyleData.  (Passing
+   * a nonzero aChangeHint forces rebuilding style data even if
+   * nsRestyleHint(0) is passed.)
+   */
+  void MediaFeatureValuesChanged(nsRestyleHint aRestyleHint,
                                  nsChangeHint aChangeHint = nsChangeHint(0));
   void PostMediaFeatureValuesChangedEvent();
   void HandleMediaFeatureValuesChangedEvent();
   void FlushPendingMediaFeatureValuesChanged() {
     if (mPendingMediaFeatureValuesChanged)
-      MediaFeatureValuesChanged(eRebuildStyleIfNeeded);
+      MediaFeatureValuesChanged(nsRestyleHint(0));
   }
 
   /**
    * Support for window.matchMedia()
    */
   already_AddRefed<mozilla::dom::MediaQueryList>
     MatchMedia(const nsAString& aMediaQueryList);
 
@@ -528,17 +544,18 @@ public:
   void SetTextZoom(float aZoom) {
     if (aZoom == mTextZoom)
       return;
 
     mTextZoom = aZoom;
     if (HasCachedStyleData()) {
       // Media queries could have changed, since we changed the meaning
       // of 'em' units in them.
-      MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
+      MediaFeatureValuesChanged(eRestyle_ForceDescendants,
+                                NS_STYLE_HINT_REFLOW);
     }
   }
 
   /**
    * Get the minimum font size for the specified language. If aLanguage
    * is nullptr, then the document's language is used.  This combines
    * the language-specific global preference with the per-presentation
    * base minimum font size.
@@ -563,17 +580,18 @@ public:
   void SetBaseMinFontSize(int32_t aMinFontSize) {
     if (aMinFontSize == mBaseMinFontSize)
       return;
 
     mBaseMinFontSize = aMinFontSize;
     if (HasCachedStyleData()) {
       // Media queries could have changed, since we changed the meaning
       // of 'em' units in them.
-      MediaFeatureValuesChanged(eAlwaysRebuildStyle, NS_STYLE_HINT_REFLOW);
+      MediaFeatureValuesChanged(eRestyle_ForceDescendants,
+                                NS_STYLE_HINT_REFLOW);
     }
   }
 
   float GetFullZoom() { return mFullZoom; }
   void SetFullZoom(float aZoom);
 
   nscoord GetAutoQualityMinFontSize() {
     return DevPixelsToAppUnits(mAutoQualityMinFontSizePixelsPref);
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6331,51 +6331,55 @@ nsIPresShell::GetPointerCapturingContent
 {
   PointerCaptureInfo* pointerCaptureInfo = nullptr;
   if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
     return pointerCaptureInfo->mOverrideContent;
   }
   return nullptr;
 }
 
-/* static */ void
+/* static */ bool
 nsIPresShell::CheckPointerCaptureState(uint32_t aPointerId)
 {
+  bool didDispatchEvent = false;
   PointerCaptureInfo* pointerCaptureInfo = nullptr;
   if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
     // If pendingContent exist or anybody calls element.releasePointerCapture
     // we should dispatch lostpointercapture event to overrideContent if it exist
     if (pointerCaptureInfo->mPendingContent || pointerCaptureInfo->mReleaseContent) {
       if (pointerCaptureInfo->mOverrideContent) {
         nsCOMPtr<nsIContent> content;
         pointerCaptureInfo->mOverrideContent.swap(content);
         if (pointerCaptureInfo->mReleaseContent) {
           pointerCaptureInfo->mPendingContent = nullptr;
         }
         if (pointerCaptureInfo->Empty()) {
           gPointerCaptureList->Remove(aPointerId);
         }
         DispatchGotOrLostPointerCaptureEvent(false, aPointerId, content);
+        didDispatchEvent = true;
       } else if (pointerCaptureInfo->mPendingContent && pointerCaptureInfo->mReleaseContent) {
         // If anybody calls element.releasePointerCapture
         // We should clear overrideContent and pendingContent
         pointerCaptureInfo->mPendingContent = nullptr;
         pointerCaptureInfo->mReleaseContent = false;
       }
     }
   }
   if (gPointerCaptureList->Get(aPointerId, &pointerCaptureInfo) && pointerCaptureInfo) {
     // If pendingContent exist we should dispatch gotpointercapture event to it
     if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent) {
       pointerCaptureInfo->mOverrideContent = pointerCaptureInfo->mPendingContent;
       pointerCaptureInfo->mPendingContent = nullptr;
       pointerCaptureInfo->mReleaseContent = false;
       DispatchGotOrLostPointerCaptureEvent(true, aPointerId, pointerCaptureInfo->mOverrideContent);
-    }
-  }
+      didDispatchEvent = true;
+    }
+  }
+  return didDispatchEvent;
 }
 
 /* static */ bool
 nsIPresShell::GetPointerInfo(uint32_t aPointerId, bool& aActiveState)
 {
   PointerInfo* pointerInfo = nullptr;
   if (gActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) {
     aActiveState = pointerInfo->mActiveState;
@@ -7244,17 +7248,19 @@ PresShell::HandleEvent(nsIFrame* aFrame,
         frame = capturingFrame;
       }
     }
 
     if (aEvent->mClass == ePointerEventClass) {
       if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
         // Before any pointer events, we should check state of pointer capture,
         // Thus got/lostpointercapture events emulate asynchronous behavior.
-        CheckPointerCaptureState(pointerEvent->pointerId);
+        // Handlers of got/lostpointercapture events can change capturing state,
+        // That's why we should re-check pointer capture state until stable state.
+        while(CheckPointerCaptureState(pointerEvent->pointerId));
       }
     }
 
     if (aEvent->mClass == ePointerEventClass &&
         aEvent->message != NS_POINTER_DOWN) {
       if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
         uint32_t pointerId = pointerEvent->pointerId;
         nsIContent* pointerCapturingContent = GetPointerCapturingContent(pointerId);
@@ -10630,16 +10636,19 @@ nsIPresShell::SetScrollPositionClampingS
 {
   if (!mScrollPositionClampingScrollPortSizeSet ||
       mScrollPositionClampingScrollPortSize.width != aWidth ||
       mScrollPositionClampingScrollPortSize.height != aHeight) {
     mScrollPositionClampingScrollPortSizeSet = true;
     mScrollPositionClampingScrollPortSize.width = aWidth;
     mScrollPositionClampingScrollPortSize.height = aHeight;
 
+    if (nsIScrollableFrame* rootScrollFrame = GetRootScrollFrameAsScrollable()) {
+      rootScrollFrame->MarkScrollbarsDirtyForReflow();
+    }
     MarkFixedFramesForReflow(eResize);
   }
 }
 
 void
 nsIPresShell::SetContentDocumentFixedPositionMargins(const nsMargin& aMargins)
 {
   if (mContentDocumentFixedPositionMargins == aMargins) {
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -2153,16 +2153,27 @@ bool ScrollFrameHelper::IsIgnoringViewpo
 {
   if (!mIsRoot)
     return false;
   nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
     (nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
   return subdocFrame && !subdocFrame->ShouldClipSubdocument();
 }
 
+void ScrollFrameHelper::MarkScrollbarsDirtyForReflow() const
+{
+  nsIPresShell* presShell = mOuter->PresContext()->PresShell();
+  if (mVScrollbarBox) {
+    presShell->FrameNeedsReflow(mVScrollbarBox, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
+  }
+  if (mHScrollbarBox) {
+    presShell->FrameNeedsReflow(mHScrollbarBox, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
+  }
+}
+
 bool ScrollFrameHelper::ShouldClampScrollPosition() const
 {
   if (!mIsRoot)
     return true;
   nsSubDocumentFrame* subdocFrame = static_cast<nsSubDocumentFrame*>
     (nsLayoutUtils::GetCrossDocParentFrame(mOuter->PresContext()->PresShell()->GetRootFrame()));
   return !subdocFrame || subdocFrame->ShouldClampScrollPosition();
 }
@@ -4356,20 +4367,21 @@ ScrollFrameHelper::ReflowFinished()
       // force a reflow of the fixed child
       presContext->PresShell()->
         FrameNeedsReflow(fixedChild, nsIPresShell::eResize,
                          NS_FRAME_HAS_DIRTY_CHILDREN);
     }
   }
 
   nsRect scrolledContentRect = GetScrolledRect();
+  nsSize scrollClampingScrollPort = GetScrollPositionClampingScrollPortSize();
   nscoord minX = scrolledContentRect.x;
-  nscoord maxX = scrolledContentRect.XMost() - mScrollPort.width;
+  nscoord maxX = scrolledContentRect.XMost() - scrollClampingScrollPort.width;
   nscoord minY = scrolledContentRect.y;
-  nscoord maxY = scrolledContentRect.YMost() - mScrollPort.height;
+  nscoord maxY = scrolledContentRect.YMost() - scrollClampingScrollPort.height;
 
   // Suppress handling of the curpos attribute changes we make here.
   NS_ASSERTION(!mFrameIsUpdatingScrollbar, "We shouldn't be reentering here");
   mFrameIsUpdatingScrollbar = true;
 
   nsCOMPtr<nsIContent> vScroll =
     mVScrollbarBox ? mVScrollbarBox->GetContent() : nullptr;
   nsCOMPtr<nsIContent> hScroll =
@@ -4389,29 +4401,29 @@ ScrollFrameHelper::ReflowFinished()
       nscoord increment = lineScrollAmount.height * kScrollMultiplier;
       // We normally use (scrollArea.height - increment) for height
       // of page scrolling.  However, it is too small when
       // increment is very large. (If increment is larger than
       // scrollArea.height, direction of scrolling will be opposite).
       // To avoid it, we use (float(scrollArea.height) * 0.8) as
       // lower bound value of height of page scrolling. (bug 383267)
       // XXX shouldn't we use GetPageScrollAmount here?
-      nscoord pageincrement = nscoord(mScrollPort.height - increment);
-      nscoord pageincrementMin = nscoord(float(mScrollPort.height) * 0.8);
+      nscoord pageincrement = nscoord(scrollClampingScrollPort.height - increment);
+      nscoord pageincrementMin = nscoord(float(scrollClampingScrollPort.height) * 0.8);
       FinishReflowForScrollbar(vScroll, minY, maxY, scrollPos.y,
                                std::max(pageincrement, pageincrementMin),
                                increment);
     }
     if (hScroll) {
       const double kScrollMultiplier =
         Preferences::GetInt("toolkit.scrollbox.horizontalScrollDistance",
                             NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE);
       nscoord increment = lineScrollAmount.width * kScrollMultiplier;
       FinishReflowForScrollbar(hScroll, minX, maxX, scrollPos.x,
-                               nscoord(float(mScrollPort.width) * 0.8),
+                               nscoord(float(scrollClampingScrollPort.width) * 0.8),
                                increment);
     }
     NS_ENSURE_TRUE(weakFrame.IsAlive(), false);
   }
 
   mFrameIsUpdatingScrollbar = false;
   // We used to rely on the curpos attribute changes above to scroll the
   // view.  However, for scrolling to the left of the viewport, we
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -305,16 +305,18 @@ public:
   // returns true if a resizer should be visible
   bool HasResizer() { return mResizerBox && !mCollapsedResizer; }
   void LayoutScrollbars(nsBoxLayoutState& aState,
                         const nsRect& aContentArea,
                         const nsRect& aOldScrollArea);
 
   bool IsIgnoringViewportClipping() const;
 
+  void MarkScrollbarsDirtyForReflow() const;
+
   bool ShouldClampScrollPosition() const;
 
   bool IsAlwaysActive() const;
   void MarkActive();
   void MarkInactive();
   nsExpirationState* GetExpirationState() { return &mActivityExpirationState; }
 
   void ScheduleSyntheticMouseMove();
@@ -734,16 +736,19 @@ public:
                                    nsRect* aClipRect,
                                    nsTArray<FrameMetrics>* aOutput) const MOZ_OVERRIDE {
     mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame,
                                 aParameters, aClipRect, aOutput);
   }
   virtual bool IsIgnoringViewportClipping() const MOZ_OVERRIDE {
     return mHelper.IsIgnoringViewportClipping();
   }
+  virtual void MarkScrollbarsDirtyForReflow() const MOZ_OVERRIDE {
+    mHelper.MarkScrollbarsDirtyForReflow();
+  }
 
   // nsIStatefulFrame
   NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {
     NS_ENSURE_ARG_POINTER(aState);
     *aState = mHelper.SaveState();
     return NS_OK;
   }
   NS_IMETHOD RestoreState(nsPresState* aState) MOZ_OVERRIDE {
@@ -1089,16 +1094,19 @@ public:
                                    nsRect* aClipRect,
                                    nsTArray<FrameMetrics>* aOutput) const MOZ_OVERRIDE {
     mHelper.ComputeFrameMetrics(aLayer, aContainerReferenceFrame,
                                 aParameters, aClipRect, aOutput);
   }
   virtual bool IsIgnoringViewportClipping() const MOZ_OVERRIDE {
     return mHelper.IsIgnoringViewportClipping();
   }
+  virtual void MarkScrollbarsDirtyForReflow() const MOZ_OVERRIDE {
+    mHelper.MarkScrollbarsDirtyForReflow();
+  }
 
   // nsIStatefulFrame
   NS_IMETHOD SaveState(nsPresState** aState) MOZ_OVERRIDE {
     NS_ENSURE_ARG_POINTER(aState);
     *aState = mHelper.SaveState();
     return NS_OK;
   }
   NS_IMETHOD RestoreState(nsPresState* aState) MOZ_OVERRIDE {
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -380,11 +380,16 @@ public:
                                    const ContainerLayerParameters& aParameters,
                                    nsRect* aOutClipRect,
                                    nsTArray<FrameMetrics>* aOutput) const = 0;
 
   /**
    * If this scroll frame is ignoring viewporting clipping
    */
   virtual bool IsIgnoringViewportClipping() const = 0;
+
+  /**
+   * Mark the scrollbar frames for reflow.
+   */
+  virtual void MarkScrollbarsDirtyForReflow() const = 0;
 };
 
 #endif
--- a/layout/style/FontFace.cpp
+++ b/layout/style/FontFace.cpp
@@ -268,27 +268,25 @@ LoadStateToStatus(gfxUserFontEntry::User
   }
   NS_NOTREACHED("invalid aLoadState value");
   return FontFaceLoadStatus::Error;
 }
 
 already_AddRefed<FontFace>
 FontFace::CreateForRule(nsISupports* aGlobal,
                         nsPresContext* aPresContext,
-                        nsCSSFontFaceRule* aRule,
-                        gfxUserFontEntry* aUserFontEntry)
+                        nsCSSFontFaceRule* aRule)
 {
   nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(aGlobal);
 
   nsRefPtr<FontFace> obj = new FontFace(aGlobal, aPresContext);
   obj->mInitialized = true;
   obj->mRule = aRule;
   obj->mSourceType = eSourceType_FontFaceRule;
   obj->mInFontFaceSet = true;
-  obj->SetUserFontEntry(aUserFontEntry);
   return obj.forget();
 }
 
 already_AddRefed<FontFace>
 FontFace::Constructor(const GlobalObject& aGlobal,
                       const nsAString& aFamily,
                       const StringOrArrayBufferOrArrayBufferView& aSource,
                       const FontFaceDescriptors& aDescriptors,
@@ -822,18 +820,16 @@ FontFace::GetFamilyName(nsString& aResul
 void
 FontFace::DisconnectFromRule()
 {
   MOZ_ASSERT(HasRule());
 
   // Make a copy of the descriptors.
   mDescriptors = new CSSFontFaceDescriptors;
   mRule->GetDescriptors(*mDescriptors);
-
-  mRule->SetFontFace(nullptr);
   mRule = nullptr;
   mInFontFaceSet = false;
 }
 
 bool
 FontFace::HasFontData() const
 {
   return mSourceType == eSourceType_Buffer && mSourceBuffer;
--- a/layout/style/FontFace.h
+++ b/layout/style/FontFace.h
@@ -68,21 +68,19 @@ public:
   };
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FontFace)
 
   nsISupports* GetParentObject() const { return mParent; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
-  static already_AddRefed<FontFace> CreateForRule(
-                                              nsISupports* aGlobal,
-                                              nsPresContext* aPresContext,
-                                              nsCSSFontFaceRule* aRule,
-                                              gfxUserFontEntry* aUserFontEntry);
+  static already_AddRefed<FontFace>
+  CreateForRule(nsISupports* aGlobal, nsPresContext* aPresContext,
+                nsCSSFontFaceRule* aRule);
 
   nsCSSFontFaceRule* GetRule() { return mRule; }
 
   void GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const;
 
   gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
   void SetUserFontEntry(gfxUserFontEntry* aEntry);
 
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -347,32 +347,24 @@ FontFaceSet::Length()
 static PLDHashOperator DestroyIterator(nsPtrHashKey<nsFontFaceLoader>* aKey,
                                        void* aUserArg)
 {
   aKey->GetKey()->Cancel();
   return PL_DHASH_REMOVE;
 }
 
 void
-FontFaceSet::DisconnectFromRule(FontFace* aFontFace)
-{
-  nsCSSFontFaceRule* rule = aFontFace->GetRule();
-  aFontFace->DisconnectFromRule();
-  mRuleFaceMap.Remove(rule);
-}
-
-void
 FontFaceSet::DestroyUserFontSet()
 {
   Disconnect();
   mDocument = nullptr;
   mPresContext = nullptr;
   mLoaders.EnumerateEntries(DestroyIterator, nullptr);
   for (size_t i = 0; i < mRuleFaces.Length(); i++) {
-    DisconnectFromRule(mRuleFaces[i].mFontFace);
+    mRuleFaces[i].mFontFace->DisconnectFromRule();
     mRuleFaces[i].mFontFace->SetUserFontEntry(nullptr);
   }
   for (size_t i = 0; i < mNonRuleFaces.Length(); i++) {
     mNonRuleFaces[i]->SetUserFontEntry(nullptr);
   }
   for (size_t i = 0; i < mUnavailableFaces.Length(); i++) {
     mUnavailableFaces[i]->SetUserFontEntry(nullptr);
   }
@@ -442,18 +434,32 @@ FontFaceSet::StartLoad(gfxUserFontEntry*
       aFontFaceSrc->mReferrer->GetSpec(referrerURI);
     LOG(("fontdownloader (%p) download start - font uri: (%s) "
          "referrer uri: (%s)\n",
          fontLoader.get(), fontURI.get(), referrerURI.get()));
   }
 #endif
 
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
-  if (httpChannel)
+  if (httpChannel) {
     httpChannel->SetReferrer(aFontFaceSrc->mReferrer);
+    nsAutoCString accept("application/font-woff;q=0.9,*/*;q=0.8");
+    if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED)) {
+      accept.Insert(NS_LITERAL_CSTRING("application/font-woff2;q=1.0,"), 0);
+    }
+    httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
+                                  accept, false);
+    // For WOFF and WOFF2, we should tell servers/proxies/etc NOT to try
+    // and apply additional compression at the content-encoding layer
+    if (aFontFaceSrc->mFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF |
+                                      gfxUserFontSet::FLAG_FORMAT_WOFF2)) {
+      httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept-Encoding"),
+                                    NS_LITERAL_CSTRING("identity"), false);
+    }
+  }
   nsCOMPtr<nsISupportsPriority> priorityChannel(do_QueryInterface(channel));
   if (priorityChannel) {
     priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGH);
   }
 
   rv = NS_NewStreamLoader(getter_AddRefs(streamLoader), fontLoader);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -511,16 +517,26 @@ FontFaceSet::UpdateRules(const nsTArray<
 {
   MOZ_ASSERT(mUserFontSet);
 
   // If there was a change to the mNonRuleFaces array, then there could
   // have been a modification to the user font set.
   bool modified = mNonRuleFacesDirty;
   mNonRuleFacesDirty = false;
 
+  // reuse existing FontFace objects mapped to rules already
+  nsDataHashtable<nsPtrHashKey<nsCSSFontFaceRule>, FontFace*> ruleFaceMap;
+  for (size_t i = 0, i_end = mRuleFaces.Length(); i < i_end; ++i) {
+    FontFace* f = mRuleFaces[i].mFontFace;
+    if (!f) {
+      continue;
+    }
+    ruleFaceMap.Put(f->GetRule(), f);
+  }
+
   // The @font-face rules that make up the user font set have changed,
   // so we need to update the set. However, we want to preserve existing
   // font entries wherever possible, so that we don't discard and then
   // re-download resources in the (common) case where at least some of the
   // same rules are still present.
 
   nsTArray<FontFaceRecord> oldRecords;
   mRuleFaces.SwapElements(oldRecords);
@@ -541,19 +557,22 @@ FontFaceSet::UpdateRules(const nsTArray<
   for (size_t i = 0, i_end = aRules.Length(); i < i_end; ++i) {
     // Insert each FontFace objects for each rule into our list, migrating old
     // font entries if possible rather than creating new ones; set  modified  to
     // true if we detect that rule ordering has changed, or if a new entry is
     // created.
     if (handledRules.Contains(aRules[i].mRule)) {
       continue;
     }
-    InsertRuleFontFace(FontFaceForRule(aRules[i].mRule),
-                       aRules[i].mSheetType, oldRecords,
-                       modified);
+    nsCSSFontFaceRule* rule = aRules[i].mRule;
+    nsRefPtr<FontFace> f = ruleFaceMap.Get(rule);
+    if (!f.get()) {
+      f = FontFace::CreateForRule(GetParentObject(), mPresContext, rule);
+    }
+    InsertRuleFontFace(f, aRules[i].mSheetType, oldRecords, modified);
     handledRules.PutEntry(aRules[i].mRule);
   }
 
   for (size_t i = 0, i_end = mNonRuleFaces.Length(); i < i_end; ++i) {
     // Do the same for the non rule backed FontFace objects.
     InsertNonRuleFontFace(mNonRuleFaces[i], modified);
   }
 
@@ -587,17 +606,17 @@ FontFaceSet::UpdateRules(const nsTArray<
         }
       }
 
       // Any left over FontFace objects should also cease being rule backed.
       MOZ_ASSERT(!mUnavailableFaces.Contains(f),
                  "FontFace should not occur in mUnavailableFaces twice");
 
       mUnavailableFaces.AppendElement(f);
-      DisconnectFromRule(f);
+      f->DisconnectFromRule();
     }
   }
 
   if (modified) {
     IncrementGeneration(true);
     mHasLoadingFontFacesIsDirty = true;
     CheckLoadingStarted();
     CheckLoadingFinished();
@@ -980,26 +999,16 @@ FontFaceSet::FindRuleForUserFontEntry(gf
     FontFace* f = mRuleFaces[i].mFontFace;
     if (f->GetUserFontEntry() == aUserFontEntry) {
       return f->GetRule();
     }
   }
   return nullptr;
 }
 
-gfxUserFontEntry*
-FontFaceSet::FindUserFontEntryForRule(nsCSSFontFaceRule* aRule)
-{
-  FontFace* f = mRuleFaceMap.Get(aRule);
-  if (f) {
-    return f->GetUserFontEntry();
-  }
-  return nullptr;
-}
-
 nsresult
 FontFaceSet::LogMessage(gfxUserFontEntry* aUserFontEntry,
                         const char* aMessage,
                         uint32_t aFlags,
                         nsresult aStatus)
 {
   nsCOMPtr<nsIConsoleService>
     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
@@ -1265,39 +1274,16 @@ FontFaceSet::DoRebuildUserFontSet()
     // this font-set, which means it is in the process of being torn down --
     // so there's no point trying to update its rules.
     return;
   }
 
   mPresContext->RebuildUserFontSet();
 }
 
-FontFace*
-FontFaceSet::FontFaceForRule(nsCSSFontFaceRule* aRule)
-{
-  MOZ_ASSERT(aRule);
-
-  FontFace* f = mRuleFaceMap.Get(aRule);
-  if (f) {
-    MOZ_ASSERT(f->GetFontFaceSet() == this,
-               "existing FontFace is from another FontFaceSet?");
-    return f;
-  }
-
-  // We might be creating a FontFace object for an @font-face rule that we are
-  // just about to create a user font entry for, so entry might be null.
-  gfxUserFontEntry* entry = FindUserFontEntryForRule(aRule);
-  nsRefPtr<FontFace> newFontFace =
-    FontFace::CreateForRule(GetParentObject(), mPresContext, aRule, entry);
-  MOZ_ASSERT(newFontFace->GetFontFaceSet() == this,
-             "new FontFace is from another FontFaceSet?");
-  mRuleFaceMap.Put(aRule, newFontFace);
-  return newFontFace;
-}
-
 void
 FontFaceSet::AddUnavailableFontFace(FontFace* aFontFace)
 {
   MOZ_ASSERT(!aFontFace->HasRule());
   MOZ_ASSERT(!aFontFace->IsInFontFaceSet());
   MOZ_ASSERT(!mUnavailableFaces.Contains(aFontFace));
 
   mUnavailableFaces.AppendElement(aFontFace);
--- a/layout/style/FontFaceSet.h
+++ b/layout/style/FontFaceSet.h
@@ -192,22 +192,16 @@ private:
   bool HasAvailableFontFace(FontFace* aFontFace);
 
   /**
    * Removes any listeners and observers.
    */
   void Disconnect();
 
   /**
-   * Calls DisconnectFromRule on the given FontFace and removes its entry from
-   * mRuleFaceMap.
-   */
-  void DisconnectFromRule(FontFace* aFontFace);
-
-  /**
    * Returns whether there might be any pending font loads, which should cause
    * the mReady Promise not to be resolved yet.
    */
   bool MightHavePendingFontLoads();
 
   /**
    * Checks to see whether it is time to replace mReady and dispatch a
    * "loading" event.
@@ -230,29 +224,24 @@ private:
   // Note: if you add new cycle collected objects to FontFaceRecord,
   // make sure to update FontFaceSet's cycle collection macros
   // accordingly.
   struct FontFaceRecord {
     nsRefPtr<FontFace> mFontFace;
     uint8_t mSheetType;
   };
 
-  FontFace* FontFaceForRule(nsCSSFontFaceRule* aRule);
-
   already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntryFromFontFace(
                                                    const nsAString& aFamilyName,
                                                    FontFace* aFontFace,
                                                    uint8_t aSheetType);
 
   // search for @font-face rule that matches a userfont font entry
   nsCSSFontFaceRule* FindRuleForUserFontEntry(gfxUserFontEntry* aUserFontEntry);
 
-  // search for user font entry for the given @font-face rule
-  gfxUserFontEntry* FindUserFontEntryForRule(nsCSSFontFaceRule* aRule);
-
   nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
                      const gfxFontFaceSrc* aFontFaceSrc);
   nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
                          nsIPrincipal** aPrincipal,
                          bool* aBypassCache);
   bool GetPrivateBrowsing();
   nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
                             const gfxFontFaceSrc* aFontFaceSrc,
@@ -306,23 +295,16 @@ private:
   // The non rule backed FontFace objects that have been added to this
   // FontFaceSet and their corresponding user font entries.
   nsTArray<nsRefPtr<FontFace>> mNonRuleFaces;
 
   // The non rule backed FontFace objects that have not been added to
   // this FontFaceSet.
   nsTArray<FontFace*> mUnavailableFaces;
 
-  // Map of nsCSSFontFaceRule objects to FontFace objects.  We hold a weak
-  // reference to both; for actively used FontFaces, mRuleFaces will hold
-  // a strong reference to the FontFace and the FontFace will hold on to
-  // the nsCSSFontFaceRule.  FontFaceSet::DisconnectFromRule will ensure its
-  // entry in this array will be removed.
-  nsDataHashtable<nsPtrHashKey<nsCSSFontFaceRule>, FontFace*> mRuleFaceMap;
-
   // The overall status of the loading or loaded fonts in the FontFaceSet.
   mozilla::dom::FontFaceSetLoadStatus mStatus;
 
   // Whether mNonRuleFaces has changed since last time UpdateRules ran.
   bool mNonRuleFacesDirty;
 
   // Whether we have called MaybeResolve() on mReady.
   bool mReadyIsResolved;
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -1711,25 +1711,23 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSFont
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsCSSFontFaceRule)
   // Trace the wrapper for our declaration.  This just expands out
   // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
   // directly because the wrapper is on the declaration, not on us.
   tmp->mDecl.TraceWrapper(aCallbacks, aClosure);
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSFontFaceRule)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFace)
   // Unlink the wrapper for our declaraton.  This just expands out
   // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
   // directly because the wrapper is on the declaration, not on us.
   tmp->mDecl.ReleaseWrapper(static_cast<nsISupports*>(p));
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSFontFaceRule)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFace)
   // NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS will call into our
   // Trace hook, where we do the right thing with declarations already.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 DOMCI_DATA(CSSFontFaceRule, nsCSSFontFaceRule)
 
 // QueryInterface implementation for nsCSSFontFaceRule
--- a/layout/style/nsCSSRules.h
+++ b/layout/style/nsCSSRules.h
@@ -267,29 +267,22 @@ public:
   // nsIDOMCSSFontFaceRule interface
   NS_DECL_NSIDOMCSSFONTFACERULE
 
   void SetDesc(nsCSSFontDesc aDescID, nsCSSValue const & aValue);
   void GetDesc(nsCSSFontDesc aDescID, nsCSSValue & aValue);
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
 
-  mozilla::dom::FontFace* GetFontFace() const { return mFontFace; }
-  void SetFontFace(mozilla::dom::FontFace* aFontFace) { mFontFace = aFontFace; }
-
   void GetDescriptors(mozilla::CSSFontFaceDescriptors& aDescriptors) const
     { aDescriptors = mDecl.mDescriptors; }
 
 protected:
   ~nsCSSFontFaceRule() {}
 
-  // The CSS-connected FontFace object reflecting this @font-face rule, if one
-  // has been created.
-  nsRefPtr<mozilla::dom::FontFace> mFontFace;
-
   friend class nsCSSFontFaceStyleDecl;
   nsCSSFontFaceStyleDecl mDecl;
 };
 
 // nsFontFaceRuleContainer - used for associating sheet type with
 // specific @font-face rules
 struct nsFontFaceRuleContainer {
   nsRefPtr<nsCSSFontFaceRule> mRule;
--- a/layout/tools/reftest/Makefile.in
+++ b/layout/tools/reftest/Makefile.in
@@ -77,14 +77,15 @@ copy-harness: $(_HARNESS_FILES) $(addpre
 	(cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - reftest) | (cd $(_DEST_DIR) && tar -xf -)
 
 PKG_STAGE = $(DIST)/test-stage
 
 # stage harness and tests for packaging
 stage-package:
 	$(NSINSTALL) -D $(PKG_STAGE)/reftest && $(NSINSTALL) -D $(PKG_STAGE)/reftest/tests
 	(cd $(DEPTH)/_tests/reftest/ && tar $(TAR_CREATE_FLAGS) - *) | (cd $(PKG_STAGE)/reftest && tar -xf -)
+	@cp $(DEPTH)/mozinfo.json $(PKG_STAGE)/reftest
 	$(PYTHON) $(topsrcdir)/layout/tools/reftest/print-manifest-dirs.py \
           $(topsrcdir) \
           $(topsrcdir)/layout/reftests/reftest.list \
           $(topsrcdir)/testing/crashtest/crashtests.list \
           | (cd $(topsrcdir) && xargs tar $(TAR_CREATE_FLAGS) -) \
           | (cd $(PKG_STAGE)/reftest/tests && tar -xf -)
--- a/layout/tools/reftest/b2g_desktop.py
+++ b/layout/tools/reftest/b2g_desktop.py
@@ -165,12 +165,15 @@ def run_desktop_reftests(parser, options
     if options == None:
         sys.exit(1)
 
     # add a -bin suffix if b2g-bin exists, but just b2g was specified
     if options.app[-4:] != '-bin':
         if os.path.isfile("%s-bin" % options.app):
             options.app = "%s-bin" % options.app
 
+    if options.xrePath is None:
+        options.xrePath = os.path.dirname(options.app)
+
     if options.desktop and not options.profile:
         raise Exception("must specify --profile when specifying --desktop")
 
     sys.exit(reftest.run_tests(args[0], options))
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -16,17 +16,18 @@ from runreftest import ReftestOptions
 from automation import Automation
 import devicemanager
 import droid
 import moznetwork
 from remoteautomation import RemoteAutomation, fennecLogcatFilters
 
 class RemoteOptions(ReftestOptions):
     def __init__(self, automation):
-        ReftestOptions.__init__(self, automation)
+        ReftestOptions.__init__(self)
+        self.automation = automation
 
         defaults = {}
         defaults["logFile"] = "reftest.log"
         # app, xrePath and utilityPath variables are set in main function
         defaults["app"] = ""
         defaults["xrePath"] = ""
         defaults["utilityPath"] = ""
         defaults["runTestsInParallel"] = False
@@ -250,17 +251,18 @@ class ReftestServer:
                     self._process.terminate()
             except:
                 self._process.kill()
 
 class RemoteReftest(RefTest):
     remoteApp = ''
 
     def __init__(self, automation, devicemanager, options, scriptDir):
-        RefTest.__init__(self, automation)
+        RefTest.__init__(self)
+        self.automation = automation
         self._devicemanager = devicemanager
         self.scriptDir = scriptDir
         self.remoteApp = options.app
         self.remoteProfile = options.remoteProfile
         self.remoteTestRoot = options.remoteTestRoot
         self.remoteLogFile = options.remoteLogFile
         self.localLogName = options.localLogName
         self.pidFile = options.pidFile
@@ -402,16 +404,33 @@ class RemoteReftest(RefTest):
             if printLogcat:
                 logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
                 print ''.join(logcat)
             print "Device info: %s" % self._devicemanager.getInfo()
             print "Test root: %s" % self._devicemanager.deviceRoot
         except devicemanager.DMError:
             print "WARNING: Error getting device information"
 
+    def environment(self, **kwargs):
+     return self.automation.environment(**kwargs)
+
+    def runApp(self, profile, binary, cmdargs, env,
+               timeout=None, debuggerInfo=None,
+               symbolsPath=None, options=None):
+        status = self.automation.runApp(None, env,
+                                        binary,
+                                        profile.profile,
+                                        cmdargs,
+