Merge m-c to fx-team a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 21 Jan 2015 16:28:27 -0800
changeset 225013 1ccb6100d2bdb60cec0d49b89665353f1af3a3c0
parent 225012 69c75b3dc3d0c6235e8ddedfc3a3c7e0e2c1012f (current diff)
parent 224982 34e2d2bd7ec44a260350c2c8ec574ef6cb8b367d (diff)
child 225014 1b46ee0690967791c7dffbebd85d98885b203dec
push idunknown
push userunknown
push dateunknown
reviewersmerge
milestone38.0a1
Merge m-c to fx-team a=merge
xpcom/tests/TestPipes.cpp
xpcom/tests/TestPriorityQueue.cpp
xpcom/tests/TestStorageStream.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,10 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1100184 - Lots of file moves from the /netwerk flattening and zero faith
-in the build system to properly handle them.
+Bug 1115998 - (DOMString or sequence<DOMString>) needs binding flush (Bug 1103153)
--- a/accessible/base/RelationType.h
+++ b/accessible/base/RelationType.h
@@ -7,17 +7,17 @@
 #ifndef mozilla_a11y_relationtype_h_
 #define mozilla_a11y_relationtype_h_
 
 #include "mozilla/TypedEnum.h"
 
 namespace mozilla {
 namespace a11y {
 
-MOZ_BEGIN_ENUM_CLASS(RelationType)
+enum class RelationType {
 
   /**
    * This object is labelled by a target object.
    */
   LABELLED_BY = 0x00,
 
   /**
    * This object is label for a target object.
@@ -126,14 +126,14 @@ MOZ_BEGIN_ENUM_CLASS(RelationType)
 
   /**
    * The target object is the containing application object.
    */
   CONTAINING_APPLICATION = 0x14,
 
   LAST = CONTAINING_APPLICATION
 
-MOZ_END_ENUM_CLASS(RelationType)
+};
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <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="fe91ec3af5396edab45b15e546e21613785724b5"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <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="fe91ec3af5396edab45b15e546e21613785724b5"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e06971db7acf7a35c32eb74d675a4e12e288e6be">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <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="fe91ec3af5396edab45b15e546e21613785724b5"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "e45c5dbdcfc2d598c889dfbea72fa11157422afe", 
+        "git_revision": "917b6c36717fddc6e71ffc1ec249633c8044c93c", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "ecc956a2747963c2db6edf513cd3a8a75ca8884a", 
+    "revision": "3033c2214b5863d8ac50d2067b34c5cb02fb054d", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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" remote="b2g" revision="1a2a32eda22ef2cd18f57f423a5e7b22a105a6f8"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <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="e45c5dbdcfc2d598c889dfbea72fa11157422afe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="917b6c36717fddc6e71ffc1ec249633c8044c93c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="fe91ec3af5396edab45b15e546e21613785724b5"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/test/general/browser_windowactivation.js
+++ b/browser/base/content/test/general/browser_windowactivation.js
@@ -79,16 +79,24 @@ function test() {
 
   window.messageManager.addMessageListener("Test:FocusReceived", function(message) {
     // No color change should occur after a tab switch.
     if (colorChangeNotifications == 6) {
       sendGetBackgroundRequest(false);
     }
   });
 
+  window.messageManager.addMessageListener("Test:ActivateEvent", function(message) {
+    ok(message.data.ok, "Test:ActivateEvent");
+  });
+
+  window.messageManager.addMessageListener("Test:DeactivateEvent", function(message) {
+    ok(message.data.ok, "Test:DeactivateEvent");
+  });
+
   browser1.addEventListener("load", check, true);
   browser2.addEventListener("load", check, true);
   browser1.contentWindow.location = testPage;
   browser2.contentWindow.location = testPage;
 
   browser1.messageManager.loadFrameScript("data:,(" + childFunction.toString() + ")();", true);
   browser2.messageManager.loadFrameScript("data:,(" + childFunction.toString() + ")();", true);
 
@@ -127,16 +135,35 @@ function childFunction()
     expectingResponse = true;
     ifChanged = message.data.ifChanged;
   });
 
   content.addEventListener("focus", function () {
     sendAsyncMessage("Test:FocusReceived", { });
   }, false);
 
+  var windowGotActivate = false;
+  var windowGotDeactivate = false;
+  addEventListener("activate", function() {
+      sendAsyncMessage("Test:ActivateEvent", { ok: !windowGotActivate });
+      windowGotActivate = false;
+    });
+  
+  addEventListener("deactivate", function() {
+      sendAsyncMessage("Test:DeactivateEvent", { ok: !windowGotDeactivate });
+      windowGotDeactivate = false;
+    });
+  content.addEventListener("activate", function() {
+      windowGotActivate = true;;
+    });
+  
+  content.addEventListener("deactivate", function() {
+      windowGotDeactivate = true;
+    });
+
   content.setInterval(function () {
     if (!expectingResponse) {
       return;
     }
 
     let area = content.document.getElementById("area");
     if (!area) {
       return; /* hasn't loaded yet */
--- a/browser/base/content/test/social/browser.ini
+++ b/browser/base/content/test/social/browser.ini
@@ -26,16 +26,17 @@ support-files =
   social_worker.js
   unchecked.jpg
 
 [browser_aboutHome_activation.js]
 skip-if = e10s # Bug 1053965 "cw.ensureSnippetsMapThen is not a function", also see general/browser.ini about:home comments
 [browser_addons.js]
 [browser_blocklist.js]
 [browser_share.js]
+skip-if = true # bug 1115131
 [browser_social_activation.js]
 skip-if = e10s # Bug 933103 synthesizeMouseAtCenter not e10s friendly
 [browser_social_chatwindow.js]
 [browser_social_chatwindow_resize.js]
 [browser_social_chatwindowfocus.js]
 skip-if = e10s # tab crash on data url used in this test
 [browser_social_contextmenu.js]
 skip-if = e10s # Bug 1072669 context menu relies on target element
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3615,24 +3615,26 @@ nsContentUtils::DispatchUntrustedEvent(n
                        false, aDefaultAction);
 }
 
 // static
 nsresult
 nsContentUtils::DispatchEvent(nsIDocument* aDoc, nsISupports* aTarget,
                               const nsAString& aEventName,
                               bool aCanBubble, bool aCancelable,
-                              bool aTrusted, bool *aDefaultAction)
+                              bool aTrusted, bool *aDefaultAction,
+                              bool aOnlyChromeDispatch)
 {
   nsCOMPtr<nsIDOMEvent> event;
   nsCOMPtr<EventTarget> target;
   nsresult rv = GetEventAndTarget(aDoc, aTarget, aEventName, aCanBubble,
                                   aCancelable, aTrusted, getter_AddRefs(event),
                                   getter_AddRefs(target));
   NS_ENSURE_SUCCESS(rv, rv);
+  event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = aOnlyChromeDispatch;
 
   bool dummy;
   return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
 }
 
 nsresult
 nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
                                     nsISupports *aTarget,
@@ -3659,16 +3661,27 @@ nsContentUtils::DispatchChromeEvent(nsID
   nsEventStatus status = nsEventStatus_eIgnore;
   rv = piTarget->DispatchDOMEvent(nullptr, event, nullptr, &status);
   if (aDefaultAction) {
     *aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
   }
   return rv;
 }
 
+nsresult
+nsContentUtils::DispatchEventOnlyToChrome(nsIDocument* aDoc,
+                                          nsISupports* aTarget,
+                                          const nsAString& aEventName,
+                                          bool aCanBubble, bool aCancelable,
+                                          bool* aDefaultAction)
+{
+  return DispatchEvent(aDoc, aTarget, aEventName, aCanBubble, aCancelable,
+                       true, aDefaultAction, true);
+}
+
 /* static */
 Element*
 nsContentUtils::MatchElementId(nsIContent *aContent, const nsIAtom* aId)
 {
   for (nsIContent* cur = aContent;
        cur;
        cur = cur->GetNextNode(aContent)) {
     if (aId == cur->GetID()) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -982,17 +982,20 @@ public:
                                          nsISupports* aTarget,
                                          const nsAString& aEventName,
                                          bool aCanBubble,
                                          bool aCancelable,
                                          bool *aDefaultAction = nullptr);
 
   /**
    * This method creates and dispatches a trusted event to the chrome
-   * event handler.
+   * event handler (the parent object of the DOM Window in the event target
+   * chain). Note, chrome event handler is used even if aTarget is a chrome
+   * object. Use DispatchEventOnlyToChrome if the normal event dispatching is
+   * wanted in case aTarget is a chrome object.
    * Works only with events which can be created by calling
    * nsIDOMDocument::CreateEvent() with parameter "Events".
    * @param aDocument      The document which will be used to create the event,
    *                       and whose window's chrome handler will be used to
    *                       dispatch the event.
    * @param aTarget        The target of the event, used for event->SetTarget()
    * @param aEventName     The name of the event.
    * @param aCanBubble     Whether the event can bubble.
@@ -1002,16 +1005,42 @@ public:
    */
   static nsresult DispatchChromeEvent(nsIDocument* aDoc,
                                       nsISupports* aTarget,
                                       const nsAString& aEventName,
                                       bool aCanBubble,
                                       bool aCancelable,
                                       bool *aDefaultAction = nullptr);
 
+
+  /**
+   * This method creates and dispatches a trusted event.
+   * If aTarget is not a chrome object, the nearest chrome object in the
+   * propagation path will be used as the start of the event target chain.
+   * This method is different than DispatchChromeEvent, which always dispatches
+   * events to chrome event handler. DispatchEventOnlyToChrome works like
+   * DispatchTrustedEvent in the case aTarget is a chrome object.
+   * Works only with events which can be created by calling
+   * nsIDOMDocument::CreateEvent() with parameter "Events".
+   * @param aDoc           The document which will be used to create the event.
+   * @param aTarget        The target of the event, should be QIable to
+   *                       nsIDOMEventTarget.
+   * @param aEventName     The name of the event.
+   * @param aCanBubble     Whether the event can bubble.
+   * @param aCancelable    Is the event cancelable.
+   * @param aDefaultAction Set to true if default action should be taken,
+   *                       see nsIDOMEventTarget::DispatchEvent.
+   */
+  static nsresult DispatchEventOnlyToChrome(nsIDocument* aDoc,
+                                            nsISupports* aTarget,
+                                            const nsAString& aEventName,
+                                            bool aCanBubble,
+                                            bool aCancelable,
+                                            bool *aDefaultAction = nullptr);
+
   /**
    * Determines if an event attribute name (such as onclick) is valid for
    * a given element type. Types are from the EventNameType enumeration
    * defined above.
    *
    * @param aName the event name to look up
    * @param aType the type of content
    */
@@ -1247,17 +1276,17 @@ public:
 
   /**
    * Utility method that checks if a given node has any non-empty children. This
    * method does not descend recursively into children by default.
    *
    * @param aDiscoverMode Set to eRecurseIntoChildren to descend recursively
    * into children.
    */
-  enum TextContentDiscoverMode MOZ_ENUM_TYPE(uint8_t) {
+  enum TextContentDiscoverMode : uint8_t {
     eRecurseIntoChildren, eDontRecurseIntoChildren
   };
 
   static bool HasNonEmptyTextContent(
     nsINode* aNode,
     TextContentDiscoverMode aDiscoverMode = eDontRecurseIntoChildren);
 
   /**
@@ -2041,17 +2070,17 @@ public:
    * NOTE: the caller has to make sure autocomplete makes sense for the
    * element's type.
    *
    * @param aInput the input element to check. NOTE: aInput can't be null.
    * @return whether the input element has autocomplete enabled.
    */
   static bool IsAutocompleteEnabled(nsIDOMHTMLInputElement* aInput);
 
-  enum AutocompleteAttrState MOZ_ENUM_TYPE(uint8_t)
+  enum AutocompleteAttrState : uint8_t
   {
     eAutocompleteAttrState_Unknown = 1,
     eAutocompleteAttrState_Invalid,
     eAutocompleteAttrState_Valid,
   };
   /**
    * Parses the value of the autocomplete attribute into aResult, ensuring it's
    * composed of valid tokens, otherwise the value "" is used.
@@ -2248,17 +2277,18 @@ private:
                              bool aAllowWrapping);
 
   static nsresult DispatchEvent(nsIDocument* aDoc,
                                 nsISupports* aTarget,
                                 const nsAString& aEventName,
                                 bool aCanBubble,
                                 bool aCancelable,
                                 bool aTrusted,
-                                bool *aDefaultAction = nullptr);
+                                bool *aDefaultAction = nullptr,
+                                bool aOnlyChromeDispatch = false);
 
   static void InitializeModifierStrings();
 
   static void DropFragmentParsers();
 
   static bool MatchClassNames(nsIContent* aContent, int32_t aNamespaceID,
                               nsIAtom* aAtom, void* aData);
   static void DestroyClassNameArray(void* aData);
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1140,21 +1140,22 @@ nsFocusManager::ActivateOrDeactivate(nsP
     return;
   }
 
   // Inform the DOM window that it has activated or deactivated, so that
   // the active attribute is updated on the window.
   aWindow->ActivateOrDeactivate(aActive);
 
   // Send the activate event.
-  nsContentUtils::DispatchTrustedEvent(aWindow->GetExtantDoc(),
-                                       aWindow,
-                                       aActive ? NS_LITERAL_STRING("activate") :
-                                                 NS_LITERAL_STRING("deactivate"),
-                                       true, true, nullptr);
+  nsContentUtils::DispatchEventOnlyToChrome(aWindow->GetExtantDoc(),
+                                            aWindow,
+                                            aActive ?
+                                              NS_LITERAL_STRING("activate") :
+                                              NS_LITERAL_STRING("deactivate"),
+                                            true, true, nullptr);
 
   // Look for any remote child frames, iterate over them and send the activation notification.
   nsContentUtils::CallOnAllRemoteChildren(aWindow, ActivateOrDeactivateChild,
                                           (void *)aActive);
 }
 
 void
 nsFocusManager::SetFocusInner(nsIContent* aNewContent, int32_t aFlags,
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -456,17 +456,17 @@ GetWrapperCache(void* p)
 // GetWrappeCache(void*) and GetWrapperCache(const ParentObject&).
 template <template <typename> class SmartPtr, typename T>
 inline nsWrapperCache*
 GetWrapperCache(const SmartPtr<T>& aObject)
 {
   return GetWrapperCache(aObject.get());
 }
 
-struct ParentObject {
+struct MOZ_STACK_CLASS ParentObject {
   template<class T>
   ParentObject(T* aObject) :
     mObject(aObject),
     mWrapperCache(GetWrapperCache(aObject)),
     mUseXBLScope(false)
   {}
 
   template<class T, template<typename> class SmartPtr>
@@ -477,17 +477,19 @@ struct ParentObject {
   {}
 
   ParentObject(nsISupports* aObject, nsWrapperCache* aCache) :
     mObject(aObject),
     mWrapperCache(aCache),
     mUseXBLScope(false)
   {}
 
-  nsISupports* const mObject;
+  // We don't want to make this an nsCOMPtr because of performance reasons, but
+  // it's safe because ParentObject is a stack class.
+  nsISupports* const MOZ_NON_OWNING_REF mObject;
   nsWrapperCache* const mWrapperCache;
   bool mUseXBLScope;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_BindingDeclarations_h__
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -182,17 +182,17 @@ public:
   PostMessageRunnable(BroadcastChannelChild* aActor,
                       BroadcastChannelMessage* aData)
     : mActor(aActor)
     , mData(aData)
   {
     MOZ_ASSERT(mActor);
   }
 
-  NS_IMETHODIMP Run()
+  NS_IMETHODIMP Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(mActor);
     if (mActor->IsActorDestroyed()) {
       return NS_OK;
     }
 
     ClonedMessageData message;
 
@@ -216,17 +216,17 @@ public:
         message.blobsChild().AppendElement(blobChild);
       }
     }
 
     mActor->SendPostMessage(message);
     return NS_OK;
   }
 
-  NS_IMETHODIMP Cancel()
+  NS_IMETHODIMP Cancel() MOZ_OVERRIDE
   {
     mActor = nullptr;
     return NS_OK;
   }
 
 private:
   ~PostMessageRunnable() {}
 
@@ -242,23 +242,23 @@ public:
   NS_DECL_ISUPPORTS
 
   explicit CloseRunnable(BroadcastChannel* aBC)
     : mBC(aBC)
   {
     MOZ_ASSERT(mBC);
   }
 
-  NS_IMETHODIMP Run()
+  NS_IMETHODIMP Run() MOZ_OVERRIDE
   {
     mBC->Shutdown();
     return NS_OK;
   }
 
-  NS_IMETHODIMP Cancel()
+  NS_IMETHODIMP Cancel() MOZ_OVERRIDE
   {
     mBC = nullptr;
     return NS_OK;
   }
 
 private:
   ~CloseRunnable() {}
 
@@ -273,26 +273,26 @@ public:
   NS_DECL_ISUPPORTS
 
   explicit TeardownRunnable(BroadcastChannelChild* aActor)
     : mActor(aActor)
   {
     MOZ_ASSERT(mActor);
   }
 
-  NS_IMETHODIMP Run()
+  NS_IMETHODIMP Run() MOZ_OVERRIDE
   {
     MOZ_ASSERT(mActor);
     if (!mActor->IsActorDestroyed()) {
       mActor->SendClose();
     }
     return NS_OK;
   }
 
-  NS_IMETHODIMP Cancel()
+  NS_IMETHODIMP Cancel() MOZ_OVERRIDE
   {
     mActor = nullptr;
     return NS_OK;
   }
 
 private:
   ~TeardownRunnable() {}
 
--- a/dom/broadcastchannel/BroadcastChannelChild.h
+++ b/dom/broadcastchannel/BroadcastChannelChild.h
@@ -37,17 +37,17 @@ public:
   }
 
 private:
   BroadcastChannelChild(const nsAString& aOrigin,
                         const nsAString& aChannel);
 
   ~BroadcastChannelChild();
 
-  void ActorDestroy(ActorDestroyReason aWhy);
+  virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   // This raw pointer is actually the parent object.
   // It's set to null when the parent object is deleted.
   BroadcastChannel* mBC;
 
   nsString mOrigin;
   nsString mChannel;
 
--- a/dom/camera/CameraPreferences.cpp
+++ b/dom/camera/CameraPreferences.cpp
@@ -32,29 +32,27 @@ uint32_t CameraPreferences::sPrefCameraC
 bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
 
 #ifdef MOZ_WIDGET_GONK
 StaticRefPtr<CameraPreferences> CameraPreferences::sObserver;
 
 NS_IMPL_ISUPPORTS(CameraPreferences, nsIObserver);
 #endif
 
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
 /* static */
 nsresult
 CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
 {
   uint32_t val;
   nsresult rv = Preferences::GetUint(aPref, &val);
   if (NS_SUCCEEDED(rv)) {
     aVal = static_cast<nsresult>(val);
   }
   return rv;
 }
-#endif
 
 /* static */
 nsresult
 CameraPreferences::UpdatePref(const char* aPref, uint32_t& aVal)
 {
   uint32_t val;
   nsresult rv = Preferences::GetUint(aPref, &val);
   if (NS_SUCCEEDED(rv)) {
@@ -151,26 +149,24 @@ CameraPreferences::PreferenceChanged(con
     DOM_CAMERA_LOGE("Preference '%s' is not tracked by CameraPreferences\n", aPref);
     return;
   }
 
   Pref& p = sPrefs[i];
   nsresult rv;
   switch (p.mValueType) {
     case kPrefValueIsNsResult:
-    #ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
       {
         nsresult& v = *p.mValue.mAsNsResult;
         rv = UpdatePref(aPref, v);
         if (NS_SUCCEEDED(rv)) {
           DOM_CAMERA_LOGI("Preference '%s' has changed, 0x%x\n", aPref, v);
         }
       }
       break;
-    #endif
 
     case kPrefValueIsUint32:
       {
         uint32_t& v = *p.mValue.mAsUint32;
         rv = UpdatePref(aPref, v);
         if (NS_SUCCEEDED(rv)) {
           DOM_CAMERA_LOGI("Preference '%s' has changed, %u\n", aPref, v);
         }
@@ -326,17 +322,16 @@ CameraPreferences::GetPref(const char* a
     return false;
   }
 
   DOM_CAMERA_LOGI("Preference '%s', got '%s'\n", aPref, (*s)->get());
   aVal = **s;
   return true;
 }
 
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
 /* static */
 bool
 CameraPreferences::GetPref(const char* aPref, nsresult& aVal)
 {
   MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
   MonitorAutoLock mon(*sPrefMonitor);
 
   uint32_t i = PrefToIndex(aPref);
@@ -354,17 +349,16 @@ CameraPreferences::GetPref(const char* a
     DOM_CAMERA_LOGW("Preference '%s' is not set\n", aPref);
     return false;
   }
 
   DOM_CAMERA_LOGI("Preference '%s', got 0x%x\n", aPref, v);
   aVal = v;
   return true;
 }
-#endif
 
 /* static */
 bool
 CameraPreferences::GetPref(const char* aPref, uint32_t& aVal)
 {
   MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
   MonitorAutoLock mon(*sPrefMonitor);
 
--- a/dom/camera/CameraPreferences.h
+++ b/dom/camera/CameraPreferences.h
@@ -7,23 +7,16 @@
 #define DOM_CAMERA_CAMERAPREFERENCES_H
 
 #include "nsString.h"
 #include "nsIObserver.h"
 #ifdef MOZ_WIDGET_GONK
 #include "mozilla/StaticPtr.h"
 #endif
 
-#if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) || defined(MOZ_HAVE_CXX11_ENUM_TYPE)
-// Older compilers that don't support strongly-typed enums
-// just typedef uint32_t to nsresult, which results in conflicting
-// overloaded members in CameraPreferences.
-#define CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
-#endif
-
 namespace mozilla {
 
 template<class T> class StaticAutoPtr;
 
 class CameraPreferences
 #ifdef MOZ_WIDGET_GONK
   : public nsIObserver
 #endif
@@ -33,30 +26,26 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 #endif
 
   static bool Initialize();
   static void Shutdown();
 
   static bool GetPref(const char* aPref, nsACString& aVal);
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
   static bool GetPref(const char* aPref, nsresult& aVal);
-#endif
   static bool GetPref(const char* aPref, uint32_t& aVal);
   static bool GetPref(const char* aPref, bool& aVal);
 
 protected:
   static const uint32_t kPrefNotFound = UINT32_MAX;
   static uint32_t PrefToIndex(const char* aPref);
 
   static void PreferenceChanged(const char* aPref, void* aClosure);
-#ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
   static nsresult UpdatePref(const char* aPref, nsresult& aVar);
-#endif
   static nsresult UpdatePref(const char* aPref, uint32_t& aVar);
   static nsresult UpdatePref(const char* aPref, nsACString& aVar);
   static nsresult UpdatePref(const char* aPref, bool& aVar);
 
   enum PrefValueType {
     kPrefValueIsNsResult,
     kPrefValueIsUint32,
     kPrefValueIsCString,
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -157,17 +157,17 @@ class EventListenerManager MOZ_FINAL
 public:
   struct Listener
   {
     EventListenerHolder mListener;
     nsCOMPtr<nsIAtom> mTypeAtom; // for the main thread
     nsString mTypeString; // for non-main-threads
     uint16_t mEventType;
 
-    enum ListenerType MOZ_ENUM_TYPE(uint8_t)
+    enum ListenerType : uint8_t
     {
       eNativeListener = 0,
       eJSEventListener,
       eWrappedJSListener,
       eWebIDLListener,
       eListenerTypeCount
     };
     uint8_t mListenerType;
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -424,17 +424,17 @@ protected:
      * prefs, the overflowDelta values would be inflated.
      * CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation.
      */
     void CancelApplyingUserPrefsFromOverflowDelta(WidgetWheelEvent* aEvent);
 
     /**
      * Computes the default action for the aEvent with the prefs.
      */
-    enum Action MOZ_ENUM_TYPE(uint8_t)
+    enum Action : uint8_t
     {
       ACTION_NONE = 0,
       ACTION_SCROLL,
       ACTION_HISTORY,
       ACTION_ZOOM,
       ACTION_LAST = ACTION_ZOOM
     };
     Action ComputeActionFor(WidgetWheelEvent* aEvent);
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -318,23 +318,34 @@ RTCPeerConnection.prototype = {
   classDescription: "mozRTCPeerConnection",
   classID: PC_CID,
   contractID: PC_CONTRACT,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
   init: function(win) { this._win = win; },
 
   __init: function(rtcConfig) {
+    this._winID = this._win.QueryInterface(Ci.nsIInterfaceRequestor)
+    .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
+
     if (!rtcConfig.iceServers ||
         !Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
       rtcConfig.iceServers =
         JSON.parse(Services.prefs.getCharPref("media.peerconnection.default_iceservers"));
     }
-    this._winID = this._win.QueryInterface(Ci.nsIInterfaceRequestor)
-      .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
+    // Normalize iceServers input
+    rtcConfig.iceServers.forEach(server => {
+      if (typeof server.urls === "string") {
+        server.urls = [server.urls];
+      } else if (!server.urls && server.url) {
+        // TODO: Remove support for legacy iceServer.url eventually (Bug 1116766)
+        server.urls = [server.url];
+        this.logWarning("RTCIceServer.url is deprecated! Use urls instead.", null, 0);
+      }
+    });
     this._mustValidateRTCConfiguration(rtcConfig,
         "RTCPeerConnection constructor passed invalid RTCConfiguration");
     if (_globalPCList._networkdown || !this._win.navigator.onLine) {
       throw new this._win.DOMException(
           "Can't create RTCPeerConnections when the network is down",
           "InvalidStateError");
     }
 
@@ -427,20 +438,21 @@ RTCPeerConnection.prototype = {
         func && func(result);
       } catch (e) {
         this.logErrorAndCallOnError(e);
       }
     };
   },
 
   /**
-   * An RTCConfiguration looks like this:
+   * An RTCConfiguration may look like this:
    *
-   * { "iceServers": [ { url:"stun:stun.example.org" },
-   *                   { url:"turn:turn.example.org",
+   * { "iceServers": [ { urls: "stun:stun.example.org", },
+   *                   { url: "stun:stun.example.org", }, // deprecated version
+   *                   { urls: ["turn:turn1.x.org", "turn:turn2.x.org"],
    *                     username:"jib", credential:"mypass"} ] }
    *
    * WebIDL normalizes structure for us, so we test well-formed stun/turn urls,
    * but not validity of servers themselves, before passing along to C++.
    *
    *   msg - Error message to detail which array-entry failed, if any.
    */
   _mustValidateRTCConfiguration: function(rtcConfig, msg) {
@@ -451,37 +463,39 @@ RTCPeerConnection.prototype = {
         return ios.newURI(uriStr, null, null);
       } catch (e if (e.result == Cr.NS_ERROR_MALFORMED_URI)) {
         throw new this._win.DOMException(msg + " - malformed URI: " + uriStr,
                                          "SyntaxError");
       }
     };
 
     rtcConfig.iceServers.forEach(server => {
-      if (!server.url) {
-        throw new this._win.DOMException(msg + " - missing url", "InvalidAccessError");
+      if (!server.urls) {
+        throw new this._win.DOMException(msg + " - missing urls", "InvalidAccessError");
       }
-      let url = nicerNewURI(server.url);
-      if (url.scheme in { turn:1, turns:1 }) {
-        if (!server.username) {
-          throw new this._win.DOMException(msg + " - missing username: " + server.url,
-                                           "InvalidAccessError");
+      server.urls.forEach(urlStr => {
+        let url = nicerNewURI(urlStr);
+        if (url.scheme in { turn:1, turns:1 }) {
+          if (!server.username) {
+            throw new this._win.DOMException(msg + " - missing username: " + urlStr,
+                                             "InvalidAccessError");
+          }
+          if (!server.credential) {
+            throw new this._win.DOMException(msg + " - missing credential: " + urlStr,
+                                             "InvalidAccessError");
+          }
         }
-        if (!server.credential) {
-          throw new this._win.DOMException(msg + " - missing credential: " + server.url,
-                                           "InvalidAccessError");
+        else if (!(url.scheme in { stun:1, stuns:1 })) {
+          throw new this._win.DOMException(msg + " - improper scheme: " + url.scheme,
+                                           "SyntaxError");
         }
-      }
-      else if (!(url.scheme in { stun:1, stuns:1 })) {
-        throw new this._win.DOMException(msg + " - improper scheme: " + url.scheme,
-                                         "SyntaxError");
-      }
-      if (url.scheme in { stuns:1, turns:1 }) {
-        this.logWarning(url.scheme.toUpperCase() + " is not yet supported.", null, 0);
-      }
+        if (url.scheme in { stuns:1, turns:1 }) {
+          this.logWarning(url.scheme.toUpperCase() + " is not yet supported.", null, 0);
+        }
+      });
     });
   },
 
   // Ideally, this should be of the form _checkState(state),
   // where the state is taken from an enumeration containing
   // the valid peer connection states defined in the WebRTC
   // spec. See Bug 831756.
   _checkClosed: function() {
--- a/dom/media/tests/mochitest/test_peerConnection_bug825703.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug825703.html
@@ -9,87 +9,75 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "825703",
     title: "RTCConfiguration valid/invalid permutations"
   });
 
-  makePC = function (config, expect_success) {
-      var exception = null;
-      var pc = null;
-
-      try {
-          pc = new mozRTCPeerConnection(config);
-      } catch (e) {
-          exception = e;
-      }
-      if (pc !== null) {
-        pc.close();
-      }
-      pc = null
-
-      if (expect_success) {
-          ok(!exception, "mozRTCPeerConnection(" +
-             JSON.stringify(config) + ") succeeds");
-      } else {
-          ok(exception, "mozRTCPeerConnection(" +
-             JSON.stringify(config) + ") throws");
-      }
+  makePC = (config, expected_error) => {
+    var exception;
+    try {
+      new mozRTCPeerConnection(config).close();
+    } catch (e) {
+      exception = e;
+    }
+    is((exception? exception.name : "success"), expected_error || "success",
+       "mozRTCPeerConnection(" + JSON.stringify(config) + ")");
   }
 
   // This is a test of the iceServers parsing code + readable errors
 
   runNetworkTest(function () {
-    var pcs = null;
     var exception = null;
-    var config;
 
     try {
-      pcs = new mozRTCPeerConnection();
+      new mozRTCPeerConnection().close();
     } catch (e) {
       exception = e;
     }
     ok(!exception, "mozRTCPeerConnection() succeeds");
-    if (pcs !== null) {
-      pcs.close();
-    }
-    pcs = null;
     exception = null;
 
-    makePC(1, false);
+    makePC();
 
-    makePC({}, true);
+    makePC(1, "TypeError");
 
-    makePC({ iceServers: [] }, true);
+    makePC({});
 
-    makePC({ iceServers: [{ url:"" }] }, false);
+    makePC({ iceServers: [] });
+
+    makePC({ iceServers: [{ urls:"" }] }, "SyntaxError");
 
     makePC({ iceServers: [
-                { url:"stun:127.0.0.1" },
-                { url:"stuns:localhost", foo:"" },
-                { url:"turn:[::1]:3478", username:"p", credential:"p" },
-                { url:"turns:localhost:3478?transport=udp", username:"p", credential:"p" }
-                ]}, true);
-
-    makePC({ iceServers: [{ url:"turns:localhost:3478", username:"p" }] }, false);
-
-    makePC({ iceServers: [{ url:"turns:localhost:3478", credential:"p" }] }, false);
+      { urls:"stun:127.0.0.1" },
+      { urls:"stun:localhost", foo:"" },
+      { urls: ["stun:127.0.0.1", "stun:localhost"] },
+      { urls:"stuns:localhost", foo:"" },
+      { urls:"turn:[::1]:3478", username:"p", credential:"p" },
+      { urls:"turn:localhost:3478?transport=udp", username:"p", credential:"p" },
+      { urls: ["turn:[::1]:3478", "turn:localhost"], username:"p", credential:"p" },
+      { urls:"turns:localhost:3478?transport=udp", username:"p", credential:"p" },
+      { url:"stun:localhost", foo:"" },
+      { url:"turn:localhost", username:"p", credential:"p" }
+    ]});
 
-    makePC({ iceServers: [{ url:"http:0.0.0.0" }] }, false);
+    makePC({ iceServers: [{ urls: ["stun:127.0.0.1", ""] }] }, "SyntaxError");
+
+    makePC({ iceServers: [{ urls:"turns:localhost:3478", username:"p" }] }, "InvalidAccessError");
+
+    makePC({ iceServers: [{ url:"turns:localhost:3478", credential:"p" }] }, "InvalidAccessError");
+
+    makePC({ iceServers: [{ urls:"http:0.0.0.0" }] }, "SyntaxError");
     try {
-        pcs = new mozRTCPeerConnection({ iceServers: [{ url:"http:0.0.0.0" }] });
+      new mozRTCPeerConnection({ iceServers: [{ url:"http:0.0.0.0" }] }).close();
     } catch (e) {
-        ok(e.message.indexOf("http") > 0,
-           "mozRTCPeerConnection() constructor has readable exceptions");
+      ok(e.message.indexOf("http") > 0,
+         "mozRTCPeerConnection() constructor has readable exceptions");
     }
-    if (pcs !== null) {
-      pcs.close();
-    }
-    pcs = null;
 
     networkTestFinished();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/webaudio/AudioEventTimeline.h
+++ b/dom/media/webaudio/AudioEventTimeline.h
@@ -18,17 +18,17 @@
 #include "WebAudioUtils.h"
 
 namespace mozilla {
 
 namespace dom {
 
 // This is an internal helper class and should not be used outside of this header.
 struct AudioTimelineEvent {
-  enum Type MOZ_ENUM_TYPE(uint32_t) {
+  enum Type : uint32_t {
     SetValue,
     LinearRamp,
     ExponentialRamp,
     SetTarget,
     SetValueCurve
   };
 
   AudioTimelineEvent(Type aType, double aTime, float aValue, double aTimeConstant = 0.0,
--- a/dom/network/NetworkStatsDB.jsm
+++ b/dom/network/NetworkStatsDB.jsm
@@ -43,39 +43,62 @@ NetworkStatsDB.prototype = {
       txnCb(null, result);
     }
     function errorCb(error) {
       txnCb(error, null);
     }
     return this.newTxn(txn_type, store_name, callback, successCb, errorCb);
   },
 
+  /**
+   * The onupgradeneeded handler of the IDBOpenDBRequest.
+   * This function is called in IndexedDBHelper open() method.
+   *
+   * @param {IDBTransaction} aTransaction
+   *        {IDBDatabase} aDb
+   *        {64-bit integer} aOldVersion The version number on local storage.
+   *        {64-bit integer} aNewVersion The version number to be upgraded to.
+   *
+   * @note  Be careful with the database upgrade pattern.
+   *        Because IndexedDB operations are performed asynchronously, we must
+   *        apply a recursive approach instead of an iterative approach while
+   *        upgrading versions.
+   */
   upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
     if (DEBUG) {
       debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
     }
     let db = aDb;
     let objectStore;
-    for (let currVersion = aOldVersion; currVersion < aNewVersion; currVersion++) {
-      if (currVersion == 0) {
-        /**
-         * Create the initial database schema.
-         */
 
+    // An array of upgrade functions for each version.
+    let upgradeSteps = [
+      function upgrade0to1() {
+        if (DEBUG) debug("Upgrade 0 to 1: Create object stores and indexes.");
+
+        // Create the initial database schema.
         objectStore = db.createObjectStore(DEPRECATED_STORE_NAME, { keyPath: ["connectionType", "timestamp"] });
         objectStore.createIndex("connectionType", "connectionType", { unique: false });
         objectStore.createIndex("timestamp", "timestamp", { unique: false });
         objectStore.createIndex("rxBytes", "rxBytes", { unique: false });
         objectStore.createIndex("txBytes", "txBytes", { unique: false });
         objectStore.createIndex("rxTotalBytes", "rxTotalBytes", { unique: false });
         objectStore.createIndex("txTotalBytes", "txTotalBytes", { unique: false });
-        if (DEBUG) {
-          debug("Created object stores and indexes");
-        }
-      } else if (currVersion == 2) {
+
+        upgradeNextVersion();
+      },
+
+      function upgrade1to2() {
+        if (DEBUG) debug("Upgrade 1 to 2: Do nothing.");
+        upgradeNextVersion();
+      },
+
+      function upgrade2to3() {
+        if (DEBUG) debug("Upgrade 2 to 3: Add keyPath appId to object store.");
+
         // In order to support per-app traffic data storage, the original
         // objectStore needs to be replaced by a new objectStore with new
         // key path ("appId") and new index ("appId").
         // Also, since now networks are identified by their
         // [networkId, networkType] not just by their connectionType,
         // to modify the keyPath is mandatory to delete the object store
         // and create it again. Old data is going to be deleted because the
         // networkId for each sample can not be set.
@@ -94,21 +117,23 @@ NetworkStatsDB.prototype = {
         objectStore.createIndex("network", "network", { unique: false });
         objectStore.createIndex("networkType", "networkType", { unique: false });
         objectStore.createIndex("timestamp", "timestamp", { unique: false });
         objectStore.createIndex("rxBytes", "rxBytes", { unique: false });
         objectStore.createIndex("txBytes", "txBytes", { unique: false });
         objectStore.createIndex("rxTotalBytes", "rxTotalBytes", { unique: false });
         objectStore.createIndex("txTotalBytes", "txTotalBytes", { unique: false });
 
-        if (DEBUG) {
-          debug("Created object stores and indexes for version 3");
-        }
-      } else if (currVersion == 3) {
-        // Delete redundent indexes (leave "network" only).
+        upgradeNextVersion();
+      },
+
+      function upgrade3to4() {
+        if (DEBUG) debug("Upgrade 3 to 4: Delete redundant indexes.");
+
+        // Delete redundant indexes (leave "network" only).
         objectStore = aTransaction.objectStore(DEPRECATED_STORE_NAME);
         if (objectStore.indexNames.contains("appId")) {
           objectStore.deleteIndex("appId");
         }
         if (objectStore.indexNames.contains("networkType")) {
           objectStore.deleteIndex("networkType");
         }
         if (objectStore.indexNames.contains("timestamp")) {
@@ -122,32 +147,36 @@ NetworkStatsDB.prototype = {
         }
         if (objectStore.indexNames.contains("rxTotalBytes")) {
           objectStore.deleteIndex("rxTotalBytes");
         }
         if (objectStore.indexNames.contains("txTotalBytes")) {
           objectStore.deleteIndex("txTotalBytes");
         }
 
-        if (DEBUG) {
-          debug("Deleted redundent indexes for version 4");
-        }
-      } else if (currVersion == 4) {
+        upgradeNextVersion();
+      },
+
+      function upgrade4to5() {
+        if (DEBUG) debug("Upgrade 4 to 5: Create object store for alarms.");
+
         // In order to manage alarms, it is necessary to use a global counter
         // (totalBytes) that will increase regardless of the system reboot.
         objectStore = aTransaction.objectStore(DEPRECATED_STORE_NAME);
 
         // Now, systemBytes will hold the old totalBytes and totalBytes will
         // keep the increasing counter. |counters| will keep the track of
         // accumulated values.
         let counters = {};
 
         objectStore.openCursor().onsuccess = function(event) {
           let cursor = event.target.result;
           if (!cursor){
+            // upgrade4to5 completed now.
+            upgradeNextVersion();
             return;
           }
 
           cursor.value.rxSystemBytes = cursor.value.rxTotalBytes;
           cursor.value.txSystemBytes = cursor.value.txTotalBytes;
 
           if (cursor.value.appId == 0) {
             let netId = cursor.value.network[0] + '' + cursor.value.network[1];
@@ -183,50 +212,52 @@ NetworkStatsDB.prototype = {
           cursor.update(cursor.value);
           cursor.continue();
         };
 
         // Create object store for alarms.
         objectStore = db.createObjectStore(ALARMS_STORE_NAME, { keyPath: "id", autoIncrement: true });
         objectStore.createIndex("alarm", ['networkId','threshold'], { unique: false });
         objectStore.createIndex("manifestURL", "manifestURL", { unique: false });
+      },
 
-        if (DEBUG) {
-          debug("Created alarms store for version 5");
-        }
-      } else if (currVersion == 5) {
+      function upgrade5to6() {
+        if (DEBUG) debug("Upgrade 5 to 6: Add keyPath serviceType to object store.");
+
         // In contrast to "per-app" traffic data, "system-only" traffic data
         // refers to data which can not be identified by any applications.
         // To further support "system-only" data storage, the data can be
         // saved by service type (e.g., Tethering, OTA). Thus it's needed to
         // have a new key ("serviceType") for the ojectStore.
         let newObjectStore;
         newObjectStore = db.createObjectStore(STATS_STORE_NAME,
                          { keyPath: ["appId", "serviceType", "network", "timestamp"] });
         newObjectStore.createIndex("network", "network", { unique: false });
 
         // Copy the data from the original objectStore to the new objectStore.
         objectStore = aTransaction.objectStore(DEPRECATED_STORE_NAME);
         objectStore.openCursor().onsuccess = function(event) {
           let cursor = event.target.result;
           if (!cursor) {
             db.deleteObjectStore(DEPRECATED_STORE_NAME);
+            // upgrade5to6 completed now.
+            upgradeNextVersion();
             return;
           }
 
           let newStats = cursor.value;
           newStats.serviceType = "";
           newObjectStore.put(newStats);
           cursor.continue();
         };
+      },
 
-        if (DEBUG) {
-          debug("Added new key 'serviceType' for version 6");
-        }
-      } else if (currVersion == 6) {
+      function upgrade6to7() {
+        if (DEBUG) debug("Upgrade 6 to 7: Replace alarm threshold by relativeThreshold.");
+
         // Replace threshold attribute of alarm index by relativeThreshold in alarms DB.
         // Now alarms are indexed by relativeThreshold, which is the threshold relative
         // to current system stats.
         let alarmsStore = aTransaction.objectStore(ALARMS_STORE_NAME);
 
         // Delete "alarm" index.
         if (alarmsStore.indexNames.contains("alarm")) {
           alarmsStore.deleteIndex("alarm");
@@ -234,96 +265,154 @@ NetworkStatsDB.prototype = {
 
         // Create new "alarm" index.
         alarmsStore.createIndex("alarm", ['networkId','relativeThreshold'], { unique: false });
 
         // Populate new "alarm" index attributes.
         alarmsStore.openCursor().onsuccess = function(event) {
           let cursor = event.target.result;
           if (!cursor) {
+            upgrade6to7_updateTotalBytes();
             return;
           }
 
           cursor.value.relativeThreshold = cursor.value.threshold;
           cursor.value.absoluteThreshold = cursor.value.threshold;
           delete cursor.value.threshold;
 
           cursor.update(cursor.value);
           cursor.continue();
         }
 
-        // Previous versions save accumulative totalBytes, increasing althought the system
-        // reboots or resets stats. But is necessary to reset the total counters when reset
-        // through 'clearInterfaceStats'.
-        let statsStore = aTransaction.objectStore(STATS_STORE_NAME);
-        let networks = [];
-        // Find networks stored in the database.
-        statsStore.index("network").openKeyCursor(null, "nextunique").onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            networks.push(cursor.key);
-            cursor.continue();
-            return;
-          }
+        function upgrade6to7_updateTotalBytes() {
+          if (DEBUG) debug("Upgrade 6 to 7: Update TotalBytes.");
+          // Previous versions save accumulative totalBytes, increasing although the system
+          // reboots or resets stats. But is necessary to reset the total counters when reset
+          // through 'clearInterfaceStats'.
+          let statsStore = aTransaction.objectStore(STATS_STORE_NAME);
+          let networks = [];
+
+          // Find networks stored in the database.
+          statsStore.index("network").openKeyCursor(null, "nextunique").onsuccess = function(event) {
+            let cursor = event.target.result;
+
+            // Store each network into an array.
+            if (cursor) {
+              networks.push(cursor.key);
+              cursor.continue();
+              return;
+            }
+
+            // Start to deal with each network.
+            let pending = networks.length;
 
-          networks.forEach(function(network) {
-            let lowerFilter = [0, "", network, 0];
-            let upperFilter = [0, "", network, ""];
-            let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
+            if (pending === 0) {
+              // Found no records of network. upgrade6to7 completed now.
+              upgradeNextVersion();
+              return;
+            }
+
+            networks.forEach(function(network) {
+              let lowerFilter = [0, "", network, 0];
+              let upperFilter = [0, "", network, ""];
+              let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
 
-            // Find number of samples for a given network.
-            statsStore.count(range).onsuccess = function(event) {
-              // If there are more samples than the max allowed, there is no way to know
-              // when does reset take place.
-              if (event.target.result >= VALUES_MAX_LENGTH) {
-                return;
-              }
+              // Find number of samples for a given network.
+              statsStore.count(range).onsuccess = function(event) {
+                let recordCount = event.target.result;
 
-              let last = null;
-              // Reset detected if the first sample totalCounters are different than bytes
-              // counters. If so, the total counters should be recalculated.
-              statsStore.openCursor(range).onsuccess = function(event) {
-                let cursor = event.target.result;
-                if (!cursor) {
+                // If there are more samples than the max allowed, there is no way to know
+                // when does reset take place.
+                if (recordCount === 0 || recordCount >= VALUES_MAX_LENGTH) {
+                  pending--;
+                  if (pending === 0) {
+                    upgradeNextVersion();
+                  }
                   return;
                 }
-                if (!last) {
-                  if (cursor.value.rxTotalBytes == cursor.value.rxBytes &&
-                      cursor.value.txTotalBytes == cursor.value.txBytes) {
+
+                let last = null;
+                // Reset detected if the first sample totalCounters are different than bytes
+                // counters. If so, the total counters should be recalculated.
+                statsStore.openCursor(range).onsuccess = function(event) {
+                  let cursor = event.target.result;
+                  if (!cursor) {
+                    pending--;
+                    if (pending === 0) {
+                      upgradeNextVersion();
+                    }
+                    return;
+                  }
+                  if (!last) {
+                    if (cursor.value.rxTotalBytes == cursor.value.rxBytes &&
+                        cursor.value.txTotalBytes == cursor.value.txBytes) {
+                      pending--;
+                      if (pending === 0) {
+                        upgradeNextVersion();
+                      }
+                      return;
+                    }
+
+                    cursor.value.rxTotalBytes = cursor.value.rxBytes;
+                    cursor.value.txTotalBytes = cursor.value.txBytes;
+                    cursor.update(cursor.value);
+                    last = cursor.value;
+                    cursor.continue();
                     return;
                   }
 
-                  cursor.value.rxTotalBytes = cursor.value.rxBytes;
-                  cursor.value.txTotalBytes = cursor.value.txBytes;
+                  // Recalculate the total counter for last / current sample
+                  cursor.value.rxTotalBytes = last.rxTotalBytes + cursor.value.rxBytes;
+                  cursor.value.txTotalBytes = last.txTotalBytes + cursor.value.txBytes;
                   cursor.update(cursor.value);
                   last = cursor.value;
                   cursor.continue();
-                  return;
                 }
+              }
+            }, this); // end of networks.forEach()
+          }; // end of statsStore.index("network").openKeyCursor().onsuccess callback
+        } // end of function upgrade6to7_updateTotalBytes
+      },
 
-                // Recalculate the total counter for last / current sample
-                cursor.value.rxTotalBytes = last.rxTotalBytes + cursor.value.rxBytes;
-                cursor.value.txTotalBytes = last.txTotalBytes + cursor.value.txBytes;
-                cursor.update(cursor.value);
-                last = cursor.value;
-                cursor.continue();
-              }
-            }
-          }, this);
-        };
-      } else if (currVersion == 7) {
+      function upgrade7to8() {
+        if (DEBUG) debug("Upgrade 7 to 8: Create index serviceType.");
+
         // Create index for 'ServiceType' in order to make it retrievable.
         let statsStore = aTransaction.objectStore(STATS_STORE_NAME);
         statsStore.createIndex("serviceType", "serviceType", { unique: false });
+      },
+    ];
 
-        if (DEBUG) {
-          debug("Create index of 'serviceType' for version 8");
-        }
+    let index = aOldVersion;
+    let outer = this;
+
+    function upgradeNextVersion() {
+      if (index == aNewVersion) {
+        debug("Upgrade finished.");
+        return;
+      }
+
+      try {
+        var i = index++;
+        if (DEBUG) debug("Upgrade step: " + i + "\n");
+        upgradeSteps[i].call(outer);
+      } catch (ex) {
+        dump("Caught exception " + ex);
+        throw ex;
+        return;
       }
     }
+
+    if (aNewVersion > upgradeSteps.length) {
+      debug("No migration steps for the new version!");
+      aTransaction.abort();
+      return;
+    }
+
+    upgradeNextVersion();
   },
 
   importData: function importData(aStats) {
     let stats = { appId:         aStats.appId,
                   serviceType:   aStats.serviceType,
                   network:       [aStats.networkId, aStats.networkType],
                   timestamp:     aStats.timestamp,
                   rxBytes:       aStats.rxBytes,
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -1552,16 +1552,20 @@ nsPluginHost::ClearSiteData(nsIPluginTag
 
   // Caller may give us a tag object that is no longer live.
   if (!IsLiveTag(plugin)) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsPluginTag* tag = static_cast<nsPluginTag*>(plugin);
 
+  if (!tag->IsEnabled()) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   // We only ensure support for clearing Flash site data for now.
   // We will also attempt to clear data for any plugin that happens
   // to be loaded already.
   if (!tag->mIsFlashPlugin && !tag->mPlugin) {
     return NS_ERROR_FAILURE;
   }
 
   // Make sure the plugin is loaded.
--- a/dom/svg/SVGCircleElement.cpp
+++ b/dom/svg/SVGCircleElement.cpp
@@ -85,18 +85,17 @@ bool
 SVGCircleElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
                                     const Matrix& aTransform)
 {
   float x, y, r;
   GetAnimatedLengthValues(&x, &y, &r, nullptr);
 
   if (r <= 0.f) {
     // Rendering of the element is disabled
-    aBounds->MoveTo(x, y);
-    aBounds->SetEmpty();
+    *aBounds = Rect(aTransform * Point(x, y), Size());
     return true;
   }
 
   if (aTransform.IsRectilinear()) {
     // Optimize the case where we can treat the circle as a rectangle and
     // still get tight bounds.
     if (aStrokeWidth > 0.f) {
       r += aStrokeWidth / 2.f;
--- a/dom/svg/SVGEllipseElement.cpp
+++ b/dom/svg/SVGEllipseElement.cpp
@@ -96,18 +96,17 @@ bool
 SVGEllipseElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
                                      const Matrix& aTransform)
 {
   float x, y, rx, ry;
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
   if (rx <= 0.f || ry <= 0.f) {
     // Rendering of the element is disabled
-    aBounds->MoveTo(x, y);
-    aBounds->SetEmpty();
+    *aBounds = Rect(aTransform * Point(x, y), Size());
     return true;
   }
 
   if (aTransform.IsRectilinear()) {
     // Optimize the case where we can treat the ellipse as a rectangle and
     // still get tight bounds.
     if (aStrokeWidth > 0.f) {
       rx += aStrokeWidth / 2.f;
--- a/dom/svg/SVGImageElement.cpp
+++ b/dom/svg/SVGImageElement.cpp
@@ -221,16 +221,33 @@ SVGImageElement::IsAttributeMapped(const
     SVGImageElementBase::IsAttributeMapped(name);
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
 /* For the purposes of the update/invalidation logic pretend to
    be a rectangle. */
+bool
+SVGImageElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                   const Matrix& aTransform)
+{
+  Rect rect;
+  GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width,
+                          &rect.height, nullptr);
+
+  if (rect.IsEmpty()) {
+    // Rendering of the element disabled
+    rect.SetEmpty(); // Make sure width/height are zero and not negative
+  }
+
+  *aBounds = aTransform.TransformBounds(rect);
+  return true;
+}
+
 TemporaryRef<Path>
 SVGImageElement::BuildPath(PathBuilder* aBuilder)
 {
   // We get called in order to get bounds for this element, and for
   // hit-testing against it. For that we just pretend to be a rectangle.
 
   float x, y, width, height;
   GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
--- a/dom/svg/SVGImageElement.h
+++ b/dom/svg/SVGImageElement.h
@@ -48,16 +48,18 @@ public:
                               bool aCompileEventHandlers) MOZ_OVERRIDE;
   virtual void UnbindFromTree(bool aDeep, bool aNullParent) MOZ_OVERRIDE;
 
   virtual EventStates IntrinsicState() const MOZ_OVERRIDE;
 
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* name) const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
+  virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                 const Matrix& aTransform) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE;
 
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   nsresult CopyInnerTo(mozilla::dom::Element* aDest);
--- a/dom/svg/SVGPreserveAspectRatio.h
+++ b/dom/svg/SVGPreserveAspectRatio.h
@@ -12,17 +12,17 @@
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/ErrorResult.h"
 #include "nsSVGElement.h"
 
 namespace mozilla {
 // Alignment Types
-enum SVGAlign MOZ_ENUM_TYPE(uint8_t) {
+enum SVGAlign : uint8_t {
   SVG_PRESERVEASPECTRATIO_UNKNOWN = 0,
   SVG_PRESERVEASPECTRATIO_NONE = 1,
   SVG_PRESERVEASPECTRATIO_XMINYMIN = 2,
   SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3,
   SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4,
   SVG_PRESERVEASPECTRATIO_XMINYMID = 5,
   SVG_PRESERVEASPECTRATIO_XMIDYMID = 6,
   SVG_PRESERVEASPECTRATIO_XMAXYMID = 7,
@@ -32,17 +32,17 @@ enum SVGAlign MOZ_ENUM_TYPE(uint8_t) {
 };
 
 // These constants represent the range of valid enum values for the <align>
 // parameter. They exclude the sentinel _UNKNOWN value.
 const uint16_t SVG_ALIGN_MIN_VALID = SVG_PRESERVEASPECTRATIO_NONE;
 const uint16_t SVG_ALIGN_MAX_VALID = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
 
 // Meet-or-slice Types
-enum SVGMeetOrSlice MOZ_ENUM_TYPE(uint8_t) {
+enum SVGMeetOrSlice : uint8_t {
   SVG_MEETORSLICE_UNKNOWN = 0,
   SVG_MEETORSLICE_MEET = 1,
   SVG_MEETORSLICE_SLICE = 2
 };
 
 // These constants represent the range of valid enum values for the
 // <meetOrSlice> parameter. They exclude the sentinel _UNKNOWN value.
 const uint16_t SVG_MEETORSLICE_MIN_VALID = SVG_MEETORSLICE_MEET;
--- a/dom/svg/SVGRectElement.cpp
+++ b/dom/svg/SVGRectElement.cpp
@@ -117,17 +117,18 @@ SVGRectElement::GetGeometryBounds(Rect* 
   Rect rect;
   Float rx, ry;
   GetAnimatedLengthValues(&rect.x, &rect.y, &rect.width,
                           &rect.height, &rx, &ry, nullptr);
 
   if (rect.IsEmpty()) {
     // Rendering of the element disabled
     rect.SetEmpty(); // Make sure width/height are zero and not negative
-    *aBounds = rect; // We still want the x/y position from 'rect'
+    // We still want the x/y position from 'rect'
+    *aBounds = aTransform.TransformBounds(rect);
     return true;
   }
 
   if (!aTransform.IsRectilinear()) {
     // We can't ignore the radii in this case if we want tight bounds
     rx = std::max(rx, 0.0f);
     ry = std::max(ry, 0.0f);
 
--- a/dom/svg/SVGSVGElement.cpp
+++ b/dom/svg/SVGSVGElement.cpp
@@ -1242,10 +1242,38 @@ SVGSVGElement::GetTransformProperty() co
 }
 
 bool
 SVGSVGElement::ClearTransformProperty()
 {
   return UnsetProperty(nsGkAtoms::transform);
 }
 
+int32_t
+SVGSVGElement::GetIntrinsicWidth()
+{
+  if (mLengthAttributes[ATTR_WIDTH].IsPercentage()) {
+    return -1;
+  }
+  // Passing |this| as a SVGSVGElement* invokes the variant of GetAnimValue
+  // that uses the passed argument as the context, but that's fine since we
+  // know the length isn't a percentage so the context won't be used (and we
+  // need to pass the element to be able to resolve em/ex units).
+  float width = mLengthAttributes[ATTR_WIDTH].GetAnimValue(this);
+  return nsSVGUtils::ClampToInt(width);
+}
+
+int32_t
+SVGSVGElement::GetIntrinsicHeight()
+{
+  if (mLengthAttributes[ATTR_HEIGHT].IsPercentage()) {
+    return -1;
+  }
+  // Passing |this| as a SVGSVGElement* invokes the variant of GetAnimValue
+  // that uses the passed argument as the context, but that's fine since we
+  // know the length isn't a percentage so the context won't be used (and we
+  // need to pass the element to be able to resolve em/ex units).
+  float height = mLengthAttributes[ATTR_HEIGHT].GetAnimValue(this);
+  return nsSVGUtils::ClampToInt(height);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/svg/SVGSVGElement.h
+++ b/dom/svg/SVGSVGElement.h
@@ -143,16 +143,25 @@ public:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // SVGSVGElement methods:
   float GetLength(uint8_t mCtxType);
 
   // public helpers:
 
   /**
+   * Returns -1 if the width/height is a percentage, else returns the user unit
+   * length clamped to fit in a int32_t.
+   * XXX see bug 1112533 comment 3 - we should fix drawImage so that we can
+   * change these methods to make zero the error flag for percentages.
+   */
+  int32_t GetIntrinsicWidth();
+  int32_t GetIntrinsicHeight();
+
+  /**
    * Returns true if this element has a base/anim value for its "viewBox"
    * attribute that defines a viewBox rectangle with finite values, or
    * if there is a view element overriding this element's viewBox and it
    * has a valid viewBox.
    *
    * Note that this does not check whether we need to synthesize a viewBox,
    * so you must call ShouldSynthesizeViewBox() if you need to check that too.
    *
--- a/dom/webidl/RTCConfiguration.webidl
+++ b/dom/webidl/RTCConfiguration.webidl
@@ -3,17 +3,18 @@
  * 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/.
  *
  * The origin of this IDL file is
  * http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCConfiguration
  */
 
 dictionary RTCIceServer {
-    DOMString  url;
+    (DOMString or sequence<DOMString>) urls;
+    DOMString  url; //deprecated
     DOMString? credential = null;
     DOMString? username = null;
 };
 
 dictionary RTCConfiguration {
     sequence<RTCIceServer> iceServers;
     DOMString? peerIdentity = null;
 };
--- a/gfx/2d/SVGTurbulenceRenderer-inl.h
+++ b/gfx/2d/SVGTurbulenceRenderer-inl.h
@@ -120,18 +120,21 @@ template<TurbulenceType Type, bool Stitc
 void
 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::InitFromSeed(int32_t aSeed)
 {
   RandomNumberSource rand(aSeed);
 
   float gradient[4][sBSize][2];
   for (int32_t k = 0; k < 4; k++) {
     for (int32_t i = 0; i < sBSize; i++) {
-      float a = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
-      float b = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
+      float a, b;
+      do {
+        a = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
+        b = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
+      } while (a == 0 && b == 0);
       float s = sqrt(a * a + b * b);
       gradient[k][i][0] = a / s;
       gradient[k][i][1] = b / s;
     }
   }
 
   for (int32_t i = 0; i < sBSize; i++) {
     mLatticeSelector[i] = i;
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -1045,16 +1045,17 @@ CompositorD3D11::BeginFrame(const nsIntR
   // this is important because resizing our buffers when mimised will fail and
   // cause a crash when we're restored.
   NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
   if (::IsIconic(mHwnd) || gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
     *aRenderBoundsOut = Rect();
     return;
   }
 
+  nsIntSize oldSize = mSize;
   UpdateRenderTarget();
 
   // Failed to create a render target or the view.
   if (!mDefaultRT || !mDefaultRT->mRTView ||
       mSize.width == 0 || mSize.height == 0) {
     *aRenderBoundsOut = Rect();
     return;
   }
@@ -1064,17 +1065,23 @@ CompositorD3D11::BeginFrame(const nsIntR
   ID3D11Buffer* buffer = mAttachments->mVertexBuffer;
   UINT size = sizeof(Vertex);
   UINT offset = 0;
   mContext->IASetVertexBuffers(0, 1, &buffer, &size, &offset);
 
   nsIntRect intRect = nsIntRect(nsIntPoint(0, 0), mSize);
   // Sometimes the invalid region is larger than we want to draw.
   nsIntRegion invalidRegionSafe;
-  invalidRegionSafe.And(aInvalidRegion, intRect);
+
+  if (mSize != oldSize) {
+    invalidRegionSafe = intRect;
+  } else {
+    invalidRegionSafe.And(aInvalidRegion, intRect);
+  }
+
   nsIntRect invalidRect = invalidRegionSafe.GetBounds();
   mInvalidRect = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
   mInvalidRegion = invalidRegionSafe;
 
   if (aClipRectOut) {
     *aClipRectOut = Rect(0, 0, mSize.width, mSize.height);
   }
   if (aRenderBoundsOut) {
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -234,17 +234,17 @@ private:
 
   DECL_GFX_PREF(Once, "image.cache.timeweight",                ImageCacheTimeWeight, int32_t, 500);
   DECL_GFX_PREF(Once, "image.cache.size",                      ImageCacheSize, int32_t, 5*1024*1024);
   DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, false);
   DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
   DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
   DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520);
   DECL_GFX_PREF(Once, "image.mem.decode_bytes_at_a_time",      ImageMemDecodeBytesAtATime, uint32_t, 200000);
-  DECL_GFX_PREF(Live, "image.mem.decodeondraw",                ImageMemDecodeOnDraw, bool, false);
+  DECL_GFX_PREF(Live, "image.mem.decodeondraw",                ImageMemDecodeOnDraw, bool, true);
   DECL_GFX_PREF(Live, "image.mem.discardable",                 ImageMemDiscardable, bool, false);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.discard_factor", ImageMemSurfaceCacheDiscardFactor, uint32_t, 1);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.max_size_kb",    ImageMemSurfaceCacheMaxSizeKB, uint32_t, 100 * 1024);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.min_expiration_ms", ImageMemSurfaceCacheMinExpirationMS, uint32_t, 60*1000);
   DECL_GFX_PREF(Once, "image.mem.surfacecache.size_factor",    ImageMemSurfaceCacheSizeFactor, uint32_t, 64);
   DECL_GFX_PREF(Live, "image.mozsamplesize.enabled",           ImageMozSampleSizeEnabled, bool, false);
   DECL_GFX_PREF(Once, "image.multithreaded_decoding.limit",    ImageMTDecodingLimit, int32_t, -1);
 
--- a/image/src/SVGDocumentWrapper.cpp
+++ b/image/src/SVGDocumentWrapper.cpp
@@ -63,55 +63,16 @@ SVGDocumentWrapper::DestroyViewer()
   if (mViewer) {
     mViewer->GetDocument()->OnPageHide(false, nullptr);
     mViewer->Close(nullptr);
     mViewer->Destroy();
     mViewer = nullptr;
   }
 }
 
-bool
-SVGDocumentWrapper::GetWidthOrHeight(Dimension aDimension,
-                                     int32_t& aResult)
-{
-  SVGSVGElement* rootElem = GetRootSVGElem();
-  NS_ABORT_IF_FALSE(rootElem, "root elem missing or of wrong type");
-
-  // Get the width or height SVG object
-  nsRefPtr<SVGAnimatedLength> domAnimLength;
-  if (aDimension == eWidth) {
-    domAnimLength = rootElem->Width();
-  } else {
-    NS_ABORT_IF_FALSE(aDimension == eHeight, "invalid dimension");
-    domAnimLength = rootElem->Height();
-  }
-  NS_ENSURE_TRUE(domAnimLength, false);
-
-  // Get the animated value from the object
-  nsRefPtr<DOMSVGLength> domLength = domAnimLength->AnimVal();
-  NS_ENSURE_TRUE(domLength, false);
-
-  // Check if it's a percent value (and fail if so)
-  uint16_t unitType;
-  nsresult rv = domLength->GetUnitType(&unitType);
-  NS_ENSURE_SUCCESS(rv, false);
-  if (unitType == nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
-    return false;
-  }
-
-  // Non-percent value - woot! Grab it & return it.
-  float floatLength;
-  rv = domLength->GetValue(&floatLength);
-  NS_ENSURE_SUCCESS(rv, false);
-
-  aResult = nsSVGUtils::ClampToInt(floatLength);
-
-  return true;
-}
-
 nsIFrame*
 SVGDocumentWrapper::GetRootLayoutFrame()
 {
   Element* rootElem = GetRootSVGElem();
   return rootElem ? rootElem->GetPrimaryFrame() : nullptr;
 }
 
 void
--- a/image/src/SVGDocumentWrapper.h
+++ b/image/src/SVGDocumentWrapper.h
@@ -48,31 +48,16 @@ public:
   NS_DECL_NSIOBSERVER
 
   enum Dimension {
     eWidth,
     eHeight
   };
 
   /**
-   * Looks up the value of the wrapped SVG document's |width| or |height|
-   * attribute in CSS pixels, and returns it by reference.  If the document has
-   * a percent value for the queried attribute, then this method fails
-   * (returns false).
-   *
-   * @param aDimension    Indicates whether the width or height is desired.
-   * @param[out] aResult  If this method succeeds, then this outparam will be
-                          populated with the width or height in CSS pixels.
-   * @return false to indicate failure, if the queried attribute has a
-   *         percent value.  Otherwise, true.
-   *
-   */
-  bool      GetWidthOrHeight(Dimension aDimension, int32_t& aResult);
-
-  /**
    * Returns the wrapped document, or nullptr on failure. (No AddRef.)
    */
   nsIDocument* GetDocument();
 
   /**
    * Returns the root <svg> element for the wrapped document, or nullptr on
    * failure.
    */
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -467,27 +467,24 @@ VectorImage::SetAnimationStartTime(const
 // imgIContainer methods
 
 //******************************************************************************
 /* readonly attribute int32_t width; */
 NS_IMETHODIMP
 VectorImage::GetWidth(int32_t* aWidth)
 {
   if (mError || !mIsFullyLoaded) {
-    *aWidth = 0;
-    return NS_ERROR_FAILURE;
+    *aWidth = -1;
+  } else {
+    SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
+    MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
+                         "loading without errors");
+    *aWidth = rootElem->GetIntrinsicWidth();
   }
-
-  if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth,
-                                             *aWidth)) {
-    *aWidth = 0;
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
+  return *aWidth >= 0 ? NS_OK : NS_ERROR_FAILURE;
 }
 
 //******************************************************************************
 /* [notxpcom] void requestRefresh ([const] in TimeStamp aTime); */
 NS_IMETHODIMP_(void)
 VectorImage::RequestRefresh(const TimeStamp& aTime)
 {
   if (HadRecentRefresh(aTime)) {
@@ -536,27 +533,24 @@ VectorImage::GetImageSpaceInvalidationRe
 }
 
 //******************************************************************************
 /* readonly attribute int32_t height; */
 NS_IMETHODIMP
 VectorImage::GetHeight(int32_t* aHeight)
 {
   if (mError || !mIsFullyLoaded) {
-    *aHeight = 0;
-    return NS_ERROR_FAILURE;
+    *aHeight = -1;
+  } else {
+    SVGSVGElement* rootElem = mSVGDocumentWrapper->GetRootSVGElem();
+    MOZ_ASSERT(rootElem, "Should have a root SVG elem, since we finished "
+                         "loading without errors");
+    *aHeight = rootElem->GetIntrinsicHeight();
   }
-
-  if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight,
-                                             *aHeight)) {
-    *aHeight = 0;
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
+  return *aHeight >= 0 ? NS_OK : NS_ERROR_FAILURE;
 }
 
 //******************************************************************************
 /* [noscript] readonly attribute nsSize intrinsicSize; */
 NS_IMETHODIMP
 VectorImage::GetIntrinsicSize(nsSize* aSize)
 {
   if (mError || !mIsFullyLoaded)
@@ -658,27 +652,30 @@ NS_IMETHODIMP_(TemporaryRef<SourceSurfac
 VectorImage::GetFrame(uint32_t aWhichFrame,
                       uint32_t aFlags)
 {
   MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
 
   if (aWhichFrame > FRAME_MAX_VALUE)
     return nullptr;
 
-  if (mError)
+  if (mError || !mIsFullyLoaded)
     return nullptr;
 
   // Look up height & width
   // ----------------------
-  nsIntSize imageIntSize;
-  if (!mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eWidth,
-                                             imageIntSize.width) ||
-      !mSVGDocumentWrapper->GetWidthOrHeight(SVGDocumentWrapper::eHeight,
-                                             imageIntSize.height)) {
-    // We'll get here if our SVG doc has a percent-valued width or height.
+  SVGSVGElement* svgElem = mSVGDocumentWrapper->GetRootSVGElem();
+  MOZ_ASSERT(svgElem, "Should have a root SVG elem, since we finished "
+                      "loading without errors");
+  nsIntSize imageIntSize(svgElem->GetIntrinsicWidth(),
+                         svgElem->GetIntrinsicHeight());
+  
+  if (imageIntSize.IsEmpty()) {
+    // We'll get here if our SVG doc has a percent-valued or negative width or
+    // height.
     return nullptr;
   }
 
   // Make our surface the size of what will ultimately be drawn to it.
   // (either the full image size, or the restricted region)
   RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->
     CreateOffscreenContentDrawTarget(IntSize(imageIntSize.width,
                                              imageIntSize.height),
--- a/intl/build/moz.build
+++ b/intl/build/moz.build
@@ -4,18 +4,17 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SOURCES += [
     'nsI18nModule.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
+CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS']
 LOCAL_INCLUDES += [
-    '../icu/source/common',
-    '../icu/source/i18n',
     '../locale',
     '../lwbrk',
     '../strres',
     '../uconv',
     '../unicharutil',
 ]
 
--- a/intl/locale/mac/moz.build
+++ b/intl/locale/mac/moz.build
@@ -6,15 +6,14 @@
 
 UNIFIED_SOURCES += [
     'nsCollationMacUC.cpp',
     'nsDateTimeFormatMac.cpp',
     'nsMacCharset.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
+CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS']
 LOCAL_INCLUDES += [
     '..',
-    '../../icu/source/common',
-    '../../icu/source/i18n',
 ]
 
 FAIL_ON_WARNINGS = True
--- a/ipc/nfc/Nfc.cpp
+++ b/ipc/nfc/Nfc.cpp
@@ -1,10 +1,10 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set sw=4 ts=8 et ft=cpp: */
+/* vim: set sw=2 ts=8 et ft=cpp: */
 /* 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/. */
 
 /* Copyright © 2013, Deutsche Telekom, Inc. */
 
 #include "mozilla/ipc/Nfc.h"
 
@@ -17,220 +17,223 @@
 #include <android/log.h>
 #define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args)
 #else
 #define CHROMIUM_LOG(args...)
 #endif
 
 #include "jsfriendapi.h"
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/ipc/UnixSocketConnector.h"
 #include "nsThreadUtils.h" // For NS_IsMainThread.
 
 using namespace mozilla::ipc;
 
 namespace {
 
-const char* NFC_SOCKET_NAME = "/dev/socket/nfcd";
+static const char NFC_SOCKET_NAME[] = "/dev/socket/nfcd";
 
 // Network port to connect to for adb forwarded sockets when doing
 // desktop development.
-const uint32_t NFC_TEST_PORT = 6400;
+static const uint32_t NFC_TEST_PORT = 6400;
 
-class SendNfcSocketDataTask : public nsRunnable
+class SendNfcSocketDataTask MOZ_FINAL : public nsRunnable
 {
 public:
-    SendNfcSocketDataTask(NfcConsumer* aConsumer, UnixSocketRawData* aRawData)
-        : mConsumer(aConsumer), mRawData(aRawData)
-    { }
-
-    NS_IMETHOD Run()
-    {
-        MOZ_ASSERT(NS_IsMainThread());
+  SendNfcSocketDataTask(NfcConsumer* aConsumer, UnixSocketRawData* aRawData)
+    : mConsumer(aConsumer)
+    , mRawData(aRawData)
+  { }
 
-        if (!mConsumer ||
-            mConsumer->GetConnectionStatus() != SOCKET_CONNECTED) {
-            // Probably shuting down.
-            delete mRawData;
-            return NS_OK;
-        }
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
 
-        mConsumer->SendSocketData(mRawData);
-        return NS_OK;
+    if (!mConsumer ||
+      mConsumer->GetConnectionStatus() != SOCKET_CONNECTED) {
+      // Probably shuting down.
+      return NS_OK;
     }
 
+    mConsumer->SendSocketData(mRawData.forget());
+    return NS_OK;
+  }
+
 private:
-    NfcConsumer* mConsumer;
-    UnixSocketRawData* mRawData;
+  NfcConsumer* mConsumer;
+  nsAutoPtr<UnixSocketRawData> mRawData;
 };
 
-class NfcConnector : public mozilla::ipc::UnixSocketConnector
+class NfcConnector MOZ_FINAL : public mozilla::ipc::UnixSocketConnector
 {
 public:
-    NfcConnector()
-    {}
-
-    virtual ~NfcConnector()
-    {}
+  NfcConnector()
+  { }
 
-    virtual int Create();
-    virtual bool CreateAddr(bool aIsServer,
-                            socklen_t& aAddrSize,
-                            sockaddr_any& aAddr,
-                            const char* aAddress);
-    virtual bool SetUp(int aFd);
-    virtual bool SetUpListenSocket(int aFd);
-    virtual void GetSocketAddr(const sockaddr_any& aAddr,
-                               nsAString& aAddrStr);
+  int Create() MOZ_OVERRIDE;
+  bool CreateAddr(bool aIsServer,
+                  socklen_t& aAddrSize,
+                  sockaddr_any& aAddr,
+                  const char* aAddress) MOZ_OVERRIDE;
+  bool SetUp(int aFd) MOZ_OVERRIDE;
+  bool SetUpListenSocket(int aFd) MOZ_OVERRIDE;
+  void GetSocketAddr(const sockaddr_any& aAddr,
+                     nsAString& aAddrStr) MOZ_OVERRIDE;
 };
 
 int
 NfcConnector::Create()
 {
-    MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(!NS_IsMainThread());
 
-    int fd = -1;
+  int fd = -1;
 
 #if defined(MOZ_WIDGET_GONK)
-    fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+  fd = socket(AF_LOCAL, SOCK_STREAM, 0);
 #else
-    // If we can't hit a local loopback, fail later in connect.
-    fd = socket(AF_INET, SOCK_STREAM, 0);
+  // If we can't hit a local loopback, fail later in connect.
+  fd = socket(AF_INET, SOCK_STREAM, 0);
 #endif
 
-    if (fd < 0) {
-        NS_WARNING("Could not open nfc socket!");
-        return -1;
-    }
+  if (fd < 0) {
+    NS_WARNING("Could not open nfc socket!");
+    return -1;
+  }
 
-    if (!SetUp(fd)) {
-        NS_WARNING("Could not set up socket!");
-    }
-    return fd;
+  if (!SetUp(fd)) {
+    NS_WARNING("Could not set up socket!");
+  }
+  return fd;
 }
 
 bool
 NfcConnector::CreateAddr(bool aIsServer,
                          socklen_t& aAddrSize,
                          sockaddr_any& aAddr,
                          const char* aAddress)
 {
-    // We never open nfc socket as server.
-    MOZ_ASSERT(!aIsServer);
-    uint32_t af;
+  // We never open nfc socket as server.
+  MOZ_ASSERT(!aIsServer);
+  uint32_t af;
 #if defined(MOZ_WIDGET_GONK)
-    af = AF_LOCAL;
+  af = AF_LOCAL;
 #else
-    af = AF_INET;
+  af = AF_INET;
 #endif
-    switch (af) {
-    case AF_LOCAL:
-        aAddr.un.sun_family = af;
-        if(strlen(aAddress) > sizeof(aAddr.un.sun_path)) {
-            NS_WARNING("Address too long for socket struct!");
-            return false;
-        }
-        strcpy((char*)&aAddr.un.sun_path, aAddress);
-        aAddrSize = strlen(aAddress) + offsetof(struct sockaddr_un, sun_path) + 1;
-        break;
-    case AF_INET:
-        aAddr.in.sin_family = af;
-        aAddr.in.sin_port = htons(NFC_TEST_PORT);
-        aAddr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-        aAddrSize = sizeof(sockaddr_in);
-        break;
-    default:
-        NS_WARNING("Socket type not handled by connector!");
-        return false;
+  switch (af) {
+  case AF_LOCAL:
+    aAddr.un.sun_family = af;
+    if(strlen(aAddress) > sizeof(aAddr.un.sun_path)) {
+      NS_WARNING("Address too long for socket struct!");
+      return false;
     }
-    return true;
+    strcpy((char*)&aAddr.un.sun_path, aAddress);
+    aAddrSize = strlen(aAddress) + offsetof(struct sockaddr_un, sun_path) + 1;
+    break;
+  case AF_INET:
+    aAddr.in.sin_family = af;
+    aAddr.in.sin_port = htons(NFC_TEST_PORT);
+    aAddr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    aAddrSize = sizeof(sockaddr_in);
+    break;
+  default:
+    NS_WARNING("Socket type not handled by connector!");
+    return false;
+  }
+  return true;
 }
 
 bool
 NfcConnector::SetUp(int aFd)
 {
-    // Nothing to do here.
-    return true;
+  // Nothing to do here.
+  return true;
 }
 
 bool
 NfcConnector::SetUpListenSocket(int aFd)
 {
-    // Nothing to do here.
-    return true;
+  // Nothing to do here.
+  return true;
 }
 
 void
 NfcConnector::GetSocketAddr(const sockaddr_any& aAddr,
                             nsAString& aAddrStr)
 {
-    MOZ_CRASH("This should never be called!");
+  MOZ_CRASH("This should never be called!");
 }
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace ipc {
 
 NfcConsumer::NfcConsumer(NfcSocketListener* aListener)
-    : mListener(aListener)
-    , mShutdown(false)
+  : mListener(aListener)
+  , mShutdown(false)
 {
-    mAddress = NFC_SOCKET_NAME;
+  mAddress = NFC_SOCKET_NAME;
 
-    ConnectSocket(new NfcConnector(), mAddress.get());
+  Connect(new NfcConnector(), mAddress.get());
 }
 
 void
 NfcConsumer::Shutdown()
 {
-    MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(NS_IsMainThread());
 
-    mShutdown = true;
-    CloseSocket();
+  mShutdown = true;
+  Close();
 }
 
 bool
 NfcConsumer::PostToNfcDaemon(const uint8_t* aData, size_t aSize)
 {
-    MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(!NS_IsMainThread());
 
-    UnixSocketRawData* raw = new UnixSocketRawData(aData, aSize);
-    nsRefPtr<SendNfcSocketDataTask> task = new SendNfcSocketDataTask(this, raw);
-    NS_DispatchToMainThread(task);
-    return true;
+  UnixSocketRawData* raw = new UnixSocketRawData(aData, aSize);
+  nsRefPtr<SendNfcSocketDataTask> task = new SendNfcSocketDataTask(this, raw);
+  NS_DispatchToMainThread(task);
+  return true;
 }
 
 void
 NfcConsumer::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aData)
 {
-    MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(NS_IsMainThread());
 
-    if (mListener) {
-        mListener->ReceiveSocketData(aData);
-    }
+  if (mListener) {
+    mListener->ReceiveSocketData(aData);
+  }
 }
 
 void
 NfcConsumer::OnConnectSuccess()
 {
-    // Nothing to do here.
-    CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
+  // Nothing to do here.
+  CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
 }
 
 void
 NfcConsumer::OnConnectError()
 {
-    CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
-    CloseSocket();
+  CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
+  Close();
 }
 
 void
 NfcConsumer::OnDisconnect()
 {
-    CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
-    if (!mShutdown) {
-        ConnectSocket(new NfcConnector(), mAddress.get(),
-                      GetSuggestedConnectDelayMs());
-    }
+  CHROMIUM_LOG("NFC: %s\n", __FUNCTION__);
+  if (!mShutdown) {
+    Connect(new NfcConnector(), mAddress.get(), GetSuggestedConnectDelayMs());
+  }
+}
+
+ConnectionOrientedSocketIO*
+NfcConsumer::GetIO()
+{
+  return PrepareAccept(new NfcConnector());
 }
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/nfc/Nfc.h
+++ b/ipc/nfc/Nfc.h
@@ -4,42 +4,44 @@
  * 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/. */
 
 /* Copyright © 2013, Deutsche Telekom, Inc. */
 
 #ifndef mozilla_ipc_Nfc_h
 #define mozilla_ipc_Nfc_h 1
 
-#include <mozilla/ipc/UnixSocket.h>
+#include <mozilla/ipc/StreamSocket.h>
 
 namespace mozilla {
 namespace ipc {
 
 class NfcSocketListener
 {
 public:
   virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aData) = 0;
 };
 
-class NfcConsumer : public mozilla::ipc::UnixSocketConsumer
+class NfcConsumer MOZ_FINAL : public mozilla::ipc::StreamSocket
 {
 public:
   NfcConsumer(NfcSocketListener* aListener);
-  virtual ~NfcConsumer() { }
 
   void Shutdown();
   bool PostToNfcDaemon(const uint8_t* aData, size_t aSize);
 
-private:
-  virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aData);
+  ConnectionOrientedSocketIO* GetIO() MOZ_OVERRIDE;
 
-  virtual void OnConnectSuccess();
-  virtual void OnConnectError();
-  virtual void OnDisconnect();
+private:
+  void ReceiveSocketData(
+    nsAutoPtr<UnixSocketRawData>& aData) MOZ_OVERRIDE;
+
+  void OnConnectSuccess() MOZ_OVERRIDE;
+  void OnConnectError() MOZ_OVERRIDE;
+  void OnDisconnect() MOZ_OVERRIDE;
 
 private:
   NfcSocketListener* mListener;
   nsCString mAddress;
   bool mShutdown;
 };
 
 } // namespace ipc
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3048,28 +3048,16 @@ fi
 dnl ========================================================
 dnl = Location of malloc wrapper lib
 dnl ========================================================
 MOZ_ARG_WITH_STRING(wrap-malloc,
 [  --with-wrap-malloc=DIR  Location of malloc wrapper library],
     WRAP_LDFLAGS="${WRAP_LDFLAGS} $withval")
 
 dnl ========================================================
-dnl = Use compacting GC
-dnl ========================================================
-dnl Compact the heap by moving GC things when doing a shrinking colletion.
-MOZ_ARG_ENABLE_BOOL(gccompacting,
-[  --enable-gccompacting   Compact the heap by moving GC things],
-    JSGC_COMPACTING=1,
-    JSGC_COMPACTING= )
-if test -n "$JSGC_COMPACTING"; then
-    AC_DEFINE(JSGC_COMPACTING)
-fi
-
-dnl ========================================================
 dnl = Use a smaller chunk size for GC chunks
 dnl ========================================================
 dnl Use large (1MB) chunks by default.  For B2G this option is used to give
 dnl smaller (currently 256K) chunks.
 MOZ_ARG_ENABLE_BOOL(small-chunk-size,
 [  --enable-small-chunk-size  Allocate memory for JS GC things in smaller chunks],
     JS_GC_SMALL_CHUNK_SIZE=1,
     JS_GC_SMALL_CHUNK_SIZE= )
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3252,16 +3252,18 @@ EmitDestructuringDeclsWithEmitter(Exclus
         for (ParseNode *element = pattern->pn_head; element; element = element->pn_next) {
             if (element->isKind(PNK_ELISION))
                 continue;
             ParseNode *target = element;
             if (element->isKind(PNK_SPREAD)) {
                 MOZ_ASSERT(element->pn_kid->isKind(PNK_NAME));
                 target = element->pn_kid;
             }
+            if (target->isKind(PNK_ASSIGN))
+                target = target->pn_left;
             if (target->isKind(PNK_NAME)) {
                 if (!EmitName(cx, bce, prologOp, target))
                     return false;
             } else {
                 if (!EmitDestructuringDeclsWithEmitter<EmitName>(cx, bce, prologOp, target))
                     return false;
             }
         }
@@ -3271,16 +3273,18 @@ EmitDestructuringDeclsWithEmitter(Exclus
     MOZ_ASSERT(pattern->isKind(PNK_OBJECT));
     for (ParseNode *member = pattern->pn_head; member; member = member->pn_next) {
         MOZ_ASSERT(member->isKind(PNK_MUTATEPROTO) ||
                    member->isKind(PNK_COLON) ||
                    member->isKind(PNK_SHORTHAND));
 
         ParseNode *target = member->isKind(PNK_MUTATEPROTO) ? member->pn_kid : member->pn_right;
 
+        if (target->isKind(PNK_ASSIGN))
+            target = target->pn_left;
         if (target->isKind(PNK_NAME)) {
             if (!EmitName(cx, bce, prologOp, target))
                 return false;
         } else {
             if (!EmitDestructuringDeclsWithEmitter<EmitName>(cx, bce, prologOp, target))
                 return false;
         }
     }
@@ -3336,84 +3340,86 @@ EmitDestructuringOpsHelper(ExclusiveCont
  * If emitOption is InitializeVars, the to-be-destructured value is assigned to
  * locals and ultimately the initial slot is popped (-1 total depth change).
  *
  * If emitOption is PushInitialValues, the to-be-destructured value is replaced
  * with the initial values of the N (where 0 <= N) variables assigned in the
  * lhs expression. (Same post-condition as EmitDestructuringOpsHelper)
  */
 static bool
-EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption)
+EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *target, VarEmitOption emitOption)
 {
     MOZ_ASSERT(emitOption != DefineVars);
 
     // Now emit the lvalue opcode sequence. If the lvalue is a nested
     // destructuring initialiser-form, call ourselves to handle it, then pop
     // the matched value. Otherwise emit an lvalue bytecode sequence followed
     // by an assignment op.
-    if (pn->isKind(PNK_SPREAD))
-        pn = pn->pn_kid;
-    if (pn->isKind(PNK_ARRAY) || pn->isKind(PNK_OBJECT)) {
-        if (!EmitDestructuringOpsHelper(cx, bce, pn, emitOption))
+    if (target->isKind(PNK_SPREAD))
+        target = target->pn_kid;
+    else if (target->isKind(PNK_ASSIGN))
+        target = target->pn_left;
+    if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) {
+        if (!EmitDestructuringOpsHelper(cx, bce, target, emitOption))
             return false;
         if (emitOption == InitializeVars) {
             // Per its post-condition, EmitDestructuringOpsHelper has left the
             // to-be-destructured value on top of the stack.
             if (Emit1(cx, bce, JSOP_POP) < 0)
                 return false;
         }
     } else if (emitOption == PushInitialValues) {
         // The lhs is a simple name so the to-be-destructured value is
         // its initial value and there is nothing to do.
-        MOZ_ASSERT(pn->getOp() == JSOP_SETLOCAL || pn->getOp() == JSOP_INITLEXICAL);
-        MOZ_ASSERT(pn->pn_dflags & PND_BOUND);
+        MOZ_ASSERT(target->getOp() == JSOP_SETLOCAL || target->getOp() == JSOP_INITLEXICAL);
+        MOZ_ASSERT(target->pn_dflags & PND_BOUND);
     } else {
-        switch (pn->getKind()) {
+        switch (target->getKind()) {
           case PNK_NAME:
-            if (!BindNameToSlot(cx, bce, pn))
-                return false;
-
-            switch (pn->getOp()) {
+            if (!BindNameToSlot(cx, bce, target))
+                return false;
+
+            switch (target->getOp()) {
               case JSOP_SETNAME:
               case JSOP_STRICTSETNAME:
               case JSOP_SETGNAME:
               case JSOP_STRICTSETGNAME:
               case JSOP_SETCONST: {
                 // This is like ordinary assignment, but with one difference.
                 //
                 // In `a = b`, we first determine a binding for `a` (using
                 // JSOP_BINDNAME or JSOP_BINDGNAME), then we evaluate `b`, then
                 // a JSOP_SETNAME instruction.
                 //
                 // In `[a] = [b]`, per spec, `b` is evaluated first, then we
                 // determine a binding for `a`. Then we need to do assignment--
                 // but the operands are on the stack in the wrong order for
                 // JSOP_SETPROP, so we have to add a JSOP_SWAP.
                 jsatomid atomIndex;
-                if (!bce->makeAtomIndex(pn->pn_atom, &atomIndex))
+                if (!bce->makeAtomIndex(target->pn_atom, &atomIndex))
                     return false;
 
-                if (!pn->isOp(JSOP_SETCONST)) {
-                    bool global = pn->isOp(JSOP_SETGNAME) || pn->isOp(JSOP_STRICTSETGNAME);
+                if (!target->isOp(JSOP_SETCONST)) {
+                    bool global = target->isOp(JSOP_SETGNAME) || target->isOp(JSOP_STRICTSETGNAME);
                     JSOp bindOp = global ? JSOP_BINDGNAME : JSOP_BINDNAME;
                     if (!EmitIndex32(cx, bindOp, atomIndex, bce))
                         return false;
                     if (Emit1(cx, bce, JSOP_SWAP) < 0)
                         return false;
                 }
 
-                if (!EmitIndexOp(cx, pn->getOp(), atomIndex, bce))
+                if (!EmitIndexOp(cx, target->getOp(), atomIndex, bce))
                     return false;
                 break;
               }
 
               case JSOP_SETLOCAL:
               case JSOP_SETARG:
               case JSOP_INITLEXICAL:
-                if (!EmitVarOp(cx, pn, pn->getOp(), bce))
+                if (!EmitVarOp(cx, target, target->getOp(), bce))
                     return false;
                 break;
 
               default:
                 MOZ_CRASH("EmitDestructuringLHS: bad name op");
             }
             break;
 
@@ -3422,40 +3428,40 @@ EmitDestructuringLHS(ExclusiveContext *c
             // See the (PNK_NAME, JSOP_SETNAME) case above.
             //
             // In `a.x = b`, `a` is evaluated first, then `b`, then a
             // JSOP_SETPROP instruction.
             //
             // In `[a.x] = [b]`, per spec, `b` is evaluated before `a`. Then we
             // need a property set -- but the operands are on the stack in the
             // wrong order for JSOP_SETPROP, so we have to add a JSOP_SWAP.
-            if (!EmitTree(cx, bce, pn->pn_expr))
+            if (!EmitTree(cx, bce, target->pn_expr))
                 return false;
             if (Emit1(cx, bce, JSOP_SWAP) < 0)
                 return false;
             JSOp setOp = bce->sc->strict ? JSOP_STRICTSETPROP : JSOP_SETPROP;
-            if (!EmitAtomOp(cx, pn, setOp, bce))
+            if (!EmitAtomOp(cx, target, setOp, bce))
                 return false;
             break;
           }
 
           case PNK_ELEM:
           {
             // See the comment at `case PNK_DOT:` above. This case,
             // `[a[x]] = [b]`, is handled much the same way. The JSOP_SWAP
             // is emitted by EmitElemOperands.
             JSOp setOp = bce->sc->strict ? JSOP_STRICTSETELEM : JSOP_SETELEM;
-            if (!EmitElemOp(cx, pn, setOp, bce))
+            if (!EmitElemOp(cx, target, setOp, bce))
                 return false;
             break;
           }
 
           case PNK_CALL:
-            MOZ_ASSERT(pn->pn_xflags & PNX_SETCALL);
-            if (!EmitTree(cx, bce, pn))
+            MOZ_ASSERT(target->pn_xflags & PNX_SETCALL);
+            if (!EmitTree(cx, bce, target))
                 return false;
 
             // Pop the call return value. Below, we pop the RHS too, balancing
             // the stack --- presumably for the benefit of bytecode
             // analysis. (The interpreter will never reach these instructions
             // since we just emitted JSOP_SETCALL, which always throws. It's
             // possible no analyses actually depend on this either.)
             if (Emit1(cx, bce, JSOP_POP) < 0)
@@ -3495,16 +3501,43 @@ EmitIteratorNext(ExclusiveContext *cx, B
     if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // ... NEXT ITER
         return false;
     if (EmitCall(cx, bce, JSOP_CALL, 0, pn) < 0)               // ... RESULT
         return false;
     CheckTypeSet(cx, bce, JSOP_CALL);
     return true;
 }
 
+/**
+ * EmitDefault will check if the value on top of the stack is "undefined".
+ * If so, it will replace that value on the stack with the value defined by |defaultExpr|.
+ */
+static bool
+EmitDefault(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *defaultExpr)
+{
+    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // VALUE VALUE
+        return false;
+    if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)                    // VALUE VALUE UNDEFINED
+        return false;
+    if (Emit1(cx, bce, JSOP_STRICTEQ) < 0)                     // VALUE EQL?
+        return false;
+    // Emit source note to enable ion compilation.
+    if (NewSrcNote(cx, bce, SRC_IF) < 0)
+        return false;
+    ptrdiff_t jump = EmitJump(cx, bce, JSOP_IFEQ, 0);          // VALUE
+    if (jump < 0)
+        return false;
+    if (Emit1(cx, bce, JSOP_POP) < 0)                          // .
+        return false;
+    if (!EmitTree(cx, bce, defaultExpr))                       // DEFAULTVALUE
+        return false;
+    SetJumpOffsetAt(bce, jump);
+    return true;
+}
+
 static bool
 EmitDestructuringOpsArrayHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pattern,
                                 VarEmitOption emitOption)
 {
     MOZ_ASSERT(pattern->isKind(PNK_ARRAY));
     MOZ_ASSERT(pattern->isArity(PN_LIST));
     MOZ_ASSERT(bce->stackDepth != 0);
 
@@ -3521,17 +3554,24 @@ EmitDestructuringOpsArrayHelper(Exclusiv
     bool needToPopIterator = true;
 
     for (ParseNode *member = pattern->pn_head; member; member = member->pn_next) {
         /*
          * Now push the property name currently being matched, which is the
          * current property name "label" on the left of a colon in the object
          * initializer.
          */
-        if (member->isKind(PNK_SPREAD)) {
+        ParseNode *pndefault = nullptr;
+        ParseNode *elem = member;
+        if (elem->isKind(PNK_ASSIGN)) {
+            pndefault = elem->pn_right;
+            elem = elem->pn_left;
+        }
+
+        if (elem->isKind(PNK_SPREAD)) {
             /* Create a new array with the rest of the iterator */
             ptrdiff_t off = EmitN(cx, bce, JSOP_NEWARRAY, 3);          // ... OBJ? ITER ARRAY
             if (off < 0)
                 return false;
             CheckTypeSet(cx, bce, JSOP_NEWARRAY);
             jsbytecode *pc = bce->code(off);
             SET_UINT24(pc, 0);
 
@@ -3576,18 +3616,21 @@ EmitDestructuringOpsArrayHelper(Exclusiv
             if (!EmitAtomOp(cx, cx->names().value, JSOP_GETPROP, bce)) // ... OBJ? ITER VALUE
                 return false;
 
             SetJumpOffsetAt(bce, jmp);
             if (!SetSrcNoteOffset(cx, bce, noteIndex, 0, jmp - beq))
                 return false;
         }
 
+        if (pndefault && !EmitDefault(cx, bce, pndefault))
+            return false;
+
         // Destructure into the pattern the element contains.
-        ParseNode *subpattern = member;
+        ParseNode *subpattern = elem;
         if (subpattern->isKind(PNK_ELISION)) {
             // The value destructuring into an elision just gets ignored.
             if (Emit1(cx, bce, JSOP_POP) < 0)                          // ... OBJ? ITER
                 return false;
             continue;
         }
 
         int32_t depthBefore = bce->stackDepth;
@@ -3679,16 +3722,22 @@ EmitDestructuringOpsObjectHelper(Exclusi
 
             subpattern = member->pn_right;
         }
 
         // Get the property value if not done already.
         if (needsGetElem && !EmitElemOpBase(cx, bce, JSOP_GETELEM))    // ... OBJ PROP
             return false;
 
+        if (subpattern->isKind(PNK_ASSIGN)) {
+            if (!EmitDefault(cx, bce, subpattern->pn_right))
+                return false;
+            subpattern = subpattern->pn_left;
+        }
+
         // Destructure PROP per this member's subpattern.
         int32_t depthBefore = bce->stackDepth;
         if (!EmitDestructuringLHS(cx, bce, subpattern, emitOption))
             return false;
 
         // If emitOption is InitializeVars, destructuring initialized each
         // target in the subpattern's LHS as it went, then popped PROP.  We've
         // correctly returned to the loop-entry stack, and we continue to the
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -3380,16 +3380,18 @@ Parser<FullParseHandler>::checkDestructu
     for (ParseNode *member = objectPattern->pn_head; member; member = member->pn_next) {
         ParseNode *expr;
         if (member->isKind(PNK_MUTATEPROTO)) {
             expr = member->pn_kid;
         } else {
             MOZ_ASSERT(member->isKind(PNK_COLON) || member->isKind(PNK_SHORTHAND));
             expr = member->pn_right;
         }
+        if (expr->isKind(PNK_ASSIGN))
+            expr = expr->pn_left;
 
         bool ok;
         if (expr->isKind(PNK_ARRAY) || expr->isKind(PNK_OBJECT)) {
             ok = checkDestructuring(data, expr);
         } else if (data) {
             if (!expr->isKind(PNK_NAME)) {
                 report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME);
                 return false;
@@ -3424,16 +3426,18 @@ Parser<FullParseHandler>::checkDestructu
             }
             target = target->pn_kid;
 
             // The RestElement should not support nested patterns.
             if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) {
                 report(ParseError, false, target, JSMSG_BAD_DESTRUCT_TARGET);
                 return false;
             }
+        } else if (target->isKind(PNK_ASSIGN)) {
+            target = target->pn_left;
         }
 
         bool ok;
         if (target->isKind(PNK_ARRAY) || target->isKind(PNK_OBJECT)) {
             ok = checkDestructuring(data, target);
         } else {
             if (data) {
                 if (!target->isKind(PNK_NAME)) {
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -138,23 +138,21 @@ struct AutoStopVerifyingBarriers
 };
 #endif /* JS_GC_ZEAL */
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 void
 CheckHashTablesAfterMovingGC(JSRuntime *rt);
 #endif
 
-#ifdef JSGC_COMPACTING
 struct MovingTracer : JSTracer {
     explicit MovingTracer(JSRuntime *rt) : JSTracer(rt, Visit, TraceWeakMapKeysValues) {}
 
     static void Visit(JSTracer *jstrc, void **thingp, JSGCTraceKind kind);
     static bool IsMovingTracer(JSTracer *trc) {
         return trc->callback == Visit;
     }
 };
-#endif
 
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* gc_GCInternals_h */
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -29,21 +29,18 @@ class AutoLockGC;
 namespace gc {
 
 typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
 
 struct FinalizePhase;
 class MarkingValidator;
 struct AutoPrepareForTracing;
 class AutoTraceSession;
-
-#ifdef JSGC_COMPACTING
 struct ArenasToUpdate;
 struct MovingTracer;
-#endif
 
 class ChunkPool
 {
     Chunk *head_;
     size_t count_;
 
   public:
     ChunkPool() : head_(nullptr), count_(0) {}
@@ -292,21 +289,17 @@ class GCRuntime
 
     void setParameter(JSGCParamKey key, uint32_t value);
     uint32_t getParameter(JSGCParamKey key, const AutoLockGC &lock);
 
     bool isHeapBusy() { return heapState != js::Idle; }
     bool isHeapMajorCollecting() { return heapState == js::MajorCollecting; }
     bool isHeapMinorCollecting() { return heapState == js::MinorCollecting; }
     bool isHeapCollecting() { return isHeapMajorCollecting() || isHeapMinorCollecting(); }
-#ifdef JSGC_COMPACTING
     bool isHeapCompacting() { return isHeapMajorCollecting() && state() == COMPACT; }
-#else
-    bool isHeapCompacting() { return false; }
-#endif
 
     bool triggerGC(JS::gcreason::Reason reason);
     void maybeAllocTriggerZoneGC(Zone *zone, const AutoLockGC &lock);
     bool triggerZoneGC(Zone *zone, JS::gcreason::Reason reason);
     bool maybeGC(Zone *zone);
     void maybePeriodicFullGC();
     void minorGC(JS::gcreason::Reason reason) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MINOR_GC);
@@ -432,21 +425,19 @@ class GCRuntime
 
     bool isIncrementalGCEnabled() { return mode == JSGC_MODE_INCREMENTAL && incrementalAllowed; }
     bool isIncrementalGCInProgress() { return state() != gc::NO_INCREMENTAL; }
 
     bool isGenerationalGCEnabled() { return generationalDisabled == 0; }
     void disableGenerationalGC();
     void enableGenerationalGC();
 
-#ifdef JSGC_COMPACTING
     void disableCompactingGC();
     void enableCompactingGC();
     bool isCompactingGCEnabled();
-#endif
 
     void setGrayRootsTracer(JSTraceDataOp traceOp, void *data);
     bool addBlackRootsTracer(JSTraceDataOp traceOp, void *data);
     void removeBlackRootsTracer(JSTraceDataOp traceOp, void *data);
 
     void setMaxMallocBytes(size_t value);
     void resetMallocBytes();
     bool isTooMuchMalloc() const { return mallocBytes <= 0; }
@@ -599,30 +590,28 @@ class GCRuntime
     void decommitAllWithoutUnlocking(const AutoLockGC &lock);
     void decommitArenas(AutoLockGC &lock);
     void expireChunksAndArenas(bool shouldShrink, AutoLockGC &lock);
     void queueZonesForBackgroundSweep(ZoneList &zones);
     void sweepBackgroundThings(ZoneList &zones, LifoAlloc &freeBlocks, ThreadType threadType);
     void assertBackgroundSweepingFinished();
     bool shouldCompact();
     bool compactPhase(bool lastGC);
-#ifdef JSGC_COMPACTING
     void sweepTypesAfterCompacting(Zone *zone);
     void sweepZoneAfterCompacting(Zone *zone);
     ArenaHeader *relocateArenas();
-    void updateAllCellPointersParallel(ArenasToUpdate &source);
-    void updateAllCellPointersSerial(MovingTracer *trc, ArenasToUpdate &source);
+    void updateAllCellPointersParallel(MovingTracer *trc);
+    void updateAllCellPointersSerial(MovingTracer *trc);
     void updatePointersToRelocatedCells();
     void releaseRelocatedArenas(ArenaHeader *relocatedList);
     void releaseRelocatedArenasWithoutUnlocking(ArenaHeader *relocatedList, const AutoLockGC& lock);
 #ifdef DEBUG
     void protectRelocatedArenas(ArenaHeader *relocatedList);
     void unprotectRelocatedArenas(ArenaHeader *relocatedList);
 #endif
-#endif
     void finishCollection();
 
     void computeNonIncrementalMarkingForValidation();
     void validateIncrementalMarking();
     void finishMarkingValidation();
 
     void markConservativeStackRoots(JSTracer *trc, bool useSavedRoots);
 
@@ -806,23 +795,21 @@ class GCRuntime
      */
     bool incrementalAllowed;
 
     /*
      * GGC can be enabled from the command line while testing.
      */
     unsigned generationalDisabled;
 
-#ifdef JSGC_COMPACTING
     /*
      * Some code cannot tolerate compacting GC so it can be disabled with this
      * counter.
      */
     unsigned compactingDisabled;
-#endif
 
     /*
      * This is true if we are in the middle of a brain transplant (e.g.,
      * JS_TransplantObject) or some other operation that can manipulate
      * dead zones.
      */
     bool manipulatingDeadZones;
 
@@ -913,19 +900,17 @@ class GCRuntime
      * understand. In those cases, we trade the static analysis for a dynamic
      * analysis. When this is non-zero, we should assert if we trigger, or
      * might trigger, a GC.
      */
     int inUnsafeRegion;
 
     size_t noGCOrAllocationCheck;
 
-#ifdef JSGC_COMPACTING
     ArenaHeader* relocatedArenasToRelease;
-#endif
 
 #endif
 
     /* Synchronize GC heap access between main thread and GCHelperState. */
     PRLock *lock;
     mozilla::DebugOnly<PRThread *> lockOwner;
 
     BackgroundAllocTask allocTask;
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -637,20 +637,18 @@ struct ArenaHeader
     inline void setNextAllocDuringSweep(ArenaHeader *aheader);
     inline void unsetAllocDuringSweep();
 
     inline void setNextArenaToUpdate(ArenaHeader *aheader);
     inline ArenaHeader *getNextArenaToUpdateAndUnlink();
 
     void unmarkAll();
 
-#ifdef JSGC_COMPACTING
     size_t countUsedCells();
     size_t countFreeCells();
-#endif
 };
 static_assert(ArenaZoneOffset == offsetof(ArenaHeader, zone),
               "The hardcoded API zone offset must match the actual offset.");
 
 struct Arena
 {
     /*
      * Layout of an arena:
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -156,46 +156,37 @@ CheckMarkedThing(JSTracer *trc, T **thin
 {
 #ifdef DEBUG
     MOZ_ASSERT(trc);
     MOZ_ASSERT(thingp);
 
     T *thing = *thingp;
     MOZ_ASSERT(*thingp);
 
-#ifdef JSGC_COMPACTING
     thing = MaybeForwarded(thing);
-#endif
 
     /* This function uses data that's not available in the nursery. */
     if (IsInsideNursery(thing))
         return;
 
-#ifdef JSGC_COMPACTING
     MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc) && !Nursery::IsMinorCollectionTracer(trc),
                   !IsForwarded(*thingp));
-#endif
 
     /*
      * Permanent atoms are not associated with this runtime, but will be ignored
      * during marking.
      */
     if (ThingIsPermanentAtom(thing))
         return;
 
     Zone *zone = thing->zoneFromAnyThread();
     JSRuntime *rt = trc->runtime();
 
-#ifdef JSGC_COMPACTING
     MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc), CurrentThreadCanAccessZone(zone));
     MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc), CurrentThreadCanAccessRuntime(rt));
-#else
-    MOZ_ASSERT(CurrentThreadCanAccessZone(zone));
-    MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
-#endif
 
     MOZ_ASSERT(zone->runtimeFromAnyThread() == trc->runtime());
     MOZ_ASSERT(trc->hasTracingDetails());
 
     bool isGcMarkingTracer = IS_GC_MARKING_TRACER(trc);
 
     MOZ_ASSERT_IF(zone->requireGCTracer(), isGcMarkingTracer);
 
@@ -432,20 +423,18 @@ IsMarkedFromAnyThread(T **thingp)
     if (IsInsideNursery(*thingp)) {
         Nursery &nursery = rt->gc.nursery;
         return nursery.getForwardedPointer(thingp);
     }
 
     Zone *zone = (*thingp)->asTenured().zoneFromAnyThread();
     if (!zone->isCollectingFromAnyThread() || zone->isGCFinished())
         return true;
-#ifdef JSGC_COMPACTING
     if (zone->isGCCompacting() && IsForwarded(*thingp))
         *thingp = Forwarded(*thingp);
-#endif
     return (*thingp)->asTenured().isMarked();
 }
 
 template <typename T>
 static bool
 IsAboutToBeFinalized(T **thingp)
 {
     MOZ_ASSERT_IF(!ThingIsPermanentAtom(*thingp),
@@ -476,22 +465,20 @@ IsAboutToBeFinalizedFromAnyThread(T **th
     }
 
     Zone *zone = thing->asTenured().zoneFromAnyThread();
     if (zone->isGCSweeping()) {
         if (thing->asTenured().arenaHeader()->allocatedDuringIncremental)
             return false;
         return !thing->asTenured().isMarked();
     }
-#ifdef JSGC_COMPACTING
     else if (zone->isGCCompacting() && IsForwarded(thing)) {
         *thingp = Forwarded(thing);
         return false;
     }
-#endif
 
     return false;
 }
 
 template <typename T>
 T *
 UpdateIfRelocated(JSRuntime *rt, T **thingp)
 {
@@ -499,21 +486,20 @@ UpdateIfRelocated(JSRuntime *rt, T **thi
     if (!*thingp)
         return nullptr;
 
     if (rt->isHeapMinorCollecting() && IsInsideNursery(*thingp)) {
         rt->gc.nursery.getForwardedPointer(thingp);
         return *thingp;
     }
 
-#ifdef JSGC_COMPACTING
     Zone *zone = (*thingp)->zone();
     if (zone->isGCCompacting() && IsForwarded(*thingp))
         *thingp = Forwarded(*thingp);
-#endif
+
     return *thingp;
 }
 
 #define DeclMarkerImpl(base, type)                                                                \
 void                                                                                              \
 Mark##base(JSTracer *trc, BarrieredBase<type*> *thing, const char *name)                          \
 {                                                                                                 \
     Mark<type>(trc, thing, name);                                                                 \
@@ -1810,20 +1796,18 @@ GCMarker::processMarkStackTop(SliceBudge
         PushMarkStack(this, shape);
 
         /* Call the trace hook if necessary. */
         const Class *clasp = type->clasp();
         if (clasp->trace) {
             // Global objects all have the same trace hook. That hook is safe without barriers
             // if the global has no custom trace hook of its own, or has been moved to a different
             // compartment, and so can't have one.
-            MOZ_ASSERT_IF(runtime()->gc.isIncrementalGCEnabled() &&
-                          !(clasp->trace == JS_GlobalObjectTraceHook &&
-                            (!obj->compartment()->options().getTrace() ||
-                             !obj->isOwnGlobal())),
+            MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook &&
+                            (!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())),
                           clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
             if (clasp->trace == InlineTypedObject::obj_trace)
                 goto scan_typed_obj;
             clasp->trace(this, obj);
         }
 
         if (!shape->isNative())
             return;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/destructuring-default.js
@@ -0,0 +1,166 @@
+
+load(libdir + 'asserts.js');
+load(libdir + 'eqArrayHelper.js');
+
+var arrayPattern = '[a = 1, b = 2, c = 3, d = 4, e = 5, f = 6]';
+var objectPattern = '{0: a = 1, 1: b = 2, 2: c = 3, 3: d = 4, 4: e = 5, 5: f = 6}';
+var nestedPattern = '{a: a = 1, b: [b = 2] = [], c: {c: [c]} = {c: [3]}, d: {d, e} = {d: 4, e: 5}, f: f = 6}';
+
+function testAll(fn) {
+  assertEqArray(fn(arrayPattern, []), [1, 2, 3, 4, 5, 6]);
+  assertEqArray(fn(arrayPattern, [2, 3, 4, 5, 6, 7, 8, 9]), [2, 3, 4, 5, 6, 7]);
+  assertEqArray(fn(arrayPattern, [undefined, 0, false, null, "", undefined]), [1, 0, false, null, "", 6]);
+  assertEqArray(fn(arrayPattern, [0, false]), [0, false, 3, 4, 5, 6]);
+
+  assertEqArray(fn(objectPattern, []), [1, 2, 3, 4, 5, 6]);
+  assertEqArray(fn(objectPattern, [2, 3, 4, 5, 6, 7, 8, 9]), [2, 3, 4, 5, 6, 7]);
+  assertEqArray(fn(objectPattern, [undefined, 0, false, null, "", undefined]), [1, 0, false, null, "", 6]);
+  assertEqArray(fn(objectPattern, [0, false]), [0, false, 3, 4, 5, 6]);
+
+  assertEqArray(fn(nestedPattern, {}), [1, 2, 3, 4, 5, 6]);
+  assertEqArray(fn(nestedPattern, {a: 2, b: [], c: undefined}), [2, 2, 3, 4, 5, 6]);
+  assertEqArray(fn(nestedPattern, {a: undefined, b: [3], c: {c: [4]}}), [1, 3, 4, 4, 5, 6]);
+  assertEqArray(fn(nestedPattern, {a: undefined, b: [3], c: {c: [4]}, d: {d: 5, e: 6}}), [1, 3, 4, 5, 6, 6]);
+}
+
+function testVar(pattern, input) {
+  return new Function('input',
+    'var ' + pattern + ' = input;' +
+    'return [a, b, c, d, e, f];'
+  )(input);
+}
+testAll(testVar);
+
+function testLet(pattern, input) {
+  return new Function('input',
+    'let ' + pattern + ' = input;' +
+    'return [a, b, c, d, e, f];'
+  )(input);
+}
+testAll(testLet);
+
+function testConst(pattern, input) {
+  return new Function('input',
+    'const ' + pattern + ' = input;' +
+    'return [a, b, c, d, e, f];'
+  )(input);
+}
+testAll(testConst);
+
+function testGlobal(pattern, input) {
+  return new Function('input',
+    '(' + pattern + ') = input;' +
+    'return [a, b, c, d, e, f];'
+  )(input);
+}
+testAll(testGlobal);
+
+function testClosure(pattern, input) {
+  return new Function('input',
+    'var rest; (function () {' +
+    '(' + pattern + ') = input;' +
+    '})();' +
+    'return [a, b, c, d, e, f];'
+  )(input);
+}
+testAll(testClosure);
+
+function testArgument(pattern, input) {
+  return new Function('input',
+    'return (function (' + pattern + ') {' +
+    'return [a, b, c, d, e, f]; })(input);'
+  )(input);
+}
+testAll(testArgument);
+
+function testArgumentFunction(pattern, input) {
+  return new Function(pattern,
+    'return [a, b, c, d, e, f];'
+  )(input);
+}
+// XXX: ES6 requires the `Function` constructor to accept arbitrary
+// `BindingElement`s as formal parameters. See Bug 1037939.
+// Once fixed, please update the assertions below.
+assertThrowsInstanceOf(() => testAll(testArgumentFunction), SyntaxError);
+
+function testThrow(pattern, input) {
+  return new Function('input',
+    'try { throw input }' +
+    'catch(' + pattern + ') {' +
+    'return [a, b, c, d, e, f]; }'
+  )(input);
+}
+testAll(testThrow);
+
+// XXX: Support for let blocks and expressions will be removed in bug 1023609.
+// However, they test a special code path in destructuring assignment so having
+// these tests here for now seems like a good idea.
+function testLetBlock(pattern, input) {
+  return new Function('input',
+    'let (' + pattern + ' = input)' +
+    '{ return [a, b, c, d, e, f]; }'
+  )(input);
+}
+testAll(testLetBlock);
+
+function testLetExpression(pattern, input) {
+  return new Function('input',
+    'return (let (' + pattern + ' = input) [a, b, c, d, e, f]);'
+  )(input);
+}
+testAll(testLetExpression);
+
+// test global const
+const [ca = 1, cb = 2] = [];
+assertEq(ca, 1);
+assertEq(cb, 2);
+
+const {a: {a: cc = 3} = {a: undefined}} = {};
+assertEq(cc, 3);
+
+// test that the assignment happens in source order
+var a = undefined, b = undefined, c = undefined;
+({a: a = 1, c: c = 2, b: b = 3}) = {
+  get a() {
+    assertEq(a, undefined);
+    assertEq(c, undefined);
+    assertEq(b, undefined);
+    return undefined;
+  },
+  get b() {
+    assertEq(a, 1);
+    assertEq(c, 2);
+    assertEq(b, undefined);
+    return 4;
+  },
+  get c() {
+    assertEq(a, 1);
+    assertEq(c, undefined);
+    assertEq(b, undefined);
+    return undefined;
+  }
+};
+assertEq(b, 4);
+
+assertThrowsInstanceOf(() => { var {a: {a} = null} = {}; }, TypeError);
+assertThrowsInstanceOf(() => { var [[a] = 2] = []; }, TypeError);
+
+// destructuring assignment might have  duplicate variable names.
+var [a = 1, a = 2] = [3];
+assertEq(a, 2);
+
+// assignment to properties of default params
+[a = {y: 2}, a.x = 1] = [];
+assertEq(typeof a, 'object');
+assertEq(a.x, 1);
+assertEq(a.y, 2);
+
+// defaults are evaluated even if there is no binding
+var evaled = false;
+({a: {} = (evaled = true, null)}) = {};
+assertEq(evaled, true);
+evaled = false;
+assertThrowsInstanceOf(() => { [[] = (evaled = true, 2)] = [] }, TypeError);
+assertEq(evaled, true);
+
+assertThrowsInstanceOf(() => new Function('var [...rest = defaults] = [];'), SyntaxError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/simd-bug1123631.js
@@ -0,0 +1,9 @@
+if (!this.hasOwnProperty("SIMD"))
+  quit();
+
+var float64x2 = SIMD.float64x2;
+function test() {
+  var a = float64x2(1, 2);
+}
+test();
+test();
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2525,19 +2525,18 @@ IonBuilder::inlineConstructSimdObject(Ca
     MIRType simdType;
     switch (descr->type()) {
       case SimdTypeDescr::TYPE_INT32:
         simdType = MIRType_Int32x4;
         break;
       case SimdTypeDescr::TYPE_FLOAT32:
         simdType = MIRType_Float32x4;
         break;
-      default:
-        MOZ_CRASH("Unknown SIMD kind when generating MSimdBox instruction.");
-        return InliningStatus_NotInlined;
+      case SimdTypeDescr::TYPE_FLOAT64:
+        return InliningStatus_NotInlined; // :TODO: NYI (Bug 1124205)
     }
 
     // We do not inline SIMD constructors if the number of arguments does not
     // match the number of lanes.
     if (SimdTypeToLength(simdType) != callInfo.argc())
         return InliningStatus_NotInlined;
 
     // Take the templateObject out of Baseline ICs, such that we can box
--- a/js/src/js-config.h.in
+++ b/js/src/js-config.h.in
@@ -26,19 +26,16 @@
 
 /* Define to 1 if SpiderMonkey should support the ability to perform
    entirely too much GC.  */
 #undef JS_GC_ZEAL
 
 /* Define to 1 if SpiderMonkey should use small chunks. */
 #undef JS_GC_SMALL_CHUNK_SIZE
 
-/* Define to 1 if SpiderMonkey should use Compacting GC. */
-#undef JSGC_COMPACTING
-
 /* Define to 1 if the <endian.h> header is present and
    useable.  See jscpucfg.h.  */
 #undef JS_HAVE_ENDIAN_H
 
 /* Define to 1 if the <machine/endian.h> header is present and
    useable.  See jscpucfg.h.  */
 #undef JS_HAVE_MACHINE_ENDIAN_H
 
--- a/js/src/jsapi-tests/testPersistentRooted.cpp
+++ b/js/src/jsapi-tests/testPersistentRooted.cpp
@@ -16,17 +16,17 @@ struct BarkWhenTracedClass {
     static void trace(JSTracer *trc, JSObject *obj) { traceCount++; }
     static void reset() { finalizeCount = 0; traceCount = 0; }
 };
 
 int BarkWhenTracedClass::finalizeCount;
 int BarkWhenTracedClass::traceCount;
 
 const JSClass BarkWhenTracedClass::class_ = {
-    "BarkWhenTracedClass", 0,
+    "BarkWhenTracedClass", JSCLASS_IMPLEMENTS_BARRIERS,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     finalize,
--- a/js/src/jsapi-tests/testWeakMap.cpp
+++ b/js/src/jsapi-tests/testWeakMap.cpp
@@ -61,20 +61,16 @@ checkSize(JS::HandleObject map, uint32_t
     uint32_t length;
     CHECK(JS_GetArrayLength(cx, keys, &length));
     CHECK(length == expected);
 
     return true;
 }
 END_TEST(testWeakMap_basicOperations)
 
-// TODO: this test stores object pointers in a private slot which is not marked
-// and so doesn't work with compacting GC.
-#ifndef JSGC_COMPACTING
-
 BEGIN_TEST(testWeakMap_keyDelegates)
 {
     JS_SetGCParameter(rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
     JS_GC(rt);
 
     JS::RootedObject map(cx, JS::NewWeakMapObject(cx));
     CHECK(map);
 
@@ -248,10 +244,8 @@ checkSize(JS::HandleObject map, uint32_t
 
     uint32_t length;
     CHECK(JS_GetArrayLength(cx, keys, &length));
     CHECK(length == expected);
 
     return true;
 }
 END_TEST(testWeakMap_keyDelegates)
-
-#endif
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -644,36 +644,32 @@ JSCompartment::sweepCrossCompartmentWrap
         } else if (key.wrapped != e.front().key().wrapped ||
                    key.debugger != e.front().key().debugger)
         {
             e.rekeyFront(key);
         }
     }
 }
 
-#ifdef JSGC_COMPACTING
-
 void JSCompartment::fixupAfterMovingGC()
 {
     fixupGlobal();
     fixupNewTypeObjectTable(newTypeObjects);
     fixupNewTypeObjectTable(lazyTypeObjects);
     fixupInitialShapeTable();
 }
 
 void
 JSCompartment::fixupGlobal()
 {
     GlobalObject *global = *global_.unsafeGet();
     if (global)
         global_.set(MaybeForwarded(global));
 }
 
-#endif // JSGC_COMPACTING
-
 void
 JSCompartment::purge()
 {
     dtoaCache.purge();
 }
 
 void
 JSCompartment::clearTables()
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -393,22 +393,20 @@ struct JSCompartment
     void sweepRegExps();
     void sweepDebugScopes();
     void sweepWeakMaps();
     void sweepNativeIterators();
 
     void purge();
     void clearTables();
 
-#ifdef JSGC_COMPACTING
     void fixupInitialShapeTable();
     void fixupNewTypeObjectTable(js::types::NewTypeObjectTable &table);
     void fixupAfterMovingGC();
     void fixupGlobal();
-#endif
 
     bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
     void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
     void forgetObjectMetadataCallback() {
         objectMetadataCallback = nullptr;
     }
     bool callObjectMetadataCallback(JSContext *cx, JSObject **obj) const {
         return objectMetadataCallback(cx, obj);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1107,19 +1107,17 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     arenasAllocatedDuringSweep(nullptr),
 #ifdef JS_GC_MARKING_VALIDATION
     markingValidator(nullptr),
 #endif
     interFrameGC(false),
     sliceBudget(SliceBudget::Unlimited),
     incrementalAllowed(true),
     generationalDisabled(0),
-#ifdef JSGC_COMPACTING
     compactingDisabled(0),
-#endif
     manipulatingDeadZones(false),
     objectsMarkedInDeadZones(0),
     poked(false),
     heapState(Idle),
 #ifdef JS_GC_ZEAL
     zealMode(0),
     zealFrequency(0),
     nextScheduled(0),
@@ -1129,20 +1127,18 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     validate(true),
     fullCompartmentChecks(false),
     mallocBytes(0),
     mallocGCTriggered(false),
     alwaysPreserveCode(false),
 #ifdef DEBUG
     inUnsafeRegion(0),
     noGCOrAllocationCheck(0),
-#ifdef JSGC_COMPACTING
     relocatedArenasToRelease(nullptr),
 #endif
-#endif
     lock(nullptr),
     lockOwner(nullptr),
     allocTask(rt, emptyChunks_),
     helperState(rt)
 {
     setGCMode(JSGC_MODE_GLOBAL);
 }
 
@@ -1925,24 +1921,18 @@ ArenaLists::allocateFromArenaInner(JS::Z
     return thing;
 }
 
 /* Compacting GC */
 
 bool
 GCRuntime::shouldCompact()
 {
-#ifdef JSGC_COMPACTING
     return invocationKind == GC_SHRINK && isCompactingGCEnabled();
-#else
-    return false;
-#endif
-}
-
-#ifdef JSGC_COMPACTING
+}
 
 void
 GCRuntime::disableCompactingGC()
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
     ++rt->gc.compactingDisabled;
 }
 
@@ -2368,43 +2358,58 @@ UpdateCellPointers(MovingTracer *trc, Ar
     }
 }
 
 namespace js {
 namespace gc {
 
 struct ArenasToUpdate
 {
-    explicit ArenasToUpdate(JSRuntime *rt);
+    enum KindsToUpdate {
+        FOREGROUND = 1,
+        BACKGROUND = 2,
+        ALL = FOREGROUND | BACKGROUND
+    };
+    ArenasToUpdate(JSRuntime *rt, KindsToUpdate kinds);
     bool done() { return initialized && arena == nullptr; }
     ArenaHeader* next();
     ArenaHeader *getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned max);
 
   private:
     bool initialized;
+    KindsToUpdate kinds;
     GCZonesIter zone;    // Current zone to process, unless zone.done()
     unsigned kind;       // Current alloc kind to process
     ArenaHeader *arena;  // Next arena to process
 
     bool shouldProcessKind(unsigned kind);
 };
 
 bool ArenasToUpdate::shouldProcessKind(unsigned kind)
 {
     MOZ_ASSERT(kind < FINALIZE_LIMIT);
-    return
-        kind != FINALIZE_FAT_INLINE_STRING &&
-        kind != FINALIZE_STRING &&
-        kind != FINALIZE_EXTERNAL_STRING &&
-        kind != FINALIZE_SYMBOL;
-}
-
-ArenasToUpdate::ArenasToUpdate(JSRuntime *rt)
-  : initialized(false), zone(rt, SkipAtoms)
-{}
+    if (kind == FINALIZE_FAT_INLINE_STRING ||
+        kind == FINALIZE_STRING ||
+        kind == FINALIZE_EXTERNAL_STRING ||
+        kind == FINALIZE_SYMBOL)
+    {
+        return false;
+    }
+
+    if (kind > FINALIZE_OBJECT_LAST || js::gc::IsBackgroundFinalized(AllocKind(kind)))
+        return (kinds & BACKGROUND) != 0;
+    else
+        return (kinds & FOREGROUND) != 0;
+}
+
+ArenasToUpdate::ArenasToUpdate(JSRuntime *rt, KindsToUpdate kinds)
+  : initialized(false), kinds(kinds), zone(rt, SkipAtoms)
+{
+    MOZ_ASSERT(kinds && !(kinds & ~ALL));
+}
 
 ArenaHeader *
 ArenasToUpdate::next()
 {
     // Find the next arena to update.
     //
     // Note that this uses a generator-like arrangement. The first time this is
     // called, |initialized| is false and the for-loops below are entered in the
@@ -2521,42 +2526,46 @@ UpdateCellPointersTask::run()
         }
     }
 }
 
 } // namespace gc
 } // namespace js
 
 void
-GCRuntime::updateAllCellPointersParallel(ArenasToUpdate &source)
+GCRuntime::updateAllCellPointersParallel(MovingTracer *trc)
 {
     AutoDisableProxyCheck noProxyCheck(rt); // These checks assert when run in parallel.
 
     const size_t minTasks = 2;
     const size_t maxTasks = 8;
     unsigned taskCount = Min(Max(HelperThreadState().cpuCount / 2, minTasks),
-                             maxTasks);
+                             maxTasks) + 1;
     UpdateCellPointersTask updateTasks[maxTasks];
 
+    ArenasToUpdate fgArenas(rt, ArenasToUpdate::FOREGROUND);
+    ArenasToUpdate bgArenas(rt, ArenasToUpdate::BACKGROUND);
     AutoLockHelperThreadState lock;
     unsigned i;
-    for (i = 0; i < taskCount && !source.done(); ++i) {
-        updateTasks[i].init(rt, &source, lock);
+    for (i = 0; i < taskCount && !bgArenas.done(); ++i) {
+        ArenasToUpdate *source = i == 0 ? &fgArenas : &bgArenas;
+        updateTasks[i].init(rt, source, lock);
         startTask(updateTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
     }
     unsigned tasksStarted = i;
 
     for (i = 0; i < tasksStarted; ++i)
         joinTask(updateTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
 }
 
 void
-GCRuntime::updateAllCellPointersSerial(MovingTracer *trc, ArenasToUpdate &source)
-{
-    while (ArenaHeader *arena = source.next())
+GCRuntime::updateAllCellPointersSerial(MovingTracer *trc)
+{
+    ArenasToUpdate allArenas(rt, ArenasToUpdate::ALL);
+    while (ArenaHeader *arena = allArenas.next())
         UpdateCellPointers(trc, arena);
 }
 
 /*
  * Update pointers to relocated cells by doing a full heap traversal and sweep.
  *
  * The latter is necessary to update weak references which are not marked as
  * part of the traversal.
@@ -2575,21 +2584,20 @@ GCRuntime::updatePointersToRelocatedCell
 
     // Fixup cross compartment wrappers as we assert the existence of wrappers in the map.
     for (CompartmentsIter comp(rt, SkipAtoms); !comp.done(); comp.next())
         comp->sweepCrossCompartmentWrappers();
 
     // Iterate through all cells that can contain JSObject pointers to update
     // them. Since updating each cell is independent we try to parallelize this
     // as much as possible.
-    ArenasToUpdate source(rt);
     if (CanUseExtraThreads())
-        updateAllCellPointersParallel(source);
+        updateAllCellPointersParallel(&trc);
     else
-        updateAllCellPointersSerial(&trc, source);
+        updateAllCellPointersSerial(&trc);
 
     // Mark roots to update them.
     {
         markRuntime(&trc, MarkRuntime);
 
         gcstats::AutoPhase ap(stats, gcstats::PHASE_MARK_ROOTS);
         Debugger::markAll(&trc);
         Debugger::markAllCrossCompartmentEdges(&trc);
@@ -2692,22 +2700,20 @@ GCRuntime::releaseRelocatedArenasWithout
                   JS_MOVED_TENURED_PATTERN, Arena::thingsSpan(thingSize));
 #endif
 
         releaseArena(aheader, lock);
         ++count;
     }
 }
 
-#endif // JSGC_COMPACTING
-
 void
 GCRuntime::releaseHeldRelocatedArenas()
 {
-#if defined(JSGC_COMPACTING) && defined(DEBUG)
+#ifdef DEBUG
     // In debug mode we don't release relocated arenas straight away.  Instead
     // we protect them and hold onto them until the next GC sweep phase to catch
     // any pointers to them that didn't get forwarded.
     unprotectRelocatedArenas(relocatedArenasToRelease);
     releaseRelocatedArenas(relocatedArenasToRelease);
     relocatedArenasToRelease = nullptr;
 #endif
 }
@@ -5457,19 +5463,16 @@ GCRuntime::endSweepPhase(bool lastGC)
         }
     }
 #endif
 }
 
 bool
 GCRuntime::compactPhase(bool lastGC)
 {
-#ifndef JSGC_COMPACTING
-    MOZ_CRASH();
-#else
     gcstats::AutoPhase ap(stats, gcstats::PHASE_COMPACT);
 
     if (isIncremental) {
         // Poll for end of background sweeping
         AutoLockGC lock(rt);
         if (isBackgroundSweeping())
             return false;
     } else {
@@ -5524,18 +5527,16 @@ GCRuntime::compactPhase(bool lastGC)
                     for (ArenaHeader *arena = al.arenaAfterCursor(); arena; arena = arena->next)
                         freeCells += arena->countFreeCells();
                     MOZ_ASSERT(freeCells < thingsPerArena);
                 }
             }
         }
     }
 #endif
-
-#endif // JSGC_COMPACTING
     return true;
 }
 
 void
 GCRuntime::finishCollection()
 {
     MOZ_ASSERT(marker.isDrained());
     marker.stop();
@@ -5685,33 +5686,31 @@ GCRuntime::resetIncrementalGC(const char
 
         {
             gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
             rt->gc.waitBackgroundSweepOrAllocEnd();
         }
         break;
       }
 
-#ifdef JSGC_COMPACTING
       case COMPACT: {
         {
             gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
             rt->gc.waitBackgroundSweepOrAllocEnd();
         }
 
         JSGCInvocationKind oldInvocationKind = invocationKind;
         invocationKind = GC_NORMAL;
 
         SliceBudget budget;
         incrementalCollectSlice(budget, JS::gcreason::RESET);
 
         invocationKind = oldInvocationKind;
         break;
       }
-#endif
 
       default:
         MOZ_CRASH("Invalid incremental GC state");
     }
 
     stats.reset(reason);
 
 #ifdef DEBUG
@@ -6389,17 +6388,17 @@ GCRuntime::onOutOfMallocMemory()
     onOutOfMallocMemory(lock);
 }
 
 void
 GCRuntime::onOutOfMallocMemory(const AutoLockGC &lock)
 {
     // Release any relocated arenas we may be holding on to, without releasing
     // the GC lock.
-#if defined(JSGC_COMPACTING) && defined(DEBUG)
+#ifdef DEBUG
     unprotectRelocatedArenas(relocatedArenasToRelease);
     releaseRelocatedArenasWithoutUnlocking(relocatedArenasToRelease, lock);
     relocatedArenasToRelease = nullptr;
 #endif
 
     // Throw away any excess chunks we have lying around.
     freeEmptyChunks(rt, lock);
 
@@ -7110,29 +7109,23 @@ JS_PUBLIC_API(bool)
 JS::IsIncrementalGCEnabled(JSRuntime *rt)
 {
     return rt->gc.isIncrementalGCEnabled();
 }
 
 JS_PUBLIC_API(void)
 JS::DisableCompactingGC(JSRuntime *rt)
 {
-#ifdef JSGC_COMPACTING
     rt->gc.disableCompactingGC();
-#endif
 }
 
 JS_PUBLIC_API(bool)
 JS::IsCompactingGCEnabled(JSRuntime *rt)
 {
-#ifdef JSGC_COMPACTING
     return rt->gc.isCompactingGCEnabled();
-#else
-    return false;
-#endif
 }
 
 JS_PUBLIC_API(bool)
 JS::IsIncrementalGCInProgress(JSRuntime *rt)
 {
     return rt->gc.isIncrementalGCInProgress() && !rt->gc.isVerifyPreBarriersEnabled();
 }
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -449,21 +449,19 @@ class ArenaList {
         // Insert the full arenas of |other| after those of |this|.
         *other.cursorp_ = *cursorp_;
         *cursorp_ = other.head_;
         cursorp_ = other.cursorp_;
         check();
         return *this;
     }
 
-#ifdef JSGC_COMPACTING
     ArenaHeader *removeRemainingArenas(ArenaHeader **arenap, const AutoLockGC &lock);
     ArenaHeader *pickArenasToRelocate(JSRuntime *runtime);
     ArenaHeader *relocateArenas(ArenaHeader *toRelocate, ArenaHeader *relocated);
-#endif
 };
 
 /*
  * A class that holds arenas in sorted order by appending arenas to specific
  * segments. Each segment has a head and a tail, which can be linked up to
  * other segments to create a contiguous ArenaList.
  */
 class SortedArenaList
@@ -780,19 +778,17 @@ class ArenaLists
             MOZ_ASSERT(freeLists[i].isEmpty());
 #endif
     }
 
     void checkEmptyFreeList(AllocKind kind) {
         MOZ_ASSERT(freeLists[kind].isEmpty());
     }
 
-#ifdef JSGC_COMPACTING
     ArenaHeader *relocateArenas(ArenaHeader *relocatedList);
-#endif
 
     void queueForegroundObjectsForSweep(FreeOp *fop);
     void queueForegroundThingsForSweep(FreeOp *fop);
 
     void mergeForegroundSweptObjectArenas();
 
     bool foregroundFinalize(FreeOp *fop, AllocKind thingKind, SliceBudget &sliceBudget,
                             SortedArenaList &sweepList);
@@ -1265,19 +1261,17 @@ MaybeForwarded(T t)
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 template <typename T>
 inline void
 CheckGCThingAfterMovingGC(T *t)
 {
     MOZ_ASSERT_IF(t, !IsInsideNursery(t));
-#ifdef JSGC_COMPACTING
     MOZ_ASSERT_IF(t, !IsForwarded(t));
-#endif
 }
 
 inline void
 CheckValueAfterMovingGC(const JS::Value& value)
 {
     if (value.isObject())
         return CheckGCThingAfterMovingGC(&value.toObject());
     else if (value.isString())
@@ -1424,26 +1418,21 @@ class AutoDisableProxyCheck
 struct AutoDisableProxyCheck
 {
     explicit AutoDisableProxyCheck(JSRuntime *rt) {}
 };
 #endif
 
 struct AutoDisableCompactingGC
 {
-#ifdef JSGC_COMPACTING
     explicit AutoDisableCompactingGC(JSRuntime *rt);
     ~AutoDisableCompactingGC();
 
   private:
     gc::GCRuntime &gc;
-#else
-    explicit AutoDisableCompactingGC(JSRuntime *rt) {}
-    ~AutoDisableCompactingGC() {}
-#endif
 };
 
 void
 PurgeJITCaches(JS::Zone *zone);
 
 // This is the same as IsInsideNursery, but not inlined.
 bool
 UninlinedIsInsideNursery(const gc::Cell *cell);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -4886,18 +4886,16 @@ JSCompartment::sweepNewTypeObjectTable(N
                 /* Any rekeying necessary is handled by fixupNewTypeObjectTable() below. */
                 MOZ_ASSERT(entry.object.unbarrieredGet() == e.front().object.unbarrieredGet());
                 MOZ_ASSERT(entry.associated == e.front().associated);
             }
         }
     }
 }
 
-#ifdef JSGC_COMPACTING
-
 void
 JSCompartment::fixupNewTypeObjectTable(NewTypeObjectTable &table)
 {
     /*
      * Each entry's hash depends on the object's prototype and we can't tell
      * whether that has been moved or not in sweepNewTypeObjectTable().
      */
     MOZ_ASSERT(zone()->isCollecting());
@@ -4961,18 +4959,16 @@ TypeObject::fixupAfterMovingGC()
                 addendum_ = Forwarded(maybeInterpretedFunction());
             break;
           default:
             MOZ_CRASH();
         }
     }
 }
 
-#endif // JSGC_COMPACTING
-
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 void
 JSCompartment::checkTypeObjectTablesAfterMovingGC()
 {
     checkTypeObjectTableAfterMovingGC(newTypeObjects);
     checkTypeObjectTableAfterMovingGC(lazyTypeObjects);
 }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -288,17 +288,17 @@ public:
     /*
      * If the data this constraint refers to is still live, copy it into the
      * zone's new allocator. Type constraints only hold weak references.
      */
     virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0;
 };
 
 /* Flags and other state stored in TypeSet::flags */
-enum MOZ_ENUM_TYPE(uint32_t) {
+enum : uint32_t {
     TYPE_FLAG_UNDEFINED =   0x1,
     TYPE_FLAG_NULL      =   0x2,
     TYPE_FLAG_BOOLEAN   =   0x4,
     TYPE_FLAG_INT32     =   0x8,
     TYPE_FLAG_DOUBLE    =  0x10,
     TYPE_FLAG_STRING    =  0x20,
     TYPE_FLAG_SYMBOL    =  0x40,
     TYPE_FLAG_LAZYARGS  =  0x80,
@@ -347,17 +347,17 @@ enum MOZ_ENUM_TYPE(uint32_t) {
      * Otherwise these bits are clear.
      */
     TYPE_FLAG_DEFINITE_MASK       = 0xfffc0000,
     TYPE_FLAG_DEFINITE_SHIFT      = 18
 };
 typedef uint32_t TypeFlags;
 
 /* Flags and other state stored in TypeObject::flags */
-enum MOZ_ENUM_TYPE(uint32_t) {
+enum : uint32_t {
     /* Whether this type object is associated with some allocation site. */
     OBJECT_FLAG_FROM_ALLOCATION_SITE  = 0x1,
 
     /*
      * If set, the object's prototype might be in the nursery and can't be
      * used during Ion compilation (which may be occurring off thread).
      */
     OBJECT_FLAG_NURSERY_PROTO         = 0x2,
@@ -920,20 +920,17 @@ class TypeNewScript
     }
 
     TypeObject *initializedType() const {
         return initializedType_;
     }
 
     void trace(JSTracer *trc);
     void sweep();
-
-#ifdef JSGC_COMPACTING
     void fixupAfterMovingGC();
-#endif
 
     void registerNewObject(PlainObject *res);
     void unregisterNewObject(PlainObject *res);
     bool maybeAnalyze(JSContext *cx, TypeObject *type, bool *regenerate, bool force = false);
 
     void rollbackPartiallyInitializedObjects(JSContext *cx, TypeObject *type);
 
     static void make(JSContext *cx, TypeObject *type, JSFunction *fun);
@@ -1236,19 +1233,17 @@ struct TypeObject : public gc::TenuredCe
 
   public:
     void setGeneration(uint32_t generation) {
         MOZ_ASSERT(generation <= (OBJECT_FLAG_GENERATION_MASK >> OBJECT_FLAG_GENERATION_SHIFT));
         flags_ &= ~OBJECT_FLAG_GENERATION_MASK;
         flags_ |= generation << OBJECT_FLAG_GENERATION_SHIFT;
     }
 
-#ifdef JSGC_COMPACTING
     void fixupAfterMovingGC();
-#endif
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     inline void finalize(FreeOp *fop);
 
     static inline ThingRootKind rootKind() { return THING_ROOT_TYPE_OBJECT; }
 
     static inline uint32_t offsetOfClasp() {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1227,42 +1227,20 @@ NewObject(ExclusiveContext *cx, types::T
 
     if (newKind == SingletonObject) {
         RootedObject nobj(cx, obj);
         if (!JSObject::setSingletonType(cx, nobj))
             return nullptr;
         obj = nobj;
     }
 
-    /*
-     * This will cancel an already-running incremental GC from doing any more
-     * slices, and it will prevent any future incremental GCs.
-     */
     bool globalWithoutCustomTrace = clasp->trace == JS_GlobalObjectTraceHook &&
                                     !cx->compartment()->options().getTrace();
-    if (clasp->trace &&
-        !globalWithoutCustomTrace &&
-        !(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS))
-    {
-        if (!cx->shouldBeJSContext())
-            return nullptr;
-        JSRuntime *rt = cx->asJSContext()->runtime();
-        rt->gc.disallowIncrementalGC();
-
-#ifdef DEBUG
-        if (rt->gc.gcMode() == JSGC_MODE_INCREMENTAL) {
-            fprintf(stderr,
-                    "The class %s has a trace hook but does not declare the\n"
-                    "JSCLASS_IMPLEMENTS_BARRIERS flag. Please ensure that it correctly\n"
-                    "implements write barriers and then set the flag.\n",
-                    clasp->name);
-            MOZ_CRASH();
-        }
-#endif
-    }
+    if (clasp->trace && !globalWithoutCustomTrace)
+        MOZ_RELEASE_ASSERT(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
 
     probes::CreateObject(cx, obj);
     return obj;
 }
 
 void
 NewObjectCache::fillProto(EntryIndex entry, const Class *clasp, js::TaggedProto proto,
                           gc::AllocKind kind, NativeObject *obj)
@@ -2923,23 +2901,28 @@ js::NonProxyLookupOwnProperty(JSContext 
         {
             return false;
         }
     } else {
         typename MaybeRooted<NativeObject*, allowGC>::HandleType nobj =
             MaybeRooted<JSObject*, allowGC>::template downcastHandle<NativeObject>(obj);
 
         bool done;
-        if (!LookupOwnPropertyInline<allowGC>(cx, nobj, id, objp, propp, &done))
+        if (!LookupOwnPropertyInline<allowGC>(cx, nobj, id, propp, &done))
             return false;
         if (!done) {
             objp.set(nullptr);
             propp.set(nullptr);
             return true;
         }
+
+        if (propp)
+            objp.set(obj);
+        else
+            objp.set(nullptr);
     }
 
     if (!propp)
         return true;
 
     if (objp == obj)
         return true;
 
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -230,18 +230,16 @@ Shape::sweep()
 
 void
 Shape::finalize(FreeOp *fop)
 {
     if (!inDictionary() && kids.isHash())
         fop->delete_(kids.toHash());
 }
 
-#ifdef JSGC_COMPACTING
-
 void
 Shape::fixupDictionaryShapeAfterMovingGC()
 {
     if (!listp)
         return;
 
     // It's possible that this shape is unreachable and that listp points to the
     // location of a dead object in the nursery, in which case we should never
@@ -317,18 +315,16 @@ void
 Shape::fixupAfterMovingGC()
 {
     if (inDictionary())
         fixupDictionaryShapeAfterMovingGC();
     else
         fixupShapeTreeAfterMovingGC();
 }
 
-#endif // JSGC_COMPACTING
-
 void
 ShapeGetterSetterRef::mark(JSTracer *trc)
 {
     // Update the current shape's entry in the parent KidsHash table if needed.
     // This is necessary as the computed hash includes the getter/setter
     // pointers.
 
     JSObject *obj = *objp;
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -15,18 +15,17 @@
 #include "mozilla/LinkedList.h"
 #include "mozilla/PodOperations.h"
 
 #include "jsprototypes.h"
 #include "jstypes.h"
 
 #include "js/TypeDecls.h"
 
-#if (defined(JS_GC_ZEAL)) || \
-    (defined(JSGC_COMPACTING) && defined(DEBUG))
+#if (defined(JS_GC_ZEAL)) || defined(DEBUG)
 # define JSGC_HASH_TABLE_CHECKS
 #endif
 
 namespace JS {
 
 class AutoIdVector;
 class CallArgs;
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -352,16 +352,22 @@ GetContextData(JSContext *cx)
 }
 
 static bool
 ShellInterruptCallback(JSContext *cx)
 {
     if (!gServiceInterrupt)
         return true;
 
+    // Reset gServiceInterrupt. CancelExecution or InterruptIf will set it to
+    // true to distinguish watchdog or user triggered interrupts.
+    // Do this first to prevent other interrupts that may occur while the
+    // user-supplied callback is executing from re-entering the handler.
+    gServiceInterrupt = false;
+
     bool result;
     RootedValue interruptFunc(cx, *gInterruptFunc);
     if (!interruptFunc.isNull()) {
         JS::AutoSaveExceptionState savedExc(cx);
         JSAutoCompartment ac(cx, &interruptFunc.toObject());
         RootedValue rval(cx);
         if (!JS_CallFunctionValue(cx, JS::NullPtr(), interruptFunc,
                                   JS::HandleValueArray::empty(), &rval))
@@ -374,20 +380,16 @@ ShellInterruptCallback(JSContext *cx)
             result = false;
     } else {
         result = false;
     }
 
     if (!result && gExitCode == 0)
         gExitCode = EXITCODE_TIMEOUT;
 
-    // Reset gServiceInterrupt. CancelExecution or InterruptIf will set it to
-    // true to distinguish watchdog or user triggered interrupts.
-    gServiceInterrupt = false;
-
     return result;
 }
 
 /*
  * Some UTF-8 files, notably those written using Notepad, have a Unicode
  * Byte-Order-Mark (BOM) as their first character. This is useless (byte-order
  * is meaningless for UTF-8) but causes a syntax error unless we skip it.
  */
--- a/js/src/tests/js1_8_5/extensions/reflect-parse.js
+++ b/js/src/tests/js1_8_5/extensions/reflect-parse.js
@@ -107,16 +107,21 @@ function idxExpr(idx) Pattern({ type: "G
 
 function compBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: false, of: false })
 function compEachBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: true, of: false })
 function compOfBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: false, of: true })
 
 function arrPatt(elts) Pattern({ type: "ArrayPattern", elements: elts })
 function objPatt(elts) Pattern({ type: "ObjectPattern", properties: elts })
 
+function assignElem(target, defaultExpr = null, targetIdent = typeof target == 'string' ? ident(target) : target) defaultExpr ? aExpr('=', targetIdent, defaultExpr) : targetIdent
+function assignProp(property, target, defaultExpr = null, shorthand = !target, targetProp = target || ident(property)) Pattern({
+    type: "Property", key: ident(property), shorthand,
+    value: defaultExpr ? aExpr('=', targetProp, defaultExpr) : targetProp })
+
 function localSrc(src) "(function(){ " + src + " })"
 function localPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([patt])))])
 function blockSrc(src) "(function(){ { " + src + " } })"
 function blockPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([blockStmt([patt])])))])
 
 function assertBlockStmt(src, patt) {
     blockPatt(patt).assert(Reflect.parse(blockSrc(src)));
 }
@@ -230,17 +235,17 @@ assertDecl("function foo(a=(function () 
 
 // Bug 591437: rebound args have their defs turned into uses
 assertDecl("function f(a) { function a() { } }",
            funDecl(ident("f"), [ident("a")], blockStmt([funDecl(ident("a"), [], blockStmt([]))])));
 assertDecl("function f(a,b,c) { function b() { } }",
            funDecl(ident("f"), [ident("a"),ident("b"),ident("c")], blockStmt([funDecl(ident("b"), [], blockStmt([]))])));
 assertDecl("function f(a,[x,y]) { function a() { } }",
            funDecl(ident("f"),
-                   [ident("a"), arrPatt([ident("x"), ident("y")])],
+                   [ident("a"), arrPatt([assignElem("x"), assignElem("y")])],
                    blockStmt([funDecl(ident("a"), [], blockStmt([]))])));
 
 // Bug 632027: array holes should reflect as null
 assertExpr("[,]=[,]", aExpr("=", arrPatt([null]), arrExpr([null])));
 
 // Bug 591450: this test currently crashes because of a bug in jsparse
 // assertDecl("function f(a,[x,y],b,[w,z],c) { function b() { } }",
 //            funDecl(ident("f"),
@@ -264,17 +269,17 @@ assertExpr("(function(){})", funExpr(nul
 assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([])));
 assertExpr("(function f(x,y,z) {})", funExpr(ident("f"), [ident("x"),ident("y"),ident("z")], blockStmt([])));
 assertExpr("a => a", arrowExpr([ident("a")], ident("a")));
 assertExpr("(a) => a", arrowExpr([ident("a")], ident("a")));
 assertExpr("a => b => a", arrowExpr([ident("a")], arrowExpr([ident("b")], ident("a"))));
 assertExpr("a => {}", arrowExpr([ident("a")], blockStmt([])));
 assertExpr("a => ({})", arrowExpr([ident("a")], objExpr([])));
 assertExpr("(a, b, c) => {}", arrowExpr([ident("a"), ident("b"), ident("c")], blockStmt([])));
-assertExpr("([a, b]) => {}", arrowExpr([arrPatt([ident("a"), ident("b")])], blockStmt([])));
+assertExpr("([a, b]) => {}", arrowExpr([arrPatt([assignElem("a"), assignElem("b")])], blockStmt([])));
 assertExpr("(++x)", updExpr("++", ident("x"), true));
 assertExpr("(x++)", updExpr("++", ident("x"), false));
 assertExpr("(+x)", unExpr("+", ident("x")));
 assertExpr("(-x)", unExpr("-", ident("x")));
 assertExpr("(!x)", unExpr("!", ident("x")));
 assertExpr("(~x)", unExpr("~", ident("x")));
 assertExpr("(delete x)", unExpr("delete", ident("x")));
 assertExpr("(typeof x)", unExpr("typeof", ident("x")));
@@ -561,41 +566,41 @@ assertStmt("function f() { function g() 
 //           funDecl(ident("f"), [], blockStmt([funDecl(ident("g"), [], blockStmt([])),
 //                                              funDecl(ident("g"), [], blockStmt([returnStmt(lit(42))]))])));
 
 assertStmt("function f() { var x = 42; var x = 43; }",
            funDecl(ident("f"), [], blockStmt([varDecl([{ id: ident("x"), init: lit(42) }]),
                                               varDecl([{ id: ident("x"), init: lit(43) }])])));
 
 
-assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y"), shorthand: false }]),
+assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([assignProp("x", ident("y"))]),
                                           init: ident("foo") }]));
-assertDecl("var {x} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("x"), shorthand: true }]),
+assertDecl("var {x} = foo;", varDecl([{ id: objPatt([assignProp("x")]),
                                         init: ident("foo") }]));
 
 // Bug 632030: redeclarations between var and funargs, var and function
 assertStmt("function g(x) { var x }",
            funDecl(ident("g"), [ident("x")], blockStmt([varDecl[{ id: ident("x"), init: null }]])));
 assertProg("f.p = 1; var f; f.p; function f(){}",
            [exprStmt(aExpr("=", dotExpr(ident("f"), ident("p")), lit(1))),
             varDecl([{ id: ident("f"), init: null }]),
             exprStmt(dotExpr(ident("f"), ident("p"))),
             funDecl(ident("f"), [], blockStmt([]))]);
 
 // global let is var
-assertGlobalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
+assertGlobalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([assignProp("x", ident("y"))]),
                                                 init: ident("foo") }]));
 // function-global let is let
-assertLocalDecl("let {x:y} = foo;", letDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
+assertLocalDecl("let {x:y} = foo;", letDecl([{ id: objPatt([assignProp("x", ident("y"))]),
                                                init: ident("foo") }]));
 // block-local let is let
-assertBlockDecl("let {x:y} = foo;", letDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
+assertBlockDecl("let {x:y} = foo;", letDecl([{ id: objPatt([assignProp("x", ident("y"))]),
                                                init: ident("foo") }]));
 
-assertDecl("const {x:y} = foo;", constDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
+assertDecl("const {x:y} = foo;", constDecl([{ id: objPatt([assignProp("x", ident("y"))]),
                                               init: ident("foo") }]));
 
 
 // various combinations of identifiers and destructuring patterns:
 function makePatternCombinations(id, destr)
     [
       [ id(1)                                            ],
       [ id(1),    id(2)                                  ],
@@ -665,26 +670,33 @@ function testParamPatternCombinations(ma
         assertExpr(makeSrc("(0)"), makePatt(lit(0)));
         // upvars, expression body
         assertExpr(makeSrc("[x1,x2,x3,x4,x5]"),
                    makePatt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")])));
     }
 }
 
 testParamPatternCombinations(function(n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "}"),
-                             function(n) (objPatt([{ key: ident("a" + n), value: ident("x" + n) },
-                                                   { key: ident("b" + n), value: ident("y" + n) },
-                                                   { key: ident("c" + n), value: ident("z" + n) }])));
+                             function(n) (objPatt([assignProp("a" + n, ident("x" + n)),
+                                                   assignProp("b" + n, ident("y" + n)),
+                                                   assignProp("c" + n, ident("z" + n))])));
+
+testParamPatternCombinations(function(n) ("{a" + n + ":x" + n + " = 10," + "b" + n + ":y" + n + " = 10," + "c" + n + ":z" + n + " = 10}"),
+                             function(n) (objPatt([assignProp("a" + n, ident("x" + n), lit(10)),
+                                                   assignProp("b" + n, ident("y" + n), lit(10)),
+                                                   assignProp("c" + n, ident("z" + n), lit(10))])));
 
 testParamPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "]"),
-                             function(n) (arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)])));
+                             function(n) (arrPatt([assignElem("x" + n), assignElem("y" + n), assignElem("z" + n)])));
 
 testParamPatternCombinations(function(n) ("[a" + n + ", ..." + "b" + n + "]"),
-                             function(n) (arrPatt([ident("a" + n), spread(ident("b" + n))])));
+                             function(n) (arrPatt([assignElem("a" + n), spread(ident("b" + n))])));
 
+testParamPatternCombinations(function(n) ("[a" + n + ", " + "b" + n + " = 10]"),
+                             function(n) (arrPatt([assignElem("a" + n), assignElem("b" + n, lit(10))])));
 
 // destructuring variable declarations
 
 function testVarPatternCombinations(makePattSrc, makePattPatt) {
     var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc);
     var pattPatts = makePatternCombinations(function(n) ({ id: ident("x" + n), init: null }), makePattPatt);
     // It's illegal to have uninitialized const declarations, so we need a
     // separate set of patterns and sources.
@@ -707,29 +719,38 @@ function testVarPatternCombinations(make
         assertStmt("for (let " + pattSrcs[i].join(",") + "; foo; bar);",
                    letStmt(pattPatts[i], forStmt(null, ident("foo"), ident("bar"), emptyStmt)));
         assertStmt("for (const " + constSrcs[i].join(",") + "; foo; bar);",
                    letStmt(constPatts[i], forStmt(null, ident("foo"), ident("bar"), emptyStmt)));
     }
 }
 
 testVarPatternCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
-                           function (n) ({ id: objPatt([{ key: ident("a" + n), value: ident("x" + n) },
-                                                        { key: ident("b" + n), value: ident("y" + n) },
-                                                        { key: ident("c" + n), value: ident("z" + n) }]),
+                           function (n) ({ id: objPatt([assignProp("a" + n, ident("x" + n)),
+                                                        assignProp("b" + n, ident("y" + n)),
+                                                        assignProp("c" + n, ident("z" + n))]),
+                                           init: lit(0) }));
+
+testVarPatternCombinations(function (n) ("{a" + n + ":x" + n + " = 10," + "b" + n + ":y" + n + " = 10," + "c" + n + ":z" + n + " = 10} = 0"),
+                           function (n) ({ id: objPatt([assignProp("a" + n, ident("x" + n), lit(10)),
+                                                        assignProp("b" + n, ident("y" + n), lit(10)),
+                                                        assignProp("c" + n, ident("z" + n), lit(10))]),
                                            init: lit(0) }));
 
 testVarPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "] = 0"),
-                           function(n) ({ id: arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)]),
+                           function(n) ({ id: arrPatt([assignElem("x" + n), assignElem("y" + n), assignElem("z" + n)]),
                                           init: lit(0) }));
 
 testVarPatternCombinations(function(n) ("[a" + n + ", ..." + "b" + n + "] = 0"),
-                           function(n) ({ id: arrPatt([ident("a" + n), spread(ident("b" + n))]),
+                           function(n) ({ id: arrPatt([assignElem("a" + n), spread(ident("b" + n))]),
                                           init: lit(0) }));
 
+testVarPatternCombinations(function(n) ("[a" + n + ", " + "b" + n + " = 10] = 0"),
+                           function(n) ({ id: arrPatt([assignElem("a" + n), assignElem("b" + n, lit(10))]),
+                                          init: lit(0) }));
 // destructuring assignment
 
 function testAssignmentCombinations(makePattSrc, makePattPatt) {
     var pattSrcs = makePatternCombinations(function(n) ("x" + n + " = 0"), makePattSrc);
     var pattPatts = makePatternCombinations(function(n) (aExpr("=", ident("x" + n), lit(0))), makePattPatt);
 
     for (var i = 0; i < pattSrcs.length; i++) {
         var src = pattSrcs[i].join(",");
@@ -741,28 +762,28 @@ function testAssignmentCombinations(make
         // for-loop head assignment
         assertStmt("for (" + src + "; foo; bar);",
                    forStmt(patt, ident("foo"), ident("bar"), emptyStmt));
     }
 }
 
 testAssignmentCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
                            function (n) (aExpr("=",
-                                               objPatt([{ key: ident("a" + n), value: ident("x" + n) },
-                                                        { key: ident("b" + n), value: ident("y" + n) },
-                                                        { key: ident("c" + n), value: ident("z" + n) }]),
+                                               objPatt([assignProp("a" + n, ident("x" + n)),
+                                                        assignProp("b" + n, ident("y" + n)),
+                                                        assignProp("c" + n, ident("z" + n))]),
                                                lit(0))));
 
 
 // destructuring in for-in and for-each-in loop heads
 
-var axbycz = objPatt([{ key: ident("a"), value: ident("x") },
-                      { key: ident("b"), value: ident("y") },
-                      { key: ident("c"), value: ident("z") }]);
-var xyz = arrPatt([ident("x"), ident("y"), ident("z")]);
+var axbycz = objPatt([assignProp("a", ident("x")),
+                      assignProp("b", ident("y")),
+                      assignProp("c", ident("z"))]);
+var xyz = arrPatt([assignElem("x"), assignElem("y"), assignElem("z")]);
 
 assertStmt("for (var {a:x,b:y,c:z} in foo);", forInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for (let {a:x,b:y,c:z} in foo);", forInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for ({a:x,b:y,c:z} in foo);", forInStmt(axbycz, ident("foo"), emptyStmt));
 assertStmt("for (var [x,y,z] in foo);", forInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for (let [x,y,z] in foo);", forInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
 assertStmt("for ([x,y,z] in foo);", forInStmt(xyz, ident("foo"), emptyStmt));
 assertStmt("for (var {a:x,b:y,c:z} of foo);", forOfStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -395,148 +395,130 @@ NewNativeObjectWithClassProto(ExclusiveC
                               NewObjectKind newKind = GenericObject)
 {
     return MaybeNativeObject(NewObjectWithClassProto(cx, clasp, proto, parent, newKind));
 }
 
 /*
  * Call obj's resolve hook.
  *
- * cx, id, and flags are the parameters initially passed to the ongoing lookup;
- * objp and propp are its out parameters. obj is an object along the prototype
- * chain from where the lookup started.
+ * cx and id are the parameters initially passed to the ongoing lookup;
+ * propp and recursedp are its out parameters.
  *
  * There are four possible outcomes:
  *
  *   - On failure, report an error or exception and return false.
  *
- *   - If we are already resolving a property of *curobjp, set *recursedp = true,
+ *   - If we are already resolving a property of obj, set *recursedp = true,
  *     and return true.
  *
- *   - If the resolve hook finds or defines the sought property, set *objp and
- *     *propp appropriately, set *recursedp = false, and return true.
+ *   - If the resolve hook finds or defines the sought property, set propp
+ *      appropriately, set *recursedp = false, and return true.
  *
- *   - Otherwise no property was resolved. Set *propp = nullptr and
+ *   - Otherwise no property was resolved. Set propp to nullptr and
  *     *recursedp = false and return true.
  */
 static MOZ_ALWAYS_INLINE bool
-CallResolveOp(JSContext *cx, HandleNativeObject obj, HandleId id, MutableHandleObject objp,
-              MutableHandleShape propp, bool *recursedp)
+CallResolveOp(JSContext *cx, HandleNativeObject obj, HandleId id, MutableHandleShape propp,
+              bool *recursedp)
 {
-    /*
-     * Avoid recursion on (obj, id) already being resolved on cx.
-     *
-     * Once we have successfully added an entry for (obj, key) to
-     * cx->resolvingTable, control must go through cleanup: before
-     * returning.  But note that JS_DHASH_ADD may find an existing
-     * entry, in which case we bail to suppress runaway recursion.
-     */
+    // Avoid recursion on (obj, id) already being resolved on cx.
     AutoResolving resolving(cx, obj, id);
     if (resolving.alreadyStarted()) {
-        /* Already resolving id in obj -- suppress recursion. */
+        // Already resolving id in obj, suppress recursion.
         *recursedp = true;
         return true;
     }
     *recursedp = false;
 
     bool resolved = false;
     if (!obj->getClass()->resolve(cx, obj, id, &resolved))
         return false;
 
     if (!resolved)
         return true;
 
-    objp.set(obj);
-
     if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
         MarkDenseOrTypedArrayElementFound<CanGC>(propp);
         return true;
     }
 
-    if (Shape *shape = obj->lookup(cx, id))
-        propp.set(shape);
-    else
-        objp.set(nullptr);
+    MOZ_ASSERT(!IsAnyTypedArray(obj));
 
+    propp.set(obj->lookup(cx, id));
     return true;
 }
 
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
 LookupOwnPropertyInline(ExclusiveContext *cx,
                         typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
                         typename MaybeRooted<jsid, allowGC>::HandleType id,
-                        typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
                         typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp,
                         bool *donep)
 {
     // Check for a native dense element.
     if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
-        objp.set(obj);
         MarkDenseOrTypedArrayElementFound<allowGC>(propp);
         *donep = true;
         return true;
     }
 
     // Check for a typed array element. Integer lookups always finish here
     // so that integer properties on the prototype are ignored even for out
     // of bounds accesses.
     if (IsAnyTypedArray(obj)) {
         uint64_t index;
         if (IsTypedArrayIndex(id, &index)) {
             if (index < AnyTypedArrayLength(obj)) {
-                objp.set(obj);
                 MarkDenseOrTypedArrayElementFound<allowGC>(propp);
             } else {
-                objp.set(nullptr);
                 propp.set(nullptr);
             }
             *donep = true;
             return true;
         }
     }
 
     // Check for a native property.
     if (Shape *shape = obj->lookup(cx, id)) {
-        objp.set(obj);
         propp.set(shape);
         *donep = true;
         return true;
     }
 
     // id was not found in obj. Try obj's resolve hook, if any.
     if (obj->getClass()->resolve)
     {
         if (!cx->shouldBeJSContext() || !allowGC)
             return false;
 
         bool recursed;
         if (!CallResolveOp(cx->asJSContext(),
                            MaybeRooted<NativeObject*, allowGC>::toHandle(obj),
                            MaybeRooted<jsid, allowGC>::toHandle(id),
-                           MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
                            MaybeRooted<Shape*, allowGC>::toMutableHandle(propp),
                            &recursed))
         {
             return false;
         }
 
         if (recursed) {
-            objp.set(nullptr);
             propp.set(nullptr);
             *donep = true;
             return true;
         }
 
         if (propp) {
             *donep = true;
             return true;
         }
     }
 
+    propp.set(nullptr);
     *donep = false;
     return true;
 }
 
 /*
  * Simplified version of LookupOwnPropertyInline that doesn't call resolve
  * hooks.
  */
@@ -579,20 +561,25 @@ LookupPropertyInline(ExclusiveContext *c
      *     If this changes, please remember to update the logic there as well.
      */
 
     /* Search scopes starting with obj and following the prototype link. */
     typename MaybeRooted<NativeObject*, allowGC>::RootType current(cx, obj);
 
     while (true) {
         bool done;
-        if (!LookupOwnPropertyInline<allowGC>(cx, current, id, objp, propp, &done))
+        if (!LookupOwnPropertyInline<allowGC>(cx, current, id, propp, &done))
             return false;
-        if (done)
+        if (done) {
+            if (propp)
+                objp.set(current);
+            else
+                objp.set(nullptr);
             return true;
+        }
 
         typename MaybeRooted<JSObject*, allowGC>::RootType proto(cx, current->getProto());
 
         if (!proto)
             break;
         if (!proto->isNative()) {
             if (!cx->shouldBeJSContext() || !allowGC)
                 return false;
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1453,24 +1453,18 @@ js::NativeDefineProperty(ExclusiveContex
 
     return CallAddPropertyHook(cx, obj, shape, updateValue);
 }
 
 static bool
 NativeLookupOwnProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                         MutableHandle<Shape*> shapep)
 {
-    RootedObject pobj(cx);
     bool done;
-
-    if (!LookupOwnPropertyInline<CanGC>(cx, obj, id, &pobj, shapep, &done))
-        return false;
-    if (!done || pobj != obj)
-        shapep.set(nullptr);
-    return true;
+    return LookupOwnPropertyInline<CanGC>(cx, obj, id, shapep, &done);
 }
 
 template <AllowGC allowGC>
 bool
 js::NativeLookupProperty(ExclusiveContext *cx,
                          typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
                          typename MaybeRooted<jsid, allowGC>::HandleType id,
                          typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
@@ -2067,23 +2061,19 @@ js::NativeSetProperty(JSContext *cx, Han
     RootedShape shape(cx);
     RootedNativeObject pobj(cx, obj);
 
     // This loop isn't explicit in the spec algorithm. See the comment on step
     // 4.c.i below.
     for (;;) {
         // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
         bool done;
-        RootedObject ancestor(cx);
-        if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &ancestor, &shape, &done))
+        if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
             return false;
 
-        if (!done || ancestor != pobj)
-            shape = nullptr;
-
         if (shape) {
             // Steps 5-6.
             return SetExistingProperty(cx, obj, receiver, id, pobj, shape, vp, strict);
         }
 
         // Steps 4.a-b. The check for 'done' on this next line is tricky.
         // done can be true in exactly these unlikely-sounding cases:
         // - We're looking up an element, and pobj is a TypedArray that
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -219,20 +219,18 @@ GetShapeAttributes(JSObject *obj, Shape 
         if (IsAnyTypedArray(obj))
             return JSPROP_ENUMERATE | JSPROP_PERMANENT;
         return JSPROP_ENUMERATE;
     }
 
     return shape->attributes();
 }
 
-#ifdef JSGC_COMPACTING
 inline void
 BaseShape::fixupAfterMovingGC()
 {
     if (hasTable())
         table().fixupAfterMovingGC();
 }
-#endif
 
 } /* namespace js */
 
 #endif /* vm_Shape_inl_h */
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -251,29 +251,27 @@ ShapeTable::search(jsid id, bool adding)
             collisionFlag &= entry->hadCollision();
 #endif
         }
     }
 
     MOZ_CRASH("Shape::search failed to find an expected entry.");
 }
 
-#ifdef JSGC_COMPACTING
 void
 ShapeTable::fixupAfterMovingGC()
 {
     uint32_t size = capacity();
     for (HashNumber i = 0; i < size; i++) {
         Entry &entry = getEntry(i);
         Shape *shape = entry.shape();
         if (shape && IsForwarded(shape))
             entry.setPreservingCollision(Forwarded(shape));
     }
 }
-#endif
 
 bool
 ShapeTable::change(int log2Delta, ExclusiveContext *cx)
 {
     MOZ_ASSERT(entries_);
     MOZ_ASSERT(-1 <= log2Delta && log2Delta <= 1);
 
     /*
@@ -1688,17 +1686,16 @@ JSCompartment::sweepInitialShapeTable()
                     InitialShapeEntry newKey(readBarrieredShape, TaggedProto(proto));
                     e.rekeyFront(newKey.getLookup(), newKey);
                 }
             }
         }
     }
 }
 
-#ifdef JSGC_COMPACTING
 void
 JSCompartment::fixupInitialShapeTable()
 {
     if (!initialShapes.initialized())
         return;
 
     for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
         InitialShapeEntry entry = e.front();
@@ -1727,17 +1724,16 @@ JSCompartment::fixupInitialShapeTable()
                                                parent,
                                                metadata,
                                                entry.shape->numFixedSlots(),
                                                entry.shape->getObjectFlags());
             e.rekeyFront(relookup, entry);
         }
     }
 }
-#endif // JSGC_COMPACTING
 
 void
 AutoRooterGetterSetter::Inner::trace(JSTracer *trc)
 {
     if ((attrs & JSPROP_GETTER) && *pgetter)
         gc::MarkObjectRoot(trc, (JSObject**) pgetter, "AutoRooterGetterSetter getter");
     if ((attrs & JSPROP_SETTER) && *psetter)
         gc::MarkObjectRoot(trc, (JSObject**) psetter, "AutoRooterGetterSetter setter");
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -222,20 +222,18 @@ class ShapeTable {
      * NB: init and change are fallible but do not report OOM, so callers can
      * cope or ignore. They do however use the context's calloc method in
      * order to update the malloc counter on success.
      */
     bool init(ExclusiveContext *cx, Shape *lastProp);
     bool change(int log2Delta, ExclusiveContext *cx);
     Entry &search(jsid id, bool adding);
 
-#ifdef JSGC_COMPACTING
     /* Update entries whose shapes have been moved */
     void fixupAfterMovingGC();
-#endif
 
   private:
     Entry &getEntry(uint32_t i) const {
         MOZ_ASSERT(i < capacity());
         return entries_[i];
     }
     void decEntryCount() {
         MOZ_ASSERT(entryCount_ > 0);
@@ -525,19 +523,17 @@ class BaseShape : public gc::TenuredCell
 
         if (parent)
             gc::MarkObject(trc, &parent, "parent");
 
         if (metadata)
             gc::MarkObject(trc, &metadata, "metadata");
     }
 
-#ifdef JSGC_COMPACTING
     void fixupAfterMovingGC();
-#endif
 
   private:
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(BaseShape, clasp_) == offsetof(js::shadow::BaseShape, clasp_));
     }
 };
 
 class UnownedBaseShape : public BaseShape {};
@@ -1056,30 +1052,26 @@ class Shape : public gc::TenuredCell
 
     static inline ThingRootKind rootKind() { return THING_ROOT_SHAPE; }
 
     inline void markChildren(JSTracer *trc);
 
     inline Shape *search(ExclusiveContext *cx, jsid id);
     inline Shape *searchLinear(jsid id);
 
-#ifdef JSGC_COMPACTING
     void fixupAfterMovingGC();
-#endif
 
     /* For JIT usage */
     static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
     static inline size_t offsetOfSlotInfo() { return offsetof(Shape, slotInfo); }
     static inline uint32_t fixedSlotsMask() { return FIXED_SLOTS_MASK; }
 
   private:
-#ifdef JSGC_COMPACTING
     void fixupDictionaryShapeAfterMovingGC();
     void fixupShapeTreeAfterMovingGC();
-#endif
 
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(Shape, base_) == offsetof(js::shadow::Shape, base));
         JS_STATIC_ASSERT(offsetof(Shape, slotInfo) == offsetof(js::shadow::Shape, slotInfo));
         JS_STATIC_ASSERT(FIXED_SLOTS_SHIFT == js::shadow::Shape::FIXED_SLOTS_SHIFT);
     }
 };
 
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -60,17 +60,17 @@ using JS::CanonicalizeNaN;
 // value of JS_STRUCTURED_CLONE_VERSION in js/public/StructuredClone.h.  You will
 // likely need to increment the version if anything at all changes in the serialization
 // format.
 //
 // Note that SCTAG_END_OF_KEYS is written into the serialized form and should have
 // a stable ID, it need not be at the end of the list and should not be used for
 // sizing data structures.
 
-enum StructuredDataType MOZ_ENUM_TYPE(uint32_t) {
+enum StructuredDataType : uint32_t {
     /* Structured data types provided by the engine */
     SCTAG_FLOAT_MAX = 0xFFF00000,
     SCTAG_NULL = 0xFFFF0000,
     SCTAG_UNDEFINED,
     SCTAG_BOOLEAN,
     SCTAG_INT32,
     SCTAG_STRING,
     SCTAG_DATE_OBJECT,
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -1060,19 +1060,22 @@ public:
     SetExpandoChain(JSContext *cx, JS::HandleObject target, JS::HandleObject chain);
 
     static void
     SystemIsBeingShutDown();
 
     static void
     TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt);
 
-    void TraceInside(JSTracer *trc) {
+    void TraceSelf(JSTracer *trc) {
         MOZ_ASSERT(mGlobalJSObject);
         mGlobalJSObject.trace(trc, "XPCWrappedNativeScope::mGlobalJSObject");
+    }
+
+    void TraceInside(JSTracer *trc) {
         if (mContentXBLScope)
             mContentXBLScope.trace(trc, "XPCWrappedNativeScope::mXBLScope");
         for (size_t i = 0; i < mAddonScopes.Length(); i++)
             mAddonScopes[i].trace(trc, "XPCWrappedNativeScope::mAddonScopes");
         if (mXrayExpandos.initialized())
             mXrayExpandos.trace(trc);
     }
 
@@ -1842,17 +1845,17 @@ public:
 
     void TraceInside(JSTracer *trc) {
         if (JS_IsGCMarkingTracer(trc)) {
             mSet->Mark();
             if (mScriptableInfo)
                 mScriptableInfo->Mark();
         }
 
-        GetScope()->TraceInside(trc);
+        GetScope()->TraceSelf(trc);
     }
 
     void TraceJS(JSTracer *trc) {
         TraceSelf(trc);
         TraceInside(trc);
     }
 
     void WriteBarrierPre(JSRuntime* rt)
@@ -2157,17 +2160,17 @@ public:
         if (JS_IsGCMarkingTracer(trc)) {
             mSet->Mark();
             if (mScriptableInfo)
                 mScriptableInfo->Mark();
         }
         if (HasProto())
             GetProto()->TraceSelf(trc);
         else
-            GetScope()->TraceInside(trc);
+            GetScope()->TraceSelf(trc);
         if (mFlatJSObject && JS_IsGlobalObject(mFlatJSObject))
         {
             xpc::TraceXPCGlobal(trc, mFlatJSObject);
         }
     }
 
     void TraceJS(JSTracer *trc) {
         TraceInside(trc);
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2338,21 +2338,24 @@ ContainerState::PopPaintedLayerData()
       nsRegion* dest = isPrecise ? &containingPaintedLayerData->mHitRegion
                                  : &containingPaintedLayerData->mMaybeHitRegion;
       dest->Or(*dest, rect);
     }
   } else {
     EventRegions regions;
     regions.mHitRegion = ScaleRegionToOutsidePixels(data->mHitRegion);
     // Points whose hit-region status we're not sure about need to be dispatched
-    // to the content thread.
+    // to the content thread. If a point is in both maybeHitRegion and hitRegion
+    // then it's not a "maybe" any more, and doesn't go into the dispatch-to-
+    // content region.
     nsIntRegion maybeHitRegion = ScaleRegionToOutsidePixels(data->mMaybeHitRegion);
     regions.mDispatchToContentHitRegion.Sub(maybeHitRegion, regions.mHitRegion);
-    regions.mDispatchToContentHitRegion.Or(regions.mDispatchToContentHitRegion,
-                                           ScaleRegionToOutsidePixels(data->mDispatchToContentHitRegion));
+    regions.mDispatchToContentHitRegion.OrWith(
+        ScaleRegionToOutsidePixels(data->mDispatchToContentHitRegion));
+    regions.mHitRegion.OrWith(maybeHitRegion);
 
     nsIntPoint translation = -GetTranslationForPaintedLayer(data->mLayer);
     regions.mHitRegion.MoveBy(translation);
     regions.mDispatchToContentHitRegion.MoveBy(translation);
 
     layer->SetEventRegions(regions);
   }
 
--- a/layout/forms/moz.build
+++ b/layout/forms/moz.build
@@ -51,13 +51,9 @@ LOCAL_INCLUDES += [
     '../xul',
     '/dom/base',
     '/dom/html',
 ]
 
 if CONFIG['ENABLE_INTL_API']:
     # nsNumberControlFrame.cpp requires ICUUtils.h which in turn requires
     # i18n/unum.h
-    LOCAL_INCLUDES += [
-        '../../intl/icu/source/common',
-        '../../intl/icu/source/i18n',
-    ]
-
+    CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS']
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -1464,17 +1464,17 @@ public:
                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("ComboboxFocus", TYPE_COMBOBOX_FOCUS)
 };
 
 void nsDisplayComboboxFocus::Paint(nsDisplayListBuilder* aBuilder,
                                    nsRenderingContext* aCtx)
 {
   static_cast<nsComboboxControlFrame*>(mFrame)
-    ->PaintFocus(*aCtx, ToReferenceFrame());
+    ->PaintFocus(*aCtx->GetDrawTarget(), ToReferenceFrame());
 }
 
 void
 nsComboboxControlFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                          const nsRect&           aDirtyRect,
                                          const nsDisplayListSet& aLists)
 {
 #ifdef NOISY
@@ -1506,51 +1506,48 @@ nsComboboxControlFrame::BuildDisplayList
           new (aBuilder) nsDisplayComboboxFocus(aBuilder, this));
       }
     }
   }
 
   DisplaySelectionOverlay(aBuilder, aLists.Content());
 }
 
-void nsComboboxControlFrame::PaintFocus(nsRenderingContext& aRenderingContext,
+void nsComboboxControlFrame::PaintFocus(DrawTarget& aDrawTarget,
                                         nsPoint aPt)
 {
   /* Do we need to do anything? */
   EventStates eventStates = mContent->AsElement()->State();
   if (eventStates.HasState(NS_EVENT_STATE_DISABLED) || sFocused != this)
     return;
 
-  gfxContext* gfx = aRenderingContext.ThebesContext();
+  int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
 
-  gfx->Save();
   nsRect clipRect = mDisplayFrame->GetRect() + aPt;
-  gfx->Clip(NSRectToSnappedRect(clipRect,
-                                PresContext()->AppUnitsPerDevPixel(),
-                                *aRenderingContext.GetDrawTarget()));
+  aDrawTarget.PushClipRect(NSRectToSnappedRect(clipRect,
+                                               appUnitsPerDevPixel,
+                                               aDrawTarget));
 
   // REVIEW: Why does the old code paint mDisplayFrame again? We've
   // already painted it in the children above. So clipping it here won't do
   // us much good.
 
   /////////////////////
   // draw focus
 
   StrokeOptions strokeOptions;
   nsLayoutUtils::InitDashPattern(strokeOptions, NS_STYLE_BORDER_STYLE_DOTTED);
   ColorPattern color(ToDeviceColor(StyleColor()->mColor));
   nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   clipRect.width -= onePixel;
   clipRect.height -= onePixel;
-  Rect r =
-    ToRect(nsLayoutUtils::RectToGfxRect(clipRect, PresContext()->AppUnitsPerDevPixel()));
-  StrokeSnappedEdgesOfRect(r, *aRenderingContext.GetDrawTarget(),
-                           color, strokeOptions);
+  Rect r = ToRect(nsLayoutUtils::RectToGfxRect(clipRect, appUnitsPerDevPixel));
+  StrokeSnappedEdgesOfRect(r, aDrawTarget, color, strokeOptions);
 
-  gfx->Restore();
+  aDrawTarget.PopClip();
 }
 
 //---------------------------------------------------------
 // gets the content (an option) by index and then set it as
 // being selected or not selected
 //---------------------------------------------------------
 NS_IMETHODIMP
 nsComboboxControlFrame::OnOptionSelected(int32_t aIndex, bool aSelected)
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -32,24 +32,32 @@
 #include "nsThreadUtils.h"
 
 class nsStyleContext;
 class nsIListControlFrame;
 class nsComboboxDisplayFrame;
 class nsIDOMEventListener;
 class nsIScrollableFrame;
 
+namespace mozilla {
+namespace gfx {
+class DrawTarget;
+}
+}
+
 class nsComboboxControlFrame MOZ_FINAL : public nsBlockFrame,
                                          public nsIFormControlFrame,
                                          public nsIComboboxControlFrame,
                                          public nsIAnonymousContentCreator,
                                          public nsISelectControlFrame,
                                          public nsIRollupListener,
                                          public nsIStatefulFrame
 {
+  typedef mozilla::gfx::DrawTarget DrawTarget;
+
 public:
   friend nsContainerFrame* NS_NewComboboxControlFrame(nsIPresShell* aPresShell,
                                                       nsStyleContext* aContext,
                                                       nsFrameState aFlags);
   friend class nsComboboxDisplayFrame;
 
   explicit nsComboboxControlFrame(nsStyleContext* aContext);
   ~nsComboboxControlFrame();
@@ -79,17 +87,17 @@ public:
   virtual nsresult HandleEvent(nsPresContext* aPresContext,
                                mozilla::WidgetGUIEvent* aEvent,
                                nsEventStatus* aEventStatus) MOZ_OVERRIDE;
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
-  void PaintFocus(nsRenderingContext& aRenderingContext, nsPoint aPt);
+  void PaintFocus(DrawTarget& aDrawTarget, nsPoint aPt);
 
   // XXXbz this is only needed to prevent the quirk percent height stuff from
   // leaking out of the combobox.  We may be able to get rid of this as more
   // things move to IsFrameOfType.
   virtual nsIAtom* GetType() const MOZ_OVERRIDE;
 
   virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE
   {
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -2911,18 +2911,19 @@ SVGTextDrawPathCallbacks::SetupContext()
     break;
   }
 }
 
 void
 SVGTextDrawPathCallbacks::HandleTextGeometry()
 {
   if (IsClipPathChild()) {
-    gfx->SetColor(gfxRGBA(1.0f, 1.0f, 1.0f, 1.0f));
-    gfx->Fill();
+    RefPtr<Path> path = gfx->GetPath();
+    ColorPattern white(Color(1.f, 1.f, 1.f, 1.f)); // for masking, so no ToDeviceColor
+    gfx->GetDrawTarget()->Fill(path, white);
   } else {
     // Normal painting.
     gfxContextMatrixAutoSaveRestore saveMatrix(gfx);
     gfx->SetMatrix(mCanvasTM);
 
     FillAndStrokeGeometry();
   }
 }
@@ -2979,21 +2980,25 @@ SVGTextDrawPathCallbacks::FillAndStrokeG
 }
 
 void
 SVGTextDrawPathCallbacks::FillGeometry()
 {
   GeneralPattern fillPattern;
   MakeFillPattern(&fillPattern);
   if (fillPattern.GetPattern()) {
-    gfx->SetFillRule(
-      nsSVGUtils::ToFillRule(
-        IsClipPathChild() ?
-          mFrame->StyleSVG()->mClipRule : mFrame->StyleSVG()->mFillRule));
-    gfx->Fill(fillPattern);
+    RefPtr<Path> path = gfx->GetPath();
+    FillRule fillRule = nsSVGUtils::ToFillRule(IsClipPathChild() ?
+                          mFrame->StyleSVG()->mClipRule :
+                          mFrame->StyleSVG()->mFillRule);
+    if (fillRule != path->GetFillRule()) {
+      RefPtr<PathBuilder> builder = path->CopyToBuilder(fillRule);
+      path = builder->Finish();
+    }
+    gfx->GetDrawTarget()->Fill(path, fillPattern);
   }
 }
 
 void
 SVGTextDrawPathCallbacks::StrokeGeometry()
 {
   // We don't paint the stroke when we are filling with a selection color.
   if (mColor == NS_SAME_AS_FOREGROUND_COLOR ||
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -463,30 +463,42 @@ PeerConnectionImpl::CreateRemoteSourceSt
  *
  * This function converts that into an internal IceConfiguration object.
  */
 nsresult
 PeerConnectionImpl::ConvertRTCConfiguration(const RTCConfiguration& aSrc,
                                             IceConfiguration *aDst)
 {
 #ifdef MOZILLA_INTERNAL_API
-  if (!aSrc.mIceServers.WasPassed()) {
-    return NS_OK;
+  if (aSrc.mIceServers.WasPassed()) {
+    for (size_t i = 0; i < aSrc.mIceServers.Value().Length(); i++) {
+      nsresult rv = AddIceServer(aSrc.mIceServers.Value()[i], aDst);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
   }
-  for (uint32_t i = 0; i < aSrc.mIceServers.Value().Length(); i++) {
-    const RTCIceServer& server = aSrc.mIceServers.Value()[i];
-    NS_ENSURE_TRUE(server.mUrl.WasPassed(), NS_ERROR_UNEXPECTED);
-
+#endif
+  return NS_OK;
+}
+
+nsresult
+PeerConnectionImpl::AddIceServer(const RTCIceServer &aServer,
+                                 IceConfiguration *aDst)
+{
+#ifdef MOZILLA_INTERNAL_API
+  NS_ENSURE_STATE(aServer.mUrls.WasPassed());
+  NS_ENSURE_STATE(aServer.mUrls.Value().IsStringSequence());
+  auto &urls = aServer.mUrls.Value().GetAsStringSequence();
+  for (size_t i = 0; i < urls.Length(); i++) {
     // Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than
     // nsStandardURL. To parse STUN/TURN URI's to spec
     // http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3
     // http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3
     // we parse out the query-string, and use ParseAuthority() on the rest
     nsRefPtr<nsIURI> url;
-    nsresult rv = NS_NewURI(getter_AddRefs(url), server.mUrl.Value());
+    nsresult rv = NS_NewURI(getter_AddRefs(url), urls[i]);
     NS_ENSURE_SUCCESS(rv, rv);
     bool isStun = false, isStuns = false, isTurn = false, isTurns = false;
     url->SchemeIs("stun", &isStun);
     url->SchemeIs("stuns", &isStuns);
     url->SchemeIs("turn", &isTurn);
     url->SchemeIs("turns", &isTurns);
     if (!(isStun || isStuns || isTurn || isTurns)) {
       return NS_ERROR_FAILURE;
@@ -537,18 +549,18 @@ PeerConnectionImpl::ConvertRTCConfigurat
       if (hostPos > 1)  /* The username was removed */
         return NS_ERROR_FAILURE;
       path.Mid(host, hostPos, hostLen);
     }
     if (port == -1)
       port = (isStuns || isTurns)? 5349 : 3478;
 
     if (isTurn || isTurns) {
-      NS_ConvertUTF16toUTF8 credential(server.mCredential);
-      NS_ConvertUTF16toUTF8 username(server.mUsername);
+      NS_ConvertUTF16toUTF8 credential(aServer.mCredential);
+      NS_ConvertUTF16toUTF8 username(aServer.mUsername);
 
       // Bug 1039655 - TURN TCP is not e10s ready
       if ((transport == kNrIceTransportTcp) &&
           (XRE_GetProcessType() != GeckoProcessType_Default)) {
         continue;
       }
 
       if (!aDst->addTurnServer(host.get(), port,
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -73,16 +73,17 @@ class MediaPipeline;
 #ifdef USE_FAKE_MEDIA_STREAMS
 typedef Fake_DOMMediaStream DOMMediaStream;
 #else
 class DOMMediaStream;
 #endif
 
 namespace dom {
 struct RTCConfiguration;
+struct RTCIceServer;
 struct RTCOfferOptions;
 #ifdef USE_FAKE_MEDIA_STREAMS
 typedef Fake_MediaStreamTrack MediaStreamTrack;
 #else
 class MediaStreamTrack;
 #endif
 
 #ifdef USE_FAKE_PCOBSERVER
@@ -113,16 +114,17 @@ NS_IMETHODIMP func(__VA_ARGS__, resultty
 already_AddRefed<resulttype> func (__VA_ARGS__, rv)
 
 struct MediaStreamTable;
 
 namespace mozilla {
 
 using mozilla::dom::PeerConnectionObserver;
 using mozilla::dom::RTCConfiguration;
+using mozilla::dom::RTCIceServer;
 using mozilla::dom::RTCOfferOptions;
 using mozilla::DOMMediaStream;
 using mozilla::NrIceCtx;
 using mozilla::NrIceMediaStream;
 using mozilla::DtlsIdentity;
 using mozilla::ErrorResult;
 using mozilla::NrIceStunServer;
 using mozilla::NrIceTurnServer;
@@ -254,16 +256,18 @@ public:
   bool WrapObject(JSContext* aCx, JS::MutableHandle<JSObject*> aReflector);
 #endif
 
   static already_AddRefed<PeerConnectionImpl>
       Constructor(const mozilla::dom::GlobalObject& aGlobal, ErrorResult& rv);
   static PeerConnectionImpl* CreatePeerConnection();
   static nsresult ConvertRTCConfiguration(const RTCConfiguration& aSrc,
                                           IceConfiguration *aDst);
+  static nsresult AddIceServer(const RTCIceServer& aServer,
+                               IceConfiguration* aDst);
   already_AddRefed<DOMMediaStream> MakeMediaStream(uint32_t aHint);
 
   nsresult CreateRemoteSourceStreamInfo(nsRefPtr<RemoteSourceStreamInfo>* aInfo,
                                         const std::string& aId);
 
   // DataConnection observers
   void NotifyDataChannel(already_AddRefed<mozilla::DataChannel> aChannel)
 #ifdef MOZILLA_INTERNAL_API
--- a/mfbt/TypedEnum.h
+++ b/mfbt/TypedEnum.h
@@ -10,41 +10,16 @@
 #define mozilla_TypedEnum_h
 
 #include "mozilla/TypedEnumInternal.h"
 #include "mozilla/MacroArgs.h"
 
 #if defined(__cplusplus)
 
 /**
- * MOZ_ENUM_TYPE specifies the underlying numeric type for an enum.  It's
- * specified by placing MOZ_ENUM_TYPE(type) immediately after the enum name in
- * its declaration, and before the opening curly brace, like
- *
- *   enum MyEnum MOZ_ENUM_TYPE(uint16_t)
- *   {
- *     A,
- *     B = 7,
- *     C
- *   };
- *
- * In supporting compilers, the macro will expand to ": uint16_t".  The
- * compiler will allocate exactly two bytes for MyEnum and will require all
- * enumerators to have values between 0 and 65535.  (Thus specifying "B =
- * 100000" instead of "B = 7" would fail to compile.)  In old compilers the
- * macro expands to the empty string, and the underlying type is generally
- * undefined.
- */
-#ifdef MOZ_HAVE_CXX11_ENUM_TYPE
-#  define MOZ_ENUM_TYPE(type)   : type
-#else
-#  define MOZ_ENUM_TYPE(type)   /* no support */
-#endif
-
-/**
  * MOZ_BEGIN_ENUM_CLASS and MOZ_END_ENUM_CLASS provide access to the
  * strongly-typed enumeration feature of C++11 ("enum class").  If supported
  * by the compiler, an enum defined using these macros will not be implicitly
  * converted to any other type, and its enumerators will be scoped using the
  * enumeration name.  Place MOZ_BEGIN_ENUM_CLASS(EnumName [, type]) in place of
  * "enum EnumName {", and MOZ_END_ENUM_CLASS(EnumName) in place of the closing
  * "};".  For example,
  *
@@ -150,17 +125,17 @@
      public: \
        enum Enum \
        {
    /* Two-argument form. */
 #  define MOZ_BEGIN_NESTED_ENUM_CLASS_HELPER2(Name, type) \
      class Name \
      { \
      public: \
-       enum Enum MOZ_ENUM_TYPE(type) \
+       enum Enum : type \
        {
 #  define MOZ_END_NESTED_ENUM_CLASS(Name) \
        }; \
        Name() {} \
        MOZ_CONSTEXPR Name(Enum aEnum) : mEnum(aEnum) {} \
        template<typename Other> \
        explicit MOZ_CONSTEXPR Name(Other num) : mEnum((Enum)num) {} \
        MOZ_CONSTEXPR operator Enum() const { return mEnum; } \
--- a/mfbt/TypedEnumInternal.h
+++ b/mfbt/TypedEnumInternal.h
@@ -21,28 +21,25 @@
     * Per Clang documentation, "Note that marketing version numbers should not
     * be used to check for language features, as different vendors use different
     * numbering schemes. Instead, use the feature checking macros."
     */
 #  ifndef __has_extension
 #    define __has_extension __has_feature /* compatibility, for older versions of clang */
 #  endif
 #  if __has_extension(cxx_strong_enums)
-#    define MOZ_HAVE_CXX11_ENUM_TYPE
 #    define MOZ_HAVE_CXX11_STRONG_ENUMS
 #  endif
 #elif defined(__GNUC__)
 #  if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
 #    if MOZ_GCC_VERSION_AT_LEAST(4, 6, 3)
-#      define MOZ_HAVE_CXX11_ENUM_TYPE
 #      define MOZ_HAVE_CXX11_STRONG_ENUMS
 #    endif
 #  endif
 #elif defined(_MSC_VER)
-#  define MOZ_HAVE_CXX11_ENUM_TYPE
 #  define MOZ_HAVE_CXX11_STRONG_ENUMS
 #endif
 
 namespace mozilla {
 
 /*
  * The problem that CastableTypedEnumResult aims to solve is that
  * typed enums are not convertible to bool, and there is no way to make them
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -558,17 +558,17 @@ pref("media.video-queue.default-size", 3
 
 // Enable the MediaCodec PlatformDecoderModule by default.
 pref("media.fragmented-mp4.exposed", true);
 pref("media.fragmented-mp4.enabled", true);
 pref("media.fragmented-mp4.android-media-codec.enabled", true);
 pref("media.fragmented-mp4.android-media-codec.preferred", true);
 
 // optimize images memory usage
-pref("image.mem.decodeondraw", false);
+pref("image.mem.decodeondraw", true);
 
 #ifdef NIGHTLY_BUILD
 // Shumway component (SWF player) is disabled by default. Also see bug 904346.
 pref("shumway.disabled", true);
 #endif
 
 // enable touch events interfaces
 pref("dom.w3c_touch_events.enabled", 1);
--- a/mobile/android/modules/TabMirror.jsm
+++ b/mobile/android/modules/TabMirror.jsm
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Messaging.jsm");
 
-const CONFIG = { iceServers: [{ "url": "stun:stun.services.mozilla.com" }] };
+const CONFIG = { iceServers: [{ "urls": ["stun:stun.services.mozilla.com"] }] };
 
 let log = Cu.import("resource://gre/modules/AndroidLog.jsm",
                     {}).AndroidLog.d.bind(null, "TabMirror");
 
 let failure = function(x) {
   log("ERROR: " + JSON.stringify(x));
 };
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -355,17 +355,17 @@ pref("media.getusermedia.aec", 1);
 pref("media.getusermedia.browser.enabled", true);
 // Desktop is typically VGA capture or more; and qm_select will not drop resolution
 // below 1/2 in each dimension (or so), so QVGA (320x200) is the lowest here usually.
 pref("media.peerconnection.video.min_bitrate", 200);
 pref("media.peerconnection.video.start_bitrate", 300);
 pref("media.peerconnection.video.max_bitrate", 2000);
 #endif
 pref("media.navigator.permission.disabled", false);
-pref("media.peerconnection.default_iceservers", "[{\"url\": \"stun:stun.services.mozilla.com\"}]");
+pref("media.peerconnection.default_iceservers", "[{\"urls\": [\"stun:stun.services.mozilla.com\"]}]");
 pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
 pref("media.peerconnection.use_document_iceservers", true);
 // Do not enable identity before ensuring that the UX cannot be spoofed
 // see Bug 884573 for details
 // Do not enable identity before fixing domain comparison: see Bug 958741
 // Do not enable identity before fixing origin spoofing: see Bug 968335
 pref("media.peerconnection.identity.enabled", false);
 pref("media.peerconnection.identity.timeout", 10000);
@@ -3784,17 +3784,17 @@ pref("image.high_quality_upscaling.max_s
 //
 
 // Discards inactive image frames and re-decodes them on demand from
 // compressed data.
 pref("image.mem.discardable", true);
 
 // Prevents images from automatically being decoded on load, instead allowing
 // them to be decoded on demand when they are drawn.
-pref("image.mem.decodeondraw", false);
+pref("image.mem.decodeondraw", true);
 
 // Allows image locking of decoded image data in content processes.
 pref("image.mem.allow_locking_in_content_processes", true);
 
 // Chunk size for calls to the image decoders
 pref("image.mem.decode_bytes_at_a_time", 16384);
 
 // Minimum timeout for expiring unused images from the surface cache, in
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -2178,18 +2178,20 @@ HttpBaseChannel::SetupReplacementChannel
     }
     // Transfer existing redirect information. Add all of our existing
     // redirects to the new channel.
     for (int32_t i = 0; i < mRedirects.Count(); ++i) {
 #ifdef PR_LOGGING
       nsCOMPtr<nsIURI> uri;
       mRedirects[i]->GetURI(getter_AddRefs(uri));
       nsCString spec;
-      uri->GetSpec(spec);
-      LOG(("HttpBaseChannel::SetupReplacementChannel adding redirect %s "
+      if (uri) {
+        uri->GetSpec(spec);
+      }
+      LOG(("HttpBaseChannel::SetupReplacementChannel adding redirect \'%s\' "
            "[this=%p]", spec.get(), this));
 #endif
       httpInternal->AddRedirect(mRedirects[i]);
     }
 
     // Add our own principal to the redirect information on the new channel. If
     // the redirect is vetoed, then newChannel->AsyncOpen won't be called.
     // However, the new channel's redirect chain will still be complete.
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -1,16 +1,16 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || e10s
+skip-if = buildapp == 'b2g' || e10s || toolkit == 'android' # Android: Bug 1111137 & 1078267
+
 support-files =
   method.sjs
   partial_content.sjs
   user_agent.sjs
   user_agent_update.sjs
 
 [test_arraybufferinputstream.html]
 [test_partially_cached_content.html]
 [test_uri_scheme.html]
 [test_user_agent_overrides.html]
-skip-if = toolkit == 'android' # Bug 1111137
 [test_user_agent_updates.html]
 [test_user_agent_updates_reset.html]
 [test_xhr_method_case.html]
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -258,18 +258,20 @@ fail-if = os == "android"
 [test_simple.js]
 [test_sockettransportsvc_available.js]
 [test_socks.js]
 # Bug 675039: test fails consistently on Android
 fail-if = os == "android"
 # spdy and http2 unit tests require us to have node available to run the spdy and http2 server
 [test_spdy.js]
 run-if = hasNode
+run-sequentially = node server exceptions dont replay well
 [test_http2.js]
 run-if = hasNode
+run-sequentially = node server exceptions dont replay well
 [test_speculative_connect.js]
 [test_standardurl.js]
 [test_standardurl_port.js]
 [test_streamcopier.js]
 [test_traceable_channel.js]
 [test_unescapestring.js]
 [test_xmlhttprequest.js]
 [test_XHR_redirects.js]
new file mode 100644
--- /dev/null
+++ b/testing/config/mozharness/android_arm_4_4_config.py
@@ -0,0 +1,105 @@
+# 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/.
+
+config = {
+    "suite_definitions": {
+        "mochitest": {
+            "run_filename": "runtestsremote.py",
+            "testsdir": "mochitest",
+            "options": ["--autorun", "--close-when-done", "--dm_trans=adb",
+                "--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s",
+                "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s",
+                "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s",
+                "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s",
+                "--quiet", "--log-raw=%(raw_log_file)s",
+                "--total-chunks=16",
+                "--run-only-tests=android23.json",
+            ],
+        },
+        "mochitest-gl": {
+            "run_filename": "runtestsremote.py",
+            "testsdir": "mochitest",
+            "options": ["--autorun", "--close-when-done", "--dm_trans=adb",
+                "--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s",
+                "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s",
+                "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s",
+                "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s",
+                "--quiet", "--log-raw=%(raw_log_file)s",
+                "--total-chunks=2",
+                "--test-manifest=gl.json",
+            ],
+        },
+        "robocop": {
+            "run_filename": "runtestsremote.py",
+            "testsdir": "mochitest",
+            "options": ["--autorun", "--close-when-done", "--dm_trans=adb",
+                "--console-level=INFO", "--app=%(app)s", "--remote-webserver=%(remote_webserver)s",
+                "--xre-path=%(xre_path)s", "--utility-path=%(utility_path)s",
+                "--http-port=%(http_port)s", "--ssl-port=%(ssl_port)s",
+                "--certificate-path=%(certs_path)s", "--symbols-path=%(symbols_path)s",
+                "--quiet", "--log-raw=%(raw_log_file)s",
+                "--total-chunks=4",
+                "--robocop-path=../..",
+                "--robocop-ids=fennec_ids.txt",
+                "--robocop=robocop.ini",
+            ],
+        },
+        "reftest": {
+            "run_filename": "remotereftest.py",
+            "testsdir": "reftest",
+            "options": [ "--app=%(app)s", "--ignore-window-size",
+                "--dm_trans=adb",
+                "--bootstrap",
+                "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s",
+                "--utility-path=%(utility_path)s", "--http-port=%(http_port)s",
+                "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s",
+                "--symbols-path=%(symbols_path)s",
+                "--total-chunks=16",
+                "tests/layout/reftests/reftest.list",
+            ],
+        },
+        "crashtest": {
+            "run_filename": "remotereftest.py",
+            "testsdir": "reftest",
+            "options": [ "--app=%(app)s", "--ignore-window-size",
+                "--dm_trans=adb",
+                "--bootstrap",
+                "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s",
+                "--utility-path=%(utility_path)s", "--http-port=%(http_port)s",
+                "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s",
+                "--symbols-path=%(symbols_path)s",
+                "--total-chunks=2",
+                "tests/testing/crashtest/crashtests.list",
+            ],
+        },
+        "jsreftest": {
+            "run_filename": "remotereftest.py",
+            "testsdir": "reftest",
+            "options": [ "--app=%(app)s", "--ignore-window-size",
+                "--dm_trans=adb",
+                "--bootstrap",
+                "--remote-webserver=%(remote_webserver)s", "--xre-path=%(xre_path)s",
+                "--utility-path=%(utility_path)s", "--http-port=%(http_port)s",
+                "--ssl-port=%(ssl_port)s", "--httpd-path", "%(modules_dir)s",
+                "--symbols-path=%(symbols_path)s",
+                "../jsreftest/tests/jstests.list",
+                "--total-chunks=6",
+                "--extra-profile-file=jsreftest/tests/user.js",
+            ],
+        },
+        "xpcshell": {
+            "run_filename": "remotexpcshelltests.py",
+            "testsdir": "xpcshell",
+            "options": [
+                "--dm_trans=adb",
+                "--xre-path=%(xre_path)s", "--testing-modules-dir=%(modules_dir)s",
+                "--apk=%(installer_path)s", "--no-logfiles",
+                "--symbols-path=%(symbols_path)s",
+                "--manifest=tests/xpcshell.ini",
+                "--log-raw=%(raw_log_file)s",
+                "--total-chunks=3",
+            ],
+        },
+    }, # end suite_definitions
+}
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -1,16 +1,16 @@
 {
     "talos.zip": {
         "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.f3179facd945.zip",
         "path": ""
     },
     "global": {
         "talos_repo": "https://hg.mozilla.org/build/talos",
-        "talos_revision": "ebc4327b8cb8"
+        "talos_revision": "39c9c9b33cfc"
     },
     "extra_options": {
         "android": [ "--apkPath=%(apk_path)s" ]
     },
     "suites": {
         "chromez": {
             "tests": ["tresize", "tcanvasmark"]
         },
@@ -34,17 +34,18 @@
         },
         "other": {
             "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore"]
         },
         "other-snow": {
             "tests": ["tpaint"]
         },
         "other-snow-e10s": {
-            "tests": ["tpaint"]
+            "tests": ["tpaint"],
+            "talos_options": ["--e10s"]
         },
         "other_nol64": {
             "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore"]
         },
         "other-e10s_nol64": {
             "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore"],
             "talos_options": ["--e10s"]
         },
@@ -75,30 +76,32 @@
                 "32": "http://talos-bundles.pvt.build.mozilla.org/zips/flash32_10_3_183_5.zip",
                 "64": "http://talos-bundles.pvt.build.mozilla.org/zips/flash64_11_0_d1_98.zip"
             }
         },
         "g1-snow": {
             "tests": ["glterrain"]
         },
         "g1-snow-e10s": {
-            "tests": ["glterrain"]
+            "tests": ["glterrain"],
+            "talos_options": ["--e10s"]
         },
         "svgr": {
             "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"]
         },
         "svgr-e10s": {
             "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"],
             "talos_options": ["--e10s"]
         },
         "svgr-snow": {
             "tests": ["tsvgx", "tscrollx"]
         },
         "svgr-snow-e10s": {
-            "tests": ["tsvgx", "tscrollx"]
+            "tests": ["tsvgx", "tscrollx"],
+            "talos_options": ["--e10s"]
         },
         "tp5o": {
             "tests": ["tp5o"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip",
             "pagesets_parent_dir_path": "talos/page_load_test/",
             "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest",
             "plugins": {
                 "32": "http://talos-bundles.pvt.build.mozilla.org/zips/flash32_10_3_183_5.zip",
--- a/testing/web-platform/harness/wptrunner/browsers/firefox.py
+++ b/testing/web-platform/harness/wptrunner/browsers/firefox.py
@@ -181,18 +181,26 @@ class FirefoxBrowser(Browser):
 
         self.logger.info("Setting up ssl")
 
         # Make sure the certutil libraries from the source tree are loaded when using a
         # local copy of certutil
         # TODO: Maybe only set this if certutil won't launch?
         env = os.environ.copy()
         certutil_dir = os.path.dirname(self.binary)
-        env["LD_LIBRARY_PATH"] = certutil_dir
-        env["PATH"] = os.path.pathsep.join([certutil_dir, env["PATH"]])
+        if mozinfo.isMac:
+            env_var = "DYLD_LIBRARY_PATH"
+        elif mozinfo.isUnix:
+            env_var = "LD_LIBRARY_PATH"
+        else:
+            env_var = "PATH"
+
+
+        env[env_var] = (os.path.pathsep.join([certutil_dir, env[env_var]])
+                        if env_var in env else certutil_dir)
 
         def certutil(*args):
             cmd = [self.certutil_binary] + list(args)
             self.logger.process_output("certutil",
                                        subprocess.check_output(cmd,
                                                                env=env,
                                                                stderr=subprocess.STDOUT),
                                        " ".join(cmd))
--- a/toolkit/content/tests/widgets/mochitest.ini
+++ b/toolkit/content/tests/widgets/mochitest.ini
@@ -23,10 +23,11 @@ support-files =
 
 [test_audiocontrols_dimensions.html]
 skip-if = toolkit == 'android'
 [test_mousecapture_area.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_videocontrols_audio.html]
 [test_videocontrols_audio_direction.html]
 [test_videocontrols_standalone.html]
+skip-if = android_version == '10' # bug 1075573
 [test_videocontrols_video_direction.html]
 [test_bug898940.html]
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -71,17 +71,17 @@ public:
 
     bool IsInProgress();
     bool IsScheduled();
     bool IsCompleted();
 
     nsresult GetStatus(uint16_t *aStatus);
 
 private:
-    enum LoadStatus MOZ_ENUM_TYPE(uint16_t) {
+    enum LoadStatus : uint16_t {
       UNINITIALIZED = 0U,
       REQUESTED = 1U,
       RECEIVING = 2U,
       LOADED = 3U
     };
 
     nsRefPtr<nsOfflineCacheUpdate> mUpdate;
     nsCOMPtr<nsIChannel>           mChannel;
--- a/widget/EventForwards.h
+++ b/widget/EventForwards.h
@@ -27,17 +27,17 @@ enum nsEventStatus
   // The event is consumed, but do default processing
   nsEventStatus_eConsumeDoDefault
 };
 
 namespace mozilla {
 
 typedef uint8_t EventClassIDType;
 
-enum EventClassID MOZ_ENUM_TYPE(EventClassIDType)
+enum EventClassID : EventClassIDType
 {
   // The event class name will be:
   //   eBasicEventClass for WidgetEvent
   //   eFooEventClass for WidgetFooEvent or InternalFooEvent
 #define NS_ROOT_EVENT_CLASS(aPrefix, aName)   eBasic##aName##Class
 #define NS_EVENT_CLASS(aPrefix, aName)      , e##aName##Class
 
 #include "mozilla/EventClassList.h"
@@ -72,17 +72,17 @@ enum CodeNameIndex
   CODE_NAME_INDEX_USE_STRING
 };
 
 #undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME
 
 #define NS_DEFINE_COMMAND(aName, aCommandStr) , Command##aName
 
 typedef int8_t CommandInt;
-enum Command MOZ_ENUM_TYPE(CommandInt)
+enum Command : CommandInt
 {
   CommandDoNothing
 
 #include "mozilla/CommandList.h"
 };
 #undef NS_DEFINE_COMMAND
 
 } // namespace mozilla
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -25,17 +25,18 @@
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/PLayerTransaction.h"
 #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
 #include "mozilla/StaticPtr.h"
 #include "cutils/properties.h"
 #include "gfx2DGlue.h"
-#include "nsWindow.h"
+#include "gfxPlatform.h"
+#include "VsyncSource.h"
 
 #if ANDROID_VERSION >= 17
 #include "libdisplay/FramebufferSurface.h"
 #include "gfxPrefs.h"
 #include "nsThreadUtils.h"
 
 #ifndef HWC_BLIT
 #define HWC_BLIT (HWC_FRAMEBUFFER_TARGET + 1)
@@ -222,17 +223,18 @@ void
 HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp)
 {
     TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(aVsyncTimestamp);
     nsecs_t vsyncInterval = aVsyncTimestamp - mLastVsyncTime;
     if (vsyncInterval < 16000000 || vsyncInterval > 17000000) {
       LOGE("Non-uniform vsync interval: %lld\n", vsyncInterval);
     }
     mLastVsyncTime = aVsyncTimestamp;
-    nsWindow::NotifyVsync(vsyncTime);
+
+    gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().NotifyVsync(vsyncTime);
 }
 
 // Called on the "invalidator" thread (run from HAL).
 void
 HwcComposer2D::Invalidate()
 {
     if (!Initialized()) {
         LOGE("HwcComposer2D::Invalidate failed!");
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -210,31 +210,16 @@ nsWindow::DoDraw(void)
     }
 
     listener = targetWindow->GetWidgetListener();
     if (listener) {
         listener->DidPaintWindow();
     }
 }
 
-/* static */ void
-nsWindow::NotifyVsync(TimeStamp aVsyncTimestamp)
-{
-    if (!gFocusedWindow) {
-      return;
-    }
-
-    CompositorVsyncDispatcher* vsyncDispatcher = gFocusedWindow->GetCompositorVsyncDispatcher();
-    // During bootup, there is a delay between when the nsWindow is created
-    // and when the Compositor is created, but vsync is already turned on
-    if (vsyncDispatcher) {
-      vsyncDispatcher->NotifyVsync(aVsyncTimestamp);
-    }
-}
-
 /*static*/ nsEventStatus
 nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent)
 {
     if (!gFocusedWindow) {
         return nsEventStatus_eIgnore;
     }
 
     gFocusedWindow->UserActivity();
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -45,17 +45,16 @@ struct InputContextAction;
 }
 
 class nsWindow : public nsBaseWidget
 {
 public:
     nsWindow();
     virtual ~nsWindow();
 
-    static void NotifyVsync(mozilla::TimeStamp aVsyncTimestamp);
     static void DoDraw(void);
     static nsEventStatus DispatchInputEvent(mozilla::WidgetGUIEvent& aEvent);
     static void DispatchTouchInput(mozilla::MultiTouchInput& aInput);
 
     NS_IMETHOD Create(nsIWidget *aParent,
                       void *aNativeParent,
                       const nsIntRect &aRect,
                       nsDeviceContext *aContext,
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -220,17 +220,17 @@ enum nsTopLevelWidgetZPlacement { // for
  * they should set mWantUpdates to NOTIFY_NOTHING to avoid the cost.
  * If the IME implementation needs notifications even while our process is
  * deactive, it should also set NOTIFY_DURING_DEACTIVE.
  */
 struct nsIMEUpdatePreference {
 
   typedef uint8_t Notifications;
 
-  enum MOZ_ENUM_TYPE(Notifications)
+  enum : Notifications
   {
     NOTIFY_NOTHING                       = 0,
     NOTIFY_SELECTION_CHANGE              = 1 << 0,
     NOTIFY_TEXT_CHANGE                   = 1 << 1,
     NOTIFY_POSITION_CHANGE               = 1 << 2,
     // NOTIFY_MOUSE_BUTTON_EVENT_ON_CHAR is used when mouse button is pressed
     // or released on a character in the focused editor.  The notification is
     // notified to IME as a mouse event.  If it's consumed by IME, NotifyIME()
@@ -514,17 +514,17 @@ struct SizeConstraints {
   nsIntSize mMinSize;
   nsIntSize mMaxSize;
 };
 
 // IMEMessage is shared by IMEStateManager and TextComposition.
 // Update values in GeckoEditable.java if you make changes here.
 // XXX Negative values are used in Android...
 typedef int8_t IMEMessageType;
-enum IMEMessage MOZ_ENUM_TYPE(IMEMessageType)
+enum IMEMessage : IMEMessageType
 {
   // An editable content is getting focus
   NOTIFY_IME_OF_FOCUS = 1,
   // An editable content is losing focus
   NOTIFY_IME_OF_BLUR,
   // Selection in the focused editable content is changed
   NOTIFY_IME_OF_SELECTION_CHANGE,
   // Text in the focused editable content is changed
--- a/widget/windows/nsTextStore.h
+++ b/widget/windows/nsTextStore.h
@@ -475,17 +475,17 @@ protected:
   // mSelection with the selection at the first call during a lock and returns
   // it.  However, mSelection is NOT modified immediately.  When pending
   // changes are flushed at unlocking the document, cached mSelection is
   // modified.  Note that this is also called by LockedContent().
   Selection& CurrentSelection();
 
   struct PendingAction MOZ_FINAL
   {
-    enum ActionType MOZ_ENUM_TYPE(uint8_t)
+    enum ActionType : uint8_t
     {
       COMPOSITION_START,
       COMPOSITION_UPDATE,
       COMPOSITION_END,
       SELECTION_SET
     };
     ActionType mType;
     // For compositionstart and selectionset
@@ -630,17 +630,17 @@ protected:
     nsTextStore::Selection& Selection() { return mSelection; }
 
   private:
     nsString mText;
     nsTextStore::Composition& mComposition;
     nsTextStore::Selection& mSelection;
 
     // The minimum offset of modified part of the text.
-    enum MOZ_ENUM_TYPE(uint32_t)
+    enum : uint32_t
     {
       NOT_MODIFIED = UINT32_MAX
     };
     uint32_t mMinTextModifiedOffset;
 
     bool mInitialized;
   };
   // mLockedContent caches content of the document ONLY while the document
--- a/xpcom/base/nsError.h
+++ b/xpcom/base/nsError.h
@@ -131,39 +131,24 @@
     #undef ERROR
   } nsresult;
 
   /*
    * enum classes don't place their initializers in the global scope, so we need
    * #define's for compatibility with old code.
    */
   #include "ErrorListCxxDefines.h"
-#elif defined(MOZ_HAVE_CXX11_ENUM_TYPE)
+#elif defined(__cplusplus)
   typedef enum tag_nsresult : uint32_t
   {
     #undef ERROR
     #define ERROR(key, val) key = val
     #include "ErrorList.h"
     #undef ERROR
   } nsresult;
-#elif defined(__cplusplus)
-  /*
-   * We're C++ in an old compiler lacking enum classes *and* typed enums (likely
-   * gcc < 4.5.1 as clang/MSVC have long supported one or both), or compiler
-   * support is unknown.  Yet nsresult must have unsigned 32-bit representation.
-   * So just make it a typedef, and implement the constants with global consts.
-   */
-  typedef uint32_t nsresult;
-
-  const nsresult
-  #undef ERROR
-  #define ERROR(key, val) key = val
-  #include "ErrorList.h"
-  #undef ERROR
-    ;
 #else
   /*
    * C doesn't have any way to fix the type underlying an enum, and enum
    * initializers can't have values outside the range of 'int'.  So typedef
    * nsresult to the correct unsigned type, and fall back to using #defines for
    * all error constants.
    */
   typedef uint32_t nsresult;
deleted file mode 100644
--- a/xpcom/tests/TestPipes.cpp
+++ /dev/null
@@ -1,469 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* 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 "TestHarness.h"
-
-#include "nsIThread.h"
-#include "nsIRunnable.h"
-#include "nsThreadUtils.h"
-#include "prprf.h"
-#include "prinrval.h"
-#include "nsCRT.h"
-#include "nsIPipe.h"    // new implementation
-
-#include "mozilla/Monitor.h"
-using namespace mozilla;
-
-/** NS_NewPipe2 reimplemented, because it's not exported by XPCOM */
-nsresult TP_NewPipe2(nsIAsyncInputStream** input,
-                     nsIAsyncOutputStream** output,
-                     bool nonBlockingInput,
-                     bool nonBlockingOutput,
-                     uint32_t segmentSize,
-                     uint32_t segmentCount,
-                     nsIMemory* segmentAlloc)
-{
-  nsCOMPtr<nsIPipe> pipe = do_CreateInstance("@mozilla.org/pipe;1");
-  if (!pipe)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  nsresult rv = pipe->Init(nonBlockingInput,
-                           nonBlockingOutput,
-                           segmentSize,
-                           segmentCount,
-                           segmentAlloc);
-
-  if (NS_FAILED(rv))
-    return rv;
-
-  pipe->GetInputStream(input);
-  pipe->GetOutputStream(output);
-  return NS_OK;
-}
-
-/** NS_NewPipe reimplemented, because it's not exported by XPCOM */
-#define TP_DEFAULT_SEGMENT_SIZE  4096
-nsresult TP_NewPipe(nsIInputStream **pipeIn,
-                    nsIOutputStream **pipeOut,
-                    uint32_t segmentSize = 0,
-                    uint32_t maxSize = 0,
-                    bool nonBlockingInput = false,
-                    bool nonBlockingOutput = false,
-                    nsIMemory *segmentAlloc = nullptr);
-nsresult TP_NewPipe(nsIInputStream **pipeIn,
-                    nsIOutputStream **pipeOut,
-                    uint32_t segmentSize,
-                    uint32_t maxSize,
-                    bool nonBlockingInput,
-                    bool nonBlockingOutput,
-                    nsIMemory *segmentAlloc)
-{
-    if (segmentSize == 0)
-        segmentSize = TP_DEFAULT_SEGMENT_SIZE;
-
-    // Handle maxSize of UINT32_MAX as a special case
-    uint32_t segmentCount;
-    if (maxSize == UINT32_MAX)
-        segmentCount = UINT32_MAX;
-    else
-        segmentCount = maxSize / segmentSize;
-
-    nsIAsyncInputStream *in;
-    nsIAsyncOutputStream *out;
-    nsresult rv = TP_NewPipe2(&in, &out, nonBlockingInput, nonBlockingOutput,
-                              segmentSize, segmentCount, segmentAlloc);
-    if (NS_FAILED(rv)) return rv;
-
-    *pipeIn = in;
-    *pipeOut = out;
-    return NS_OK;
-}
-
-
-#define KEY             0xa7
-#define ITERATIONS      33333
-char kTestPattern[] = "My hovercraft is full of eels.\n";
-
-bool gTrace = false;
-
-static nsresult
-WriteAll(nsIOutputStream *os, const char *buf, uint32_t bufLen, uint32_t *lenWritten)
-{
-    const char *p = buf;
-    *lenWritten = 0;
-    while (bufLen) {
-        uint32_t n;
-        nsresult rv = os->Write(p, bufLen, &n);
-        if (NS_FAILED(rv)) return rv;
-        p += n;
-        bufLen -= n;
-        *lenWritten += n;
-    }
-    return NS_OK;
-}
-
-class nsReceiver : public nsIRunnable {
-public:
-    NS_DECL_THREADSAFE_ISUPPORTS
-
-    NS_IMETHOD Run() {
-        nsresult rv;
-        char buf[101];
-        uint32_t count;
-        PRIntervalTime start = PR_IntervalNow();
-        while (true) {
-            rv = mIn->Read(buf, 100, &count);
-            if (NS_FAILED(rv)) {
-                printf("read failed\n");
-                break;
-            }
-            if (count == 0) {
-//                printf("EOF count = %d\n", mCount);
-                break;
-            }
-
-            if (gTrace) {
-                buf[count] = '\0';
-                printf("read: %s\n", buf);
-            }
-            mCount += count;
-        }
-        PRIntervalTime end = PR_IntervalNow();
-        printf("read  %d bytes, time = %dms\n", mCount,
-               PR_IntervalToMilliseconds(end - start));
-        return rv;
-    }
-
-    nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) {
-    }
-
-    uint32_t GetBytesRead() { return mCount; }
-
-protected:
-    nsCOMPtr<nsIInputStream> mIn;
-    uint32_t            mCount;
-};
-
-NS_IMPL_ISUPPORTS(nsReceiver, nsIRunnable)
-
-nsresult
-TestPipe(nsIInputStream* in, nsIOutputStream* out)
-{
-    nsCOMPtr<nsReceiver> receiver = new nsReceiver(in);
-    if (!receiver)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    nsresult rv;
-
-    nsCOMPtr<nsIThread> thread;
-    rv = NS_NewThread(getter_AddRefs(thread), receiver);
-    if (NS_FAILED(rv)) return rv;
-
-    uint32_t total = 0;
-    PRIntervalTime start = PR_IntervalNow();
-    for (uint32_t i = 0; i < ITERATIONS; i++) {
-        uint32_t writeCount;
-        char *buf = PR_smprintf("%d %s", i, kTestPattern);
-        uint32_t len = strlen(buf);
-        rv = WriteAll(out, buf, len, &writeCount);
-        if (gTrace) {
-            printf("wrote: ");
-            for (uint32_t j = 0; j < writeCount; j++) {
-                putc(buf[j], stdout);
-            }
-            printf("\n");
-        }
-        PR_smprintf_free(buf);
-        if (NS_FAILED(rv)) return rv;
-        total += writeCount;
-    }
-    rv = out->Close();
-    if (NS_FAILED(rv)) return rv;
-
-    PRIntervalTime end = PR_IntervalNow();
-
-    thread->Shutdown();
-
-    printf("wrote %d bytes, time = %dms\n", total,
-           PR_IntervalToMilliseconds(end - start));
-    NS_ASSERTION(receiver->GetBytesRead() == total, "didn't read everything");
-
-    return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-class nsShortReader : public nsIRunnable {
-public:
-    NS_DECL_THREADSAFE_ISUPPORTS
-
-    NS_IMETHOD Run() {
-        nsresult rv;
-        char buf[101];
-        uint32_t count;
-        uint32_t total = 0;
-        while (true) {
-            //if (gTrace)
-            //    printf("calling Read\n");
-            rv = mIn->Read(buf, 100, &count);
-            if (NS_FAILED(rv)) {
-                printf("read failed\n");
-                break;
-            }
-            if (count == 0) {
-                break;
-            }
-
-            if (gTrace) {
-                // For next |printf()| call and possible others elsewhere.
-                buf[count] = '\0';
-
-                printf("read %d bytes: %s\n", count, buf);
-            }
-
-            Received(count);
-            total += count;
-        }
-        printf("read  %d bytes\n", total);
-        return rv;
-    }
-
-    nsShortReader(nsIInputStream* in) : mIn(in), mReceived(0) {
-        mMon = new Monitor("nsShortReader");
-    }
-
-    void Received(uint32_t count) {
-        MonitorAutoEnter mon(*mMon);
-        mReceived += count;
-        mon.Notify();
-    }
-
-    uint32_t WaitForReceipt(const uint32_t aWriteCount) {
-        MonitorAutoEnter mon(*mMon);
-        uint32_t result = mReceived;
-
-        while (result < aWriteCount) {
-            mon.Wait();
-
-            NS_ASSERTION(mReceived > result, "failed to receive");
-            result = mReceived;
-        }
-
-        mReceived = 0;
-        return result;
-    }
-
-protected:
-    nsCOMPtr<nsIInputStream> mIn;
-    uint32_t                 mReceived;
-    Monitor*                 mMon;
-};
-
-NS_IMPL_ISUPPORTS(nsShortReader, nsIRunnable)
-
-nsresult
-TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
-{
-    nsCOMPtr<nsShortReader> receiver = new nsShortReader(in);
-    if (!receiver)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    nsresult rv;
-
-    nsCOMPtr<nsIThread> thread;
-    rv = NS_NewThread(getter_AddRefs(thread), receiver);
-    if (NS_FAILED(rv)) return rv;
-
-    uint32_t total = 0;
-    for (uint32_t i = 0; i < ITERATIONS; i++) {
-        uint32_t writeCount;
-        char* buf = PR_smprintf("%d %s", i, kTestPattern);
-        uint32_t len = strlen(buf);
-        len = len * rand() / RAND_MAX;
-        len = XPCOM_MAX(1, len);
-        rv = WriteAll(out, buf, len, &writeCount);
-        if (NS_FAILED(rv)) return rv;
-        NS_ASSERTION(writeCount == len, "didn't write enough");
-        total += writeCount;
-
-        if (gTrace)
-            printf("wrote %d bytes: %s\n", writeCount, buf);
-        PR_smprintf_free(buf);
-        //printf("calling Flush\n");
-        out->Flush();
-        //printf("calling WaitForReceipt\n");
-
-#ifdef DEBUG
-        const uint32_t received =
-#endif
-          receiver->WaitForReceipt(writeCount);
-        NS_ASSERTION(received == writeCount, "received wrong amount");
-    }
-    rv = out->Close();
-    if (NS_FAILED(rv)) return rv;
-
-    thread->Shutdown();
-
-    printf("wrote %d bytes\n", total);
-
-    return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-class nsPump : public nsIRunnable
-{
-public:
-    NS_DECL_THREADSAFE_ISUPPORTS
-
-    NS_IMETHOD Run() {
-        nsresult rv;
-        uint32_t count;
-        while (true) {
-            rv = mOut->WriteFrom(mIn, ~0U, &count);
-            if (NS_FAILED(rv)) {
-                printf("Write failed\n");
-                break;
-            }
-            if (count == 0) {
-                printf("EOF count = %d\n", mCount);
-                break;
-            }
-
-            if (gTrace) {
-                printf("Wrote: %d\n", count);
-            }
-            mCount += count;
-        }
-        mOut->Close();
-        return rv;
-    }
-
-    nsPump(nsIInputStream* in,
-           nsIOutputStream* out)
-        : mIn(in), mOut(out), mCount(0) {
-    }
-
-protected:
-    nsCOMPtr<nsIInputStream>      mIn;
-    nsCOMPtr<nsIOutputStream>     mOut;
-    uint32_t                            mCount;
-};
-
-NS_IMPL_ISUPPORTS(nsPump, nsIRunnable)
-
-nsresult
-TestChainedPipes()
-{
-    nsresult rv;
-    printf("TestChainedPipes\n");
-
-    nsCOMPtr<nsIInputStream> in1;
-    nsCOMPtr<nsIOutputStream> out1;
-    rv = TP_NewPipe(getter_AddRefs(in1), getter_AddRefs(out1), 20, 1999);
-    if (NS_FAILED(rv)) return rv;
-
-    nsCOMPtr<nsIInputStream> in2;
-    nsCOMPtr<nsIOutputStream> out2;
-    rv = TP_NewPipe(getter_AddRefs(in2), getter_AddRefs(out2), 200, 401);
-    if (NS_FAILED(rv)) return rv;
-
-    nsCOMPtr<nsPump> pump = new nsPump(in1, out2);
-    if (pump == nullptr) return NS_ERROR_OUT_OF_MEMORY;
-
-    nsCOMPtr<nsIThread> thread;
-    rv = NS_NewThread(getter_AddRefs(thread), pump);
-    if (NS_FAILED(rv)) return rv;
-
-    nsCOMPtr<nsReceiver> receiver = new nsReceiver(in2);
-    if (receiver == nullptr) return NS_ERROR_OUT_OF_MEMORY;
-
-    nsCOMPtr<nsIThread> receiverThread;
-    rv = NS_NewThread(getter_AddRefs(receiverThread), receiver);
-    if (NS_FAILED(rv)) return rv;
-
-    uint32_t total = 0;
-    for (uint32_t i = 0; i < ITERATIONS; i++) {
-        uint32_t writeCount;
-        char* buf = PR_smprintf("%d %s", i, kTestPattern);
-        uint32_t len = strlen(buf);
-        len = len * rand() / RAND_MAX;
-        len = XPCOM_MAX(1, len);
-        rv = WriteAll(out1, buf, len, &writeCount);
-        if (NS_FAILED(rv)) return rv;
-        NS_ASSERTION(writeCount == len, "didn't write enough");
-        total += writeCount;
-
-        if (gTrace)
-            printf("wrote %d bytes: %s\n", writeCount, buf);
-
-        PR_smprintf_free(buf);
-    }
-    printf("wrote total of %d bytes\n", total);
-    rv = out1->Close();
-    if (NS_FAILED(rv)) return rv;
-
-    thread->Shutdown();
-    receiverThread->Shutdown();
-
-    return NS_OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-void
-RunTests(uint32_t segSize, uint32_t segCount)
-{
-    nsresult rv;
-    nsCOMPtr<nsIInputStream> in;
-    nsCOMPtr<nsIOutputStream> out;
-    uint32_t bufSize = segSize * segCount;
-    printf("Testing New Pipes: segment size %d buffer size %d\n", segSize, bufSize);
-
-    printf("Testing long writes...\n");
-    rv = TP_NewPipe(getter_AddRefs(in), getter_AddRefs(out), segSize, bufSize);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "TP_NewPipe failed");
-    rv = TestPipe(in, out);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipe failed");
-
-    printf("Testing short writes...\n");
-    rv = TP_NewPipe(getter_AddRefs(in), getter_AddRefs(out), segSize, bufSize);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "TP_NewPipe failed");
-    rv = TestShortWrites(in, out);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipe failed");
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-#if 0
-extern void
-TestSegmentedBuffer();
-#endif
-
-int
-main(int argc, char* argv[])
-{
-    nsresult rv;
-
-    nsCOMPtr<nsIServiceManager> servMgr;
-    rv = NS_InitXPCOM2(getter_AddRefs(servMgr), nullptr, nullptr);
-    if (NS_FAILED(rv)) return rv;
-
-    if (argc > 1 && nsCRT::strcmp(argv[1], "-trace") == 0)
-        gTrace = true;
-
-    rv = TestChainedPipes();
-    NS_ASSERTION(NS_SUCCEEDED(rv), "TestChainedPipes failed");
-    RunTests(16, 1);
-    RunTests(4096, 16);
-
-    servMgr = 0;
-    rv = NS_ShutdownXPCOM(nullptr);
-    NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
-
-    return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
deleted file mode 100644
--- a/xpcom/tests/TestPriorityQueue.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* 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 "nsTPriorityQueue.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-template<class T, class Compare>
-void
-CheckPopSequence(const nsTPriorityQueue<T, Compare>& aQueue,
-                 const T* aExpectedSequence, const uint32_t aSequenceLength)
-{
-  nsTPriorityQueue<T, Compare> copy(aQueue);
-
-  for (uint32_t i = 0; i < aSequenceLength; i++) {
-    if (copy.IsEmpty()) {
-      printf("Number of elements in the queue is too short by %d.\n",
-          aSequenceLength - i);
-      exit(-1);
-    }
-
-    T pop = copy.Pop();
-    if (pop != aExpectedSequence[i]) {
-      printf("Unexpected value in pop sequence at position %d\n", i);
-      printf("  Sequence:");
-      for (size_t j = 0; j < aSequenceLength; j++) {
-        printf(" %d", aExpectedSequence[j]);
-        if (j == i) {
-          printf("**");
-        }
-      }
-      printf("\n            ** Got %d instead\n", pop);
-      exit(-1);
-    }
-  }
-
-  if (!copy.IsEmpty()) {
-    printf("Number of elements in the queue is too long by %d.\n",
-        copy.Length());
-    exit(-1);
-  }
-}
-
-template<class A>
-class MaxCompare {
-public:
-  bool LessThan(const A& a, const A& b) {
-    return a > b;
-  }
-};
-
-int main()
-{
-  nsTPriorityQueue<int> queue;
-
-  NS_ABORT_IF_FALSE(queue.IsEmpty(), "Queue not initially empty");
-
-  queue.Push(8);
-  queue.Push(6);
-  queue.Push(4);
-  queue.Push(2);
-  queue.Push(10);
-  queue.Push(6);
-  NS_ABORT_IF_FALSE(queue.Top() == 2, "Unexpected queue top");
-  NS_ABORT_IF_FALSE(queue.Length() == 6, "Unexpected queue length");
-  NS_ABORT_IF_FALSE(!queue.IsEmpty(), "Queue empty when populated");
-  int expected[] = { 2, 4, 6, 6, 8, 10 };
-  CheckPopSequence(queue, expected, sizeof(expected) / sizeof(expected[0]));
-
-  // copy ctor is tested by using CheckPopSequence, but check default assignment
-  // operator
-  nsTPriorityQueue<int> queue2;
-  queue2 = queue;
-  CheckPopSequence(queue2, expected, sizeof(expected) / sizeof(expected[0]));
-
-  queue.Clear();
-  NS_ABORT_IF_FALSE(queue.IsEmpty(), "Queue not emptied by Clear");
-
-  // try same sequence with a max heap
-  nsTPriorityQueue<int, MaxCompare<int> > max_queue;
-  max_queue.Push(8);
-  max_queue.Push(6);
-  max_queue.Push(4);
-  max_queue.Push(2);
-  max_queue.Push(10);
-  max_queue.Push(6);
-  NS_ABORT_IF_FALSE(max_queue.Top() == 10, "Unexpected queue top for max heap");
-  int expected_max[] = { 10, 8, 6, 6, 4, 2 };
-  CheckPopSequence(max_queue, expected_max,
-      sizeof(expected_max) / sizeof(expected_max[0]));
-
-  return 0;
-}
deleted file mode 100644
--- a/xpcom/tests/TestStorageStream.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <stdlib.h>
-#include "nsIStorageStream.h"
-#include "nsIInputStream.h"
-#include "nsIOutputStream.h"
-#include "nsCOMPtr.h"
-
-int main()
-{
-  char kData[4096];
-  memset(kData, 0, sizeof(kData));
-
-  nsresult rv;
-  nsCOMPtr<nsIStorageStream> stor;
-
-  rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(stor));
-  if (NS_FAILED(rv))
-    return -1;
-
-  nsCOMPtr<nsIOutputStream> out;
-  rv = stor->GetOutputStream(0, getter_AddRefs(out));
-  if (NS_FAILED(rv))
-    return -1;
-
-  uint32_t n;
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  if (NS_FAILED(rv))
-    return -1;
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  if (NS_FAILED(rv))
-    return -1;
-
-  rv = out->Close();
-  if (NS_FAILED(rv))
-    return -1;
-
-  out = nullptr;
-  
-  nsCOMPtr<nsIInputStream> in;
-  rv = stor->NewInputStream(0, getter_AddRefs(in));
-  if (NS_FAILED(rv))
-    return -1;
-
-  char buf[4096];
-
-  // consume contents of input stream
-  do {
-    rv = in->Read(buf, sizeof(buf), &n);
-    if (NS_FAILED(rv))
-      return -1;
-  } while (n != 0);
-
-  rv = in->Close();
-  if (NS_FAILED(rv))
-    return -1;
-  in = nullptr;
-
-  // now, write 3 more full 4k segments + 11 bytes, starting at 8192
-  // total written equals 20491 bytes
-
-  rv = stor->GetOutputStream(8192, getter_AddRefs(out));
-  if (NS_FAILED(rv))
-    return -1;
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  if (NS_FAILED(rv))
-    return -1;
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  if (NS_FAILED(rv))
-    return -1;
-
-  rv = out->Write(kData, sizeof(kData), &n);
-  if (NS_FAILED(rv))
-    return -1;
-
-  rv = out->Write(kData, 11, &n);
-  if (NS_FAILED(rv))
-    return -1;
-
-  rv = out->Close();
-  if (NS_FAILED(rv))
-    return -1;
-
-  out = nullptr;
-
-  // now, read all
-  rv = stor->NewInputStream(0, getter_AddRefs(in));
-  if (NS_FAILED(rv))
-    return -1;
-
-  // consume contents of input stream
-  do {
-    rv = in->Read(buf, sizeof(buf), &n);
-    if (NS_FAILED(rv))
-      return -1;
-  } while (n != 0);
-
-  rv = in->Close();
-  if (NS_FAILED(rv))
-    return -1;
-  in = nullptr;
-
-  return 0;
-}
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/gtest/TestPipes.cpp
@@ -0,0 +1,391 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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 "nsIAsyncInputStream.h"
+#include "nsIAsyncOutputStream.h"
+#include "nsIThread.h"
+#include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+#include "prprf.h"
+#include "prinrval.h"
+#include "nsCRT.h"
+#include "nsIPipe.h"    // new implementation
+
+#include "mozilla/ReentrantMonitor.h"
+
+#include "gtest/gtest.h"
+using namespace mozilla;
+
+#define ITERATIONS      33333
+char kTestPattern[] = "My hovercraft is full of eels.\n";
+
+bool gTrace = false;
+
+static nsresult
+WriteAll(nsIOutputStream *os, const char *buf, uint32_t bufLen, uint32_t *lenWritten)
+{
+    const char *p = buf;
+    *lenWritten = 0;
+    while (bufLen) {
+        uint32_t n;
+        nsresult rv = os->Write(p, bufLen, &n);
+        if (NS_FAILED(rv)) return rv;
+        p += n;
+        bufLen -= n;
+        *lenWritten += n;
+    }
+    return NS_OK;
+}
+
+class nsReceiver MOZ_FINAL : public nsIRunnable {
+public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+
+    NS_IMETHOD Run() MOZ_OVERRIDE {
+        nsresult rv;
+        char buf[101];
+        uint32_t count;
+        PRIntervalTime start = PR_IntervalNow();
+        while (true) {
+            rv = mIn->Read(buf, 100, &count);
+            if (NS_FAILED(rv)) {
+                printf("read failed\n");
+                break;
+            }
+            if (count == 0) {
+//                printf("EOF count = %d\n", mCount);
+                break;
+            }
+
+            if (gTrace) {
+                buf[count] = '\0';
+                printf("read: %s\n", buf);
+            }
+            mCount += count;
+        }
+        PRIntervalTime end = PR_IntervalNow();
+        printf("read  %d bytes, time = %dms\n", mCount,
+               PR_IntervalToMilliseconds(end - start));
+        return rv;
+    }
+
+    explicit nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) {
+    }
+
+    uint32_t GetBytesRead() { return mCount; }
+
+private:
+    ~nsReceiver() {}
+
+protected:
+    nsCOMPtr<nsIInputStream> mIn;
+    uint32_t            mCount;
+};
+
+NS_IMPL_ISUPPORTS(nsReceiver, nsIRunnable)
+
+nsresult
+TestPipe(nsIInputStream* in, nsIOutputStream* out)
+{
+    nsRefPtr<nsReceiver> receiver = new nsReceiver(in);
+    if (!receiver)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    nsresult rv;
+
+    nsCOMPtr<nsIThread> thread;
+    rv = NS_NewThread(getter_AddRefs(thread), receiver);
+    if (NS_FAILED(rv)) return rv;
+
+    uint32_t total = 0;
+    PRIntervalTime start = PR_IntervalNow();
+    for (uint32_t i = 0; i < ITERATIONS; i++) {
+        uint32_t writeCount;
+        char *buf = PR_smprintf("%d %s", i, kTestPattern);
+        uint32_t len = strlen(buf);
+        rv = WriteAll(out, buf, len, &writeCount);
+        if (gTrace) {
+            printf("wrote: ");
+            for (uint32_t j = 0; j < writeCount; j++) {
+                putc(buf[j], stdout);
+            }
+            printf("\n");
+        }
+        PR_smprintf_free(buf);
+        if (NS_FAILED(rv)) return rv;
+        total += writeCount;
+    }
+    rv = out->Close();
+    if (NS_FAILED(rv)) return rv;
+
+    PRIntervalTime end = PR_IntervalNow();
+
+    thread->Shutdown();
+
+    printf("wrote %d bytes, time = %dms\n", total,
+           PR_IntervalToMilliseconds(end - start));
+    EXPECT_EQ(receiver->GetBytesRead(), total);
+
+    return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class nsShortReader MOZ_FINAL : public nsIRunnable {
+public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+
+    NS_IMETHOD Run() MOZ_OVERRIDE {
+        nsresult rv;
+        char buf[101];
+        uint32_t count;
+        uint32_t total = 0;
+        while (true) {
+            //if (gTrace)
+            //    printf("calling Read\n");
+            rv = mIn->Read(buf, 100, &count);
+            if (NS_FAILED(rv)) {
+                printf("read failed\n");
+                break;
+            }
+            if (count == 0) {
+                break;
+            }
+
+            if (gTrace) {
+                // For next |printf()| call and possible others elsewhere.
+                buf[count] = '\0';
+
+                printf("read %d bytes: %s\n", count, buf);
+            }
+
+            Received(count);
+            total += count;
+        }
+        printf("read  %d bytes\n", total);
+        return rv;
+    }
+
+    explicit nsShortReader(nsIInputStream* in) : mIn(in), mReceived(0) {
+        mMon = new ReentrantMonitor("nsShortReader");
+    }
+
+    void Received(uint32_t count) {
+        ReentrantMonitorAutoEnter mon(*mMon);
+        mReceived += count;
+        mon.Notify();
+    }
+
+    uint32_t WaitForReceipt(const uint32_t aWriteCount) {
+        ReentrantMonitorAutoEnter mon(*mMon);
+        uint32_t result = mReceived;
+
+        while (result < aWriteCount) {
+            mon.Wait();
+
+            EXPECT_TRUE(mReceived > result);
+            result = mReceived;
+        }
+
+        mReceived = 0;
+        return result;
+    }
+
+private:
+    ~nsShortReader() {}
+
+protected:
+    nsCOMPtr<nsIInputStream> mIn;
+    uint32_t                 mReceived;
+    ReentrantMonitor*        mMon;
+};
+
+NS_IMPL_ISUPPORTS(nsShortReader, nsIRunnable)
+
+nsresult
+TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
+{
+    nsRefPtr<nsShortReader> receiver = new nsShortReader(in);
+    if (!receiver)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    nsresult rv;
+
+    nsCOMPtr<nsIThread> thread;
+    rv = NS_NewThread(getter_AddRefs(thread), receiver);
+    if (NS_FAILED(rv)) return rv;
+
+    uint32_t total = 0;
+    for (uint32_t i = 0; i < ITERATIONS; i++) {
+        uint32_t writeCount;
+        char* buf = PR_smprintf("%d %s", i, kTestPattern);
+        uint32_t len = strlen(buf);
+        len = len * rand() / RAND_MAX;
+        len = std::min(1u, len);
+        rv = WriteAll(out, buf, len, &writeCount);
+        if (NS_FAILED(rv)) return rv;
+        EXPECT_EQ(writeCount, len);
+        total += writeCount;
+
+        if (gTrace)
+            printf("wrote %d bytes: %s\n", writeCount, buf);
+        PR_smprintf_free(buf);
+        //printf("calling Flush\n");
+        out->Flush();
+        //printf("calling WaitForReceipt\n");
+
+#ifdef DEBUG
+        const uint32_t received =
+          receiver->WaitForReceipt(writeCount);
+        EXPECT_EQ(received, writeCount);
+#endif
+    }
+    rv = out->Close();
+    if (NS_FAILED(rv)) return rv;
+
+    thread->Shutdown();
+
+    printf("wrote %d bytes\n", total);
+
+    return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class nsPump MOZ_FINAL : public nsIRunnable
+{
+public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+
+    NS_IMETHOD Run() MOZ_OVERRIDE {
+        nsresult rv;
+        uint32_t count;
+        while (true) {
+            rv = mOut->WriteFrom(mIn, ~0U, &count);
+            if (NS_FAILED(rv)) {
+                printf("Write failed\n");
+                break;
+            }
+            if (count == 0) {
+                printf("EOF count = %d\n", mCount);
+                break;
+            }
+
+            if (gTrace) {
+                printf("Wrote: %d\n", count);
+            }
+            mCount += count;
+        }
+        mOut->Close();
+        return rv;
+    }
+
+    nsPump(nsIInputStream* in,
+           nsIOutputStream* out)
+        : mIn(in), mOut(out), mCount(0) {
+    }
+
+private:
+    ~nsPump() {}
+
+protected:
+    nsCOMPtr<nsIInputStream>      mIn;
+    nsCOMPtr<nsIOutputStream>     mOut;
+    uint32_t                            mCount;
+};
+
+NS_IMPL_ISUPPORTS(nsPump, nsIRunnable)
+
+TEST(Pipes, ChainedPipes)
+{
+    nsresult rv;
+    if (gTrace) {
+        printf("TestChainedPipes\n");
+    }
+
+    nsCOMPtr<nsIInputStream> in1;
+    nsCOMPtr<nsIOutputStream> out1;
+    rv = NS_NewPipe(getter_AddRefs(in1), getter_AddRefs(out1), 20, 1999);
+    if (NS_FAILED(rv)) return;
+
+    nsCOMPtr<nsIInputStream> in2;
+    nsCOMPtr<nsIOutputStream> out2;
+    rv = NS_NewPipe(getter_AddRefs(in2), getter_AddRefs(out2), 200, 401);
+    if (NS_FAILED(rv)) return;
+
+    nsRefPtr<nsPump> pump = new nsPump(in1, out2);
+    if (pump == nullptr) return;
+
+    nsCOMPtr<nsIThread> thread;
+    rv = NS_NewThread(getter_AddRefs(thread), pump);
+    if (NS_FAILED(rv)) return;
+
+    nsRefPtr<nsReceiver> receiver = new nsReceiver(in2);
+    if (receiver == nullptr) return;
+
+    nsCOMPtr<nsIThread> receiverThread;
+    rv = NS_NewThread(getter_AddRefs(receiverThread), receiver);
+    if (NS_FAILED(rv)) return;
+
+    uint32_t total = 0;
+    for (uint32_t i = 0; i < ITERATIONS; i++) {
+        uint32_t writeCount;
+        char* buf = PR_smprintf("%d %s", i, kTestPattern);
+        uint32_t len = strlen(buf);
+        len = len * rand() / RAND_MAX;
+        len = std::max(1u, len);
+        rv = WriteAll(out1, buf, len, &writeCount);
+        if (NS_FAILED(rv)) return;
+        EXPECT_EQ(writeCount, len);
+        total += writeCount;
+
+        if (gTrace)
+            printf("wrote %d bytes: %s\n", writeCount, buf);
+
+        PR_smprintf_free(buf);
+    }
+    if (gTrace) {
+        printf("wrote total of %d bytes\n", total);
+    }
+    rv = out1->Close();
+    if (NS_FAILED(rv)) return;
+
+    thread->Shutdown();
+    receiverThread->Shutdown();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void
+RunTests(uint32_t segSize, uint32_t segCount)
+{
+    nsresult rv;
+    nsCOMPtr<nsIInputStream> in;
+    nsCOMPtr<nsIOutputStream> out;
+    uint32_t bufSize = segSize * segCount;
+    if (gTrace) {
+        printf("Testing New Pipes: segment size %d buffer size %d\n", segSize, bufSize);
+        printf("Testing long writes...\n");
+    }
+    rv = NS_NewPipe(getter_AddRefs(in), getter_AddRefs(out), segSize, bufSize);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+    rv = TestPipe(in, out);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+    if (gTrace) {
+        printf("Testing short writes...\n");
+    }
+    rv = NS_NewPipe(getter_AddRefs(in), getter_AddRefs(out), segSize, bufSize);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+    rv = TestShortWrites(in, out);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+}
+
+TEST(Pipes, Main)
+{
+    RunTests(16, 1);
+    RunTests(4096, 16);
+}
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/gtest/TestPriorityQueue.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsTPriorityQueue.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "gtest/gtest.h"
+
+template<class T, class Compare>
+void
+CheckPopSequence(const nsTPriorityQueue<T, Compare>& aQueue,
+                 const T* aExpectedSequence, const uint32_t aSequenceLength)
+{
+  nsTPriorityQueue<T, Compare> copy(aQueue);
+
+  for (uint32_t i = 0; i < aSequenceLength; i++) {
+    EXPECT_FALSE(copy.IsEmpty());
+
+    T pop = copy.Pop();
+    EXPECT_EQ(pop, aExpectedSequence[i]);
+  }
+
+  EXPECT_TRUE(copy.IsEmpty());
+}
+
+template<class A>
+class MaxCompare {
+public:
+  bool LessThan(const A& a, const A& b) {
+    return a > b;
+  }
+};
+
+TEST(PriorityQueue, Main)
+{
+  nsTPriorityQueue<int> queue;
+
+  EXPECT_TRUE(queue.IsEmpty());
+
+  queue.Push(8);
+  queue.Push(6);
+  queue.Push(4);
+  queue.Push(2);
+  queue.Push(10);
+  queue.Push(6);
+  EXPECT_EQ(queue.Top(), 2);
+  EXPECT_EQ(queue.Length(), 6u);
+  EXPECT_FALSE(queue.IsEmpty());
+  int expected[] = { 2, 4, 6, 6, 8, 10 };
+  CheckPopSequence(queue, expected, sizeof(expected) / sizeof(expected[0]));
+
+  // copy ctor is tested by using CheckPopSequence, but check default assignment
+  // operator
+  nsTPriorityQueue<int> queue2;
+  queue2 = queue;
+  CheckPopSequence(queue2, expected, sizeof(expected) / sizeof(expected[0]));
+
+  queue.Clear();
+  EXPECT_TRUE(queue.IsEmpty());
+
+  // try same sequence with a max heap
+  nsTPriorityQueue<int, MaxCompare<int> > max_queue;
+  max_queue.Push(8);
+  max_queue.Push(6);
+  max_queue.Push(4);
+  max_queue.Push(2);
+  max_queue.Push(10);
+  max_queue.Push(6);
+  EXPECT_EQ(max_queue.Top(), 10);
+  int expected_max[] = { 10, 8, 6, 6, 4, 2 };
+  CheckPopSequence(max_queue, expected_max,
+      sizeof(expected_max) / sizeof(expected_max[0]));
+}
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/gtest/TestStorageStream.cpp
@@ -0,0 +1,92 @@
+/* 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 <stdlib.h>
+#include "nsIStorageStream.h"
+#include "nsIInputStream.h"
+#include "nsIOutputStream.h"
+#include "nsCOMPtr.h"
+#include "gtest/gtest.h"
+
+TEST(TestStorageStreams, Main)
+{
+  char kData[4096];
+  memset(kData, 0, sizeof(kData));
+
+  nsresult rv;
+  nsCOMPtr<nsIStorageStream> stor;
+
+  rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(stor));
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  nsCOMPtr<nsIOutputStream> out;
+  rv = stor->GetOutputStream(0, getter_AddRefs(out));
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  uint32_t n;
+
+  rv = out->Write(kData, sizeof(kData), &n);
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  rv = out->Write(kData, sizeof(kData), &n);
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  rv = out->Close();
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  out = nullptr;
+
+  nsCOMPtr<nsIInputStream> in;
+  rv = stor->NewInputStream(0, getter_AddRefs(in));
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  char buf[4096];
+
+  // consume contents of input stream
+  do {
+    rv = in->Read(buf, sizeof(buf), &n);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+  } while (n != 0);
+
+  rv = in->Close();
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+  in = nullptr;
+
+  // now, write 3 more full 4k segments + 11 bytes, starting at 8192
+  // total written equals 20491 bytes
+
+  rv = stor->GetOutputStream(8192, getter_AddRefs(out));
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  rv = out->Write(kData, sizeof(kData), &n);
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  rv = out->Write(kData, sizeof(kData), &n);
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  rv = out->Write(kData, sizeof(kData), &n);
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  rv = out->Write(kData, 11, &n);
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  rv = out->Close();
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  out = nullptr;
+
+  // now, read all
+  rv = stor->NewInputStream(0, getter_AddRefs(in));
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+
+  // consume contents of input stream
+  do {
+    rv = in->Read(buf, sizeof(buf), &n);
+    EXPECT_TRUE(NS_SUCCEEDED(rv));
+  } while (n != 0);
+
+  rv = in->Close();
+  EXPECT_TRUE(NS_SUCCEEDED(rv));
+  in = nullptr;
+}
--- a/xpcom/tests/gtest/moz.build
+++ b/xpcom/tests/gtest/moz.build
@@ -3,15 +3,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/.
 
 UNIFIED_SOURCES += [
     'TestCRT.cpp',
     'TestEncoding.cpp',
     'TestExpirationTracker.cpp',
+    'TestPipes.cpp',
+    'TestPriorityQueue.cpp',
     'TestSnappyStreams.cpp',
+    'TestStorageStream.cpp',
     'TestStrings.cpp',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
 
 FAIL_ON_WARNINGS = True
--- a/xpcom/tests/moz.build
+++ b/xpcom/tests/moz.build
@@ -75,19 +75,16 @@ GeckoCppUnitTests([
 
 if CONFIG['MOZ_MEMORY']:
     GeckoCppUnitTests([
         'TestJemalloc',
     ])
 
 # XXX Make these tests work in libxul builds.
 #CPP_UNIT_TESTS += [
-#    'TestPipes',
-#    'TestPriorityQueue',
-#    'TestStorageStream',
 #    'TestSynchronization',
 #    'TestTArray',
 #    'TestThreadPool',
 #    'TestThreads',
 #    'TestTimeStamp',
 #    'TestXPIDLString',
 #    'TestUTF',
 #    'TestAtoms',