Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 07 Oct 2014 15:05:29 +0200
changeset 232336 32122cb5118daeacb1fb58d3775a5f8783962983
parent 232335 4af29b25a7bff2e9b52ec704c47836855aad265c (current diff)
parent 232322 25a98bac926420e5fcca88d79b400c1b1c10faa5 (diff)
child 232337 22f1131e66e39df39eba618a8a78c854df2f5c36
child 232414 4fa74ef900c52830e0990d20aa4a91b0b8043353
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "1e5360b21cca807b2ea63ea8fb878b451131c9bd", 
+    "revision": "25a5d3c030a5ece82a1114882575560b58fe185f", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- 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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="83de447d9ae9a59459d7a445f9348a254c661850"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9306e431d5b559035d9656902e413816b6ca3c26"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9eec93462df6d01fe33a737bb4a185e9ad6cee15"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f9bc14c28aed7b2571e641bfeeca81876ec48ec"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -304,41 +304,51 @@ def processSingleLeakFile(leakLogFileNam
 
   if logAsWarning:
     log.warning("%s | leakcheck | %s %d bytes leaked (%s)"
                 % (prefix, processString, totalBytesLeaked, leakedObjectSummary))
   else:
     log.info("%s | leakcheck | %s %d bytes leaked (%s)"
              % (prefix, processString, totalBytesLeaked, leakedObjectSummary))
 
-def processLeakLog(leakLogFile, leakThresholds, ignoreMissingLeaks):
+def processLeakLog(leakLogFile, options):
   """Process the leak log, including separate leak logs created
   by child processes.
 
   Use this function if you want an additional PASS/FAIL summary.
   It must be used with the |XPCOM_MEM_BLOAT_LOG| environment variable.
 
   The base of leakLogFile for a non-default process needs to end with
     _proctype_pid12345.log
   "proctype" is a string denoting the type of the process, which should
   be the result of calling XRE_ChildProcessTypeToString(). 12345 is
   a series of digits that is the pid for the process. The .log is
   optional.
 
   All other file names are treated as being for default processes.
 
+  The options argument is checked for two optional attributes,
+  leakThresholds and ignoreMissingLeaks.
+
   leakThresholds should be a dict mapping process types to leak thresholds,
   in bytes. If a process type is not present in the dict the threshold
   will be 0.
+
+  ignoreMissingLeaks should be a list of process types. If a process
+  creates a leak log without a TOTAL, then we report an error if it isn't
+  in the list ignoreMissingLeaks.
   """
 
   if not os.path.exists(leakLogFile):
     log.info("WARNING | leakcheck | refcount logging is off, so leaks can't be detected!")
     return
 
+  leakThresholds = getattr(options, 'leakThresholds', {})
+  ignoreMissingLeaks = getattr(options, 'ignoreMissingLeaks', [])
+
   # This list is based on kGeckoProcessTypeString. ipdlunittest processes likely
   # are not going to produce leak logs we will ever see.
   knownProcessTypes = ["default", "plugin", "tab", "geckomediaplugin"]
 
   for processType in knownProcessTypes:
     log.info("TEST-INFO | leakcheck | %s process: leak threshold set at %d bytes"
              % (processType, leakThresholds.get(processType, 0)))
 
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -1723,17 +1723,17 @@ public:
     if (!cc) {
       return true;
     }
     ClonedMessageData data;
     if (!BuildClonedMessageDataForChild(cc, aData, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
-    if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+    if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
     if (aIsSync) {
       return cc->SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                                  IPC::Principal(aPrincipal), aJSONRetVal);
     }
     return cc->CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
                               IPC::Principal(aPrincipal), aJSONRetVal);
@@ -1750,17 +1750,17 @@ public:
     if (!cc) {
       return true;
     }
     ClonedMessageData data;
     if (!BuildClonedMessageDataForChild(cc, aData, data)) {
       return false;
     }
     InfallibleTArray<mozilla::jsipc::CpowEntry> cpows;
-    if (!cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+    if (aCpows && !cc->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
       return false;
     }
     return cc->SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
                                 IPC::Principal(aPrincipal));
   }
 
 };
 
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -55,8 +55,10 @@ MSG_DEF(MSG_INVALID_URL, 1, "{0} is not 
 MSG_DEF(MSG_METADATA_NOT_CONFIGURED, 0, "Either size or lastModified should be true.")
 MSG_DEF(MSG_INVALID_READ_SIZE, 0, "0 (Zero) is not a valid read size.")
 MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, "Headers are immutable and cannot be modified.")
 MSG_DEF(MSG_INVALID_HEADER_NAME, 1, "{0} is an invalid header name.")
 MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, "{0} is an invalid header value.")
 MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, "Headers require name/value tuples when being initialized by a sequence.")
 MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, "Permission denied to pass cross-origin object as {0}.")
 MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, "Missing required {0}.")
+MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, "Invalid request method {0}.")
+MSG_DEF(MSG_REQUEST_BODY_CONSUMED_ERROR, 0, "Request body has already been consumed.")
new file mode 100644
--- /dev/null
+++ b/dom/fetch/Fetch.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Fetch.h"
+
+#include "nsIStringStream.h"
+#include "nsIUnicodeEncoder.h"
+
+#include "nsStringStream.h"
+
+#include "mozilla/dom/EncodingUtils.h"
+#include "mozilla/dom/URLSearchParams.h"
+
+namespace mozilla {
+namespace dom {
+
+nsresult
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
+                          nsIInputStream** aStream,
+                          nsCString& aContentType)
+{
+  MOZ_ASSERT(aStream);
+
+  nsresult rv;
+  nsCOMPtr<nsIInputStream> byteStream;
+  if (aBodyInit.IsArrayBuffer()) {
+    const ArrayBuffer& buf = aBodyInit.GetAsArrayBuffer();
+    buf.ComputeLengthAndData();
+    //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
+    rv = NS_NewByteInputStream(getter_AddRefs(byteStream),
+                               reinterpret_cast<char*>(buf.Data()),
+                               buf.Length(), NS_ASSIGNMENT_COPY);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  } else if (aBodyInit.IsArrayBufferView()) {
+    const ArrayBufferView& buf = aBodyInit.GetAsArrayBufferView();
+    buf.ComputeLengthAndData();
+    //XXXnsm reinterpret_cast<> is used in DOMParser, should be ok.
+    rv = NS_NewByteInputStream(getter_AddRefs(byteStream),
+                               reinterpret_cast<char*>(buf.Data()),
+                               buf.Length(), NS_ASSIGNMENT_COPY);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  } else if (aBodyInit.IsScalarValueString()) {
+    nsString str = aBodyInit.GetAsScalarValueString();
+
+    nsCOMPtr<nsIUnicodeEncoder> encoder = EncodingUtils::EncoderForEncoding("UTF-8");
+    if (!encoder) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    int32_t destBufferLen;
+    rv = encoder->GetMaxLength(str.get(), str.Length(), &destBufferLen);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    nsCString encoded;
+    if (!encoded.SetCapacity(destBufferLen, fallible_t())) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    char* destBuffer = encoded.BeginWriting();
+    int32_t srcLen = (int32_t) str.Length();
+    int32_t outLen = destBufferLen;
+    rv = encoder->Convert(str.get(), &srcLen, destBuffer, &outLen);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    MOZ_ASSERT(outLen <= destBufferLen);
+    encoded.SetLength(outLen);
+    rv = NS_NewCStringInputStream(getter_AddRefs(byteStream), encoded);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    aContentType = NS_LITERAL_CSTRING("text/plain;charset=UTF-8");
+  } else if (aBodyInit.IsURLSearchParams()) {
+    URLSearchParams& params = aBodyInit.GetAsURLSearchParams();
+    nsString serialized;
+    params.Stringify(serialized);
+    rv = NS_NewStringInputStream(getter_AddRefs(byteStream), serialized);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    aContentType = NS_LITERAL_CSTRING("application/x-www-form-urlencoded;charset=UTF-8");
+  }
+
+  MOZ_ASSERT(byteStream);
+  byteStream.forget(aStream);
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/fetch/Fetch.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_Fetch_h
+#define mozilla_dom_Fetch_h
+
+#include "mozilla/dom/UnionTypes.h"
+
+class nsIInputStream;
+
+namespace mozilla {
+namespace dom {
+
+/*
+ * Creates an nsIInputStream based on the fetch specifications 'extract a byte
+ * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
+ * Stores content type in out param aContentType.
+ */
+nsresult
+ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& aBodyInit,
+                          nsIInputStream** aStream,
+                          nsCString& aContentType);
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_Fetch_h
--- a/dom/fetch/Headers.cpp
+++ b/dom/fetch/Headers.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Headers.h"
 
 #include "mozilla/ErrorResult.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/Preferences.h"
 
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsDOMString.h"
 #include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
@@ -78,16 +77,49 @@ Headers::Constructor(const GlobalObject&
 
   if (aRv.Failed()) {
     return nullptr;
   }
 
   return headers.forget();
 }
 
+// static
+already_AddRefed<Headers>
+Headers::Constructor(const GlobalObject& aGlobal,
+                     const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
+                     ErrorResult& aRv)
+{
+  nsRefPtr<Headers> headers = new Headers(aGlobal.GetAsSupports());
+
+  if (aInit.IsHeaders()) {
+    headers->Fill(aInit.GetAsHeaders(), aRv);
+  } else if (aInit.IsByteStringSequenceSequence()) {
+    headers->Fill(aInit.GetAsByteStringSequenceSequence(), aRv);
+  } else if (aInit.IsByteStringMozMap()) {
+    headers->Fill(aInit.GetAsByteStringMozMap(), aRv);
+  }
+
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  return headers.forget();
+}
+
+Headers::Headers(const Headers& aOther)
+  : mOwner(aOther.mOwner)
+  , mGuard(aOther.mGuard)
+{
+  SetIsDOMBinding();
+  ErrorResult result;
+  Fill(aOther, result);
+  MOZ_ASSERT(!result.Failed());
+}
+
 void
 Headers::Append(const nsACString& aName, const nsACString& aValue,
                 ErrorResult& aRv)
 {
   nsAutoCString lowerName;
   ToLowerCase(aName, lowerName);
 
   if (IsInvalidMutableHeader(lowerName, &aValue, aRv)) {
@@ -198,16 +230,22 @@ Headers::Set(const nsACString& aName, co
     entry->mName = lowerName;
     entry->mValue = aValue;
   } else {
     mList.AppendElement(Entry(lowerName, aValue));
   }
 }
 
 void
+Headers::Clear()
+{
+  mList.Clear();
+}
+
+void
 Headers::SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv)
 {
   // Rather than re-validate all current headers, just require code to set
   // this prior to populating the Headers object.  Allow setting immutable
   // late, though, as that is pretty much required to have a  useful, immutable
   // headers object.
   if (aGuard != HeadersGuardEnum::Immutable && mList.Length() > 0) {
     aRv.Throw(NS_ERROR_FAILURE);
@@ -323,11 +361,10 @@ void
 Headers::Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv)
 {
   nsTArray<nsString> keys;
   aInit.GetKeys(keys);
   for (uint32_t i = 0; i < keys.Length() && !aRv.Failed(); ++i) {
     Append(NS_ConvertUTF16toUTF8(keys[i]), aInit.Get(keys[i]), aRv);
   }
 }
-
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/Headers.h
+++ b/dom/fetch/Headers.h
@@ -3,16 +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/. */
 
 #ifndef mozilla_dom_Headers_h
 #define mozilla_dom_Headers_h
 
 #include "mozilla/dom/HeadersBinding.h"
+#include "mozilla/dom/UnionTypes.h"
+
 #include "nsClassHashtable.h"
 #include "nsWrapperCache.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
@@ -37,53 +39,67 @@ private:
     { }
 
     Entry() { }
 
     nsCString mName;
     nsCString mValue;
   };
 
-  nsRefPtr<nsISupports> mOwner;
+  nsCOMPtr<nsISupports> mOwner;
   HeadersGuardEnum mGuard;
   nsTArray<Entry> mList;
 
 public:
   explicit Headers(nsISupports* aOwner, HeadersGuardEnum aGuard = HeadersGuardEnum::None)
     : mOwner(aOwner)
     , mGuard(aGuard)
   {
     SetIsDOMBinding();
   }
 
+  explicit Headers(const Headers& aOther);
+
   static bool PrefEnabled(JSContext* cx, JSObject* obj);
 
   static already_AddRefed<Headers>
   Constructor(const GlobalObject& aGlobal,
               const Optional<HeadersOrByteStringSequenceSequenceOrByteStringMozMap>& aInit,
               ErrorResult& aRv);
 
+  static already_AddRefed<Headers>
+  Constructor(const GlobalObject& aGlobal,
+              const OwningHeadersOrByteStringSequenceSequenceOrByteStringMozMap& aInit,
+              ErrorResult& aRv);
+
   void Append(const nsACString& aName, const nsACString& aValue,
               ErrorResult& aRv);
   void Delete(const nsACString& aName, ErrorResult& aRv);
   void Get(const nsACString& aName, nsCString& aValue, ErrorResult& aRv) const;
   void GetAll(const nsACString& aName, nsTArray<nsCString>& aResults,
               ErrorResult& aRv) const;
   bool Has(const nsACString& aName, ErrorResult& aRv) const;
   void Set(const nsACString& aName, const nsACString& aValue, ErrorResult& aRv);
 
+  void Clear();
+
   // ChromeOnly
   HeadersGuardEnum Guard() const { return mGuard; }
   void SetGuard(HeadersGuardEnum aGuard, ErrorResult& aRv);
 
   virtual JSObject* WrapObject(JSContext* aCx);
   nsISupports* GetParentObject() const { return mOwner; }
 
+  void Fill(const Headers& aInit, ErrorResult& aRv);
 private:
-  Headers(const Headers& aOther) MOZ_DELETE;
+  // Since Headers is also an nsISupports, the above constructor can
+  // accidentally be invoked as new Headers(Headers*[, implied None guard]) when
+  // the intention is to use the copy constructor. Explicitly disallow it.
+  Headers(Headers* aOther) MOZ_DELETE;
+
   virtual ~Headers();
 
   static bool IsSimpleHeader(const nsACString& aName,
                              const nsACString* aValue = nullptr);
   static bool IsInvalidName(const nsACString& aName, ErrorResult& aRv);
   static bool IsInvalidValue(const nsACString& aValue, ErrorResult& aRv);
   bool IsImmutable(ErrorResult& aRv) const;
   bool IsForbiddenRequestHeader(const nsACString& aName) const;
@@ -98,17 +114,16 @@ private:
     return IsInvalidName(aName, aRv) ||
            (aValue && IsInvalidValue(*aValue, aRv)) ||
            IsImmutable(aRv) ||
            IsForbiddenRequestHeader(aName) ||
            IsForbiddenRequestNoCorsHeader(aName, aValue) ||
            IsForbiddenResponseHeader(aName);
   }
 
-  void Fill(const Headers& aInit, ErrorResult& aRv);
   void Fill(const Sequence<Sequence<nsCString>>& aInit, ErrorResult& aRv);
   void Fill(const MozMap<nsCString>& aInit, ErrorResult& aRv);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Headers_h
new file mode 100644
--- /dev/null
+++ b/dom/fetch/InternalRequest.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InternalRequest.h"
+
+#include "nsIContentPolicy.h"
+#include "nsIDocument.h"
+
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/workers/Workers.h"
+
+#include "WorkerPrivate.h"
+
+namespace mozilla {
+namespace dom {
+
+// The global is used to extract the principal.
+already_AddRefed<InternalRequest>
+InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const
+{
+  nsRefPtr<InternalRequest> copy = new InternalRequest();
+  copy->mURL.Assign(mURL);
+  copy->SetMethod(mMethod);
+  copy->mHeaders = new Headers(*mHeaders);
+
+  copy->mBodyStream = mBodyStream;
+  copy->mPreserveContentCodings = true;
+
+  if (NS_IsMainThread()) {
+    nsIPrincipal* principal = aGlobal->PrincipalOrNull();
+    MOZ_ASSERT(principal);
+    aRv = nsContentUtils::GetASCIIOrigin(principal, copy->mOrigin);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
+  } else {
+    workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
+    MOZ_ASSERT(worker);
+    worker->AssertIsOnWorkerThread();
+
+    workers::WorkerPrivate::LocationInfo& location = worker->GetLocationInfo();
+    copy->mOrigin = NS_ConvertUTF16toUTF8(location.mOrigin);
+  }
+
+  copy->mMode = mMode;
+  copy->mCredentialsMode = mCredentialsMode;
+  // FIXME(nsm): Add ContentType fetch to nsIContentPolicy and friends.
+  // Then set copy's mContext to that.
+  return copy.forget();
+}
+
+InternalRequest::~InternalRequest()
+{
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/fetch/InternalRequest.h
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_InternalRequest_h
+#define mozilla_dom_InternalRequest_h
+
+#include "mozilla/dom/Headers.h"
+#include "mozilla/dom/RequestBinding.h"
+#include "mozilla/dom/UnionTypes.h"
+
+#include "nsIContentPolicy.h"
+#include "nsIInputStream.h"
+#include "nsISupportsImpl.h"
+
+class nsIDocument;
+class nsPIDOMWindow;
+
+namespace mozilla {
+namespace dom {
+
+class FetchBodyStream;
+class Request;
+
+class InternalRequest MOZ_FINAL
+{
+  friend class Request;
+
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalRequest)
+
+  enum ContextFrameType
+  {
+    FRAMETYPE_AUXILIARY = 0,
+    FRAMETYPE_TOP_LEVEL,
+    FRAMETYPE_NESTED,
+    FRAMETYPE_NONE,
+  };
+
+  // Since referrer type can be none, client or a URL.
+  enum ReferrerType
+  {
+    REFERRER_NONE = 0,
+    REFERRER_CLIENT,
+    REFERRER_URL,
+  };
+
+  enum ResponseTainting
+  {
+    RESPONSETAINT_BASIC,
+    RESPONSETAINT_CORS,
+    RESPONSETAINT_OPAQUE,
+  };
+
+  explicit InternalRequest()
+    : mMethod("GET")
+    , mHeaders(new Headers(nullptr, HeadersGuardEnum::None))
+    , mContextFrameType(FRAMETYPE_NONE)
+    , mReferrerType(REFERRER_CLIENT)
+    , mMode(RequestMode::No_cors)
+    , mCredentialsMode(RequestCredentials::Omit)
+    , mResponseTainting(RESPONSETAINT_BASIC)
+    , mRedirectCount(0)
+    , mAuthenticationFlag(false)
+    , mForceOriginHeader(false)
+    , mManualRedirect(false)
+    , mPreserveContentCodings(false)
+    , mSameOriginDataURL(false)
+    , mSkipServiceWorker(false)
+    , mSynchronous(false)
+    , mUnsafeRequest(false)
+    , mUseURLCredentials(false)
+  {
+  }
+
+  explicit InternalRequest(const InternalRequest& aOther)
+    : mMethod(aOther.mMethod)
+    , mURL(aOther.mURL)
+    , mHeaders(aOther.mHeaders)
+    , mBodyStream(aOther.mBodyStream)
+    , mContext(aOther.mContext)
+    , mOrigin(aOther.mOrigin)
+    , mContextFrameType(aOther.mContextFrameType)
+    , mReferrerType(aOther.mReferrerType)
+    , mReferrerURL(aOther.mReferrerURL)
+    , mMode(aOther.mMode)
+    , mCredentialsMode(aOther.mCredentialsMode)
+    , mResponseTainting(aOther.mResponseTainting)
+    , mRedirectCount(aOther.mRedirectCount)
+    , mAuthenticationFlag(aOther.mAuthenticationFlag)
+    , mForceOriginHeader(aOther.mForceOriginHeader)
+    , mManualRedirect(aOther.mManualRedirect)
+    , mPreserveContentCodings(aOther.mPreserveContentCodings)
+    , mSameOriginDataURL(aOther.mSameOriginDataURL)
+    , mSandboxedStorageAreaURLs(aOther.mSandboxedStorageAreaURLs)
+    , mSkipServiceWorker(aOther.mSkipServiceWorker)
+    , mSynchronous(aOther.mSynchronous)
+    , mUnsafeRequest(aOther.mUnsafeRequest)
+    , mUseURLCredentials(aOther.mUseURLCredentials)
+  {
+  }
+
+  void
+  GetMethod(nsCString& aMethod) const
+  {
+    aMethod.Assign(mMethod);
+  }
+
+  void
+  SetMethod(const nsACString& aMethod)
+  {
+    mMethod.Assign(aMethod);
+  }
+
+  void
+  GetURL(nsCString& aURL) const
+  {
+    aURL.Assign(mURL);
+  }
+
+  bool
+  ReferrerIsNone() const
+  {
+    return mReferrerType == REFERRER_NONE;
+  }
+
+  bool
+  ReferrerIsURL() const
+  {
+    return mReferrerType == REFERRER_URL;
+  }
+
+  bool
+  ReferrerIsClient() const
+  {
+    return mReferrerType == REFERRER_CLIENT;
+  }
+
+  nsCString
+  ReferrerAsURL() const
+  {
+    MOZ_ASSERT(ReferrerIsURL());
+    return mReferrerURL;
+  }
+
+  void
+  SetReferrer(const nsACString& aReferrer)
+  {
+    // May be removed later.
+    MOZ_ASSERT(!ReferrerIsNone());
+    mReferrerType = REFERRER_URL;
+    mReferrerURL.Assign(aReferrer);
+  }
+
+  bool
+  IsSynchronous() const
+  {
+    return mSynchronous;
+  }
+
+  void
+  SetMode(RequestMode aMode)
+  {
+    mMode = aMode;
+  }
+
+  void
+  SetCredentialsMode(RequestCredentials aCredentialsMode)
+  {
+    mCredentialsMode = aCredentialsMode;
+  }
+
+  nsContentPolicyType
+  GetContext() const
+  {
+    return mContext;
+  }
+
+  Headers*
+  Headers_()
+  {
+    return mHeaders;
+  }
+
+  bool
+  ForceOriginHeader()
+  {
+    return mForceOriginHeader;
+  }
+
+  void
+  GetOrigin(nsCString& aOrigin) const
+  {
+    aOrigin.Assign(mOrigin);
+  }
+
+  void
+  SetBody(nsIInputStream* aStream)
+  {
+    mBodyStream = aStream;
+  }
+
+  // Will return the original stream!
+  // Use a tee or copy if you don't want to erase the original.
+  void
+  GetBody(nsIInputStream** aStream)
+  {
+    nsCOMPtr<nsIInputStream> s = mBodyStream;
+    s.forget(aStream);
+  }
+
+  // The global is used as the client for the new object.
+  already_AddRefed<InternalRequest>
+  GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
+
+private:
+  ~InternalRequest();
+
+  void
+  SetURL(const nsACString& aURL)
+  {
+    mURL.Assign(aURL);
+  }
+
+  nsCString mMethod;
+  nsCString mURL;
+  nsRefPtr<Headers> mHeaders;
+  nsCOMPtr<nsIInputStream> mBodyStream;
+
+  // nsContentPolicyType does not cover the complete set defined in the spec,
+  // but it is a good start.
+  nsContentPolicyType mContext;
+
+  nsCString mOrigin;
+
+  ContextFrameType mContextFrameType;
+  ReferrerType mReferrerType;
+
+  // When mReferrerType is REFERRER_URL.
+  nsCString mReferrerURL;
+
+  RequestMode mMode;
+  RequestCredentials mCredentialsMode;
+  ResponseTainting mResponseTainting;
+
+  uint32_t mRedirectCount;
+
+  bool mAuthenticationFlag;
+  bool mForceOriginHeader;
+  bool mManualRedirect;
+  bool mPreserveContentCodings;
+  bool mSameOriginDataURL;
+  bool mSandboxedStorageAreaURLs;
+  bool mSkipServiceWorker;
+  bool mSynchronous;
+  bool mUnsafeRequest;
+  bool mUseURLCredentials;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_InternalRequest_h
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -1,118 +1,443 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Request.h"
 
+#include "nsIUnicodeDecoder.h"
+#include "nsIURI.h"
+
+#include "nsDOMFile.h"
 #include "nsDOMString.h"
-#include "nsISupportsImpl.h"
-#include "nsIURI.h"
+#include "nsNetUtil.h"
 #include "nsPIDOMWindow.h"
+#include "nsStreamUtils.h"
+#include "nsStringStream.h"
 
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/Headers.h"
+#include "mozilla/dom/Fetch.h"
 #include "mozilla/dom/Promise.h"
+#include "mozilla/dom/URL.h"
+#include "mozilla/dom/workers/bindings/URL.h"
+
+// dom/workers
+#include "File.h"
+#include "WorkerPrivate.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner, mHeaders)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Request, mOwner)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Request)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-Request::Request(nsISupports* aOwner)
+Request::Request(nsIGlobalObject* aOwner, InternalRequest* aRequest)
   : mOwner(aOwner)
-  , mHeaders(new Headers(aOwner))
+  , mRequest(aRequest)
+  , mBodyUsed(false)
 {
   SetIsDOMBinding();
 }
 
 Request::~Request()
 {
 }
 
+already_AddRefed<InternalRequest>
+Request::GetInternalRequest()
+{
+  nsRefPtr<InternalRequest> r = mRequest;
+  return r.forget();
+}
+
 /*static*/ already_AddRefed<Request>
-Request::Constructor(const GlobalObject& global,
+Request::Constructor(const GlobalObject& aGlobal,
                      const RequestOrScalarValueString& aInput,
-                     const RequestInit& aInit, ErrorResult& rv)
+                     const RequestInit& aInit, ErrorResult& aRv)
 {
-  nsRefPtr<Request> request = new Request(global.GetAsSupports());
-  return request.forget();
+  nsRefPtr<InternalRequest> request;
+
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
+
+  if (aInput.IsRequest()) {
+    nsRefPtr<Request> inputReq = &aInput.GetAsRequest();
+    if (inputReq->BodyUsed()) {
+      aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
+      return nullptr;
+    }
+
+    inputReq->SetBodyUsed();
+    request = inputReq->GetInternalRequest();
+  } else {
+    request = new InternalRequest();
+  }
+
+  request = request->GetRequestConstructorCopy(global, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  RequestMode fallbackMode = RequestMode::EndGuard_;
+  RequestCredentials fallbackCredentials = RequestCredentials::EndGuard_;
+  if (aInput.IsScalarValueString()) {
+    nsString input;
+    input.Assign(aInput.GetAsScalarValueString());
+
+    nsString requestURL;
+    if (NS_IsMainThread()) {
+      nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global);
+      MOZ_ASSERT(window);
+      nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
+      nsCString spec;
+      aRv = docURI->GetSpec(spec);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return nullptr;
+      }
+
+      nsRefPtr<mozilla::dom::URL> url =
+        dom::URL::Constructor(aGlobal, input, NS_ConvertUTF8toUTF16(spec), aRv);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
+
+      url->Stringify(requestURL, aRv);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
+    } else {
+      workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
+      MOZ_ASSERT(worker);
+      worker->AssertIsOnWorkerThread();
+
+      nsString baseURL = NS_ConvertUTF8toUTF16(worker->GetLocationInfo().mHref);
+      nsRefPtr<workers::URL> url =
+        workers::URL::Constructor(aGlobal, input, baseURL, aRv);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
+
+      url->Stringify(requestURL, aRv);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
+    }
+    request->SetURL(NS_ConvertUTF16toUTF8(requestURL));
+    fallbackMode = RequestMode::Cors;
+    fallbackCredentials = RequestCredentials::Omit;
+  }
+
+  RequestMode mode = aInit.mMode.WasPassed() ? aInit.mMode.Value() : fallbackMode;
+  RequestCredentials credentials =
+    aInit.mCredentials.WasPassed() ? aInit.mCredentials.Value()
+                                   : fallbackCredentials;
+
+  if (mode != RequestMode::EndGuard_) {
+    request->SetMode(mode);
+  }
+
+  if (credentials != RequestCredentials::EndGuard_) {
+    request->SetCredentialsMode(credentials);
+  }
+
+  if (aInit.mMethod.WasPassed()) {
+    nsCString method = aInit.mMethod.Value();
+    ToLowerCase(method);
+
+    if (!method.EqualsASCII("options") &&
+        !method.EqualsASCII("get") &&
+        !method.EqualsASCII("head") &&
+        !method.EqualsASCII("post") &&
+        !method.EqualsASCII("put") &&
+        !method.EqualsASCII("delete")) {
+      NS_ConvertUTF8toUTF16 label(method);
+      aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
+      return nullptr;
+    }
+
+    ToUpperCase(method);
+    request->SetMethod(method);
+  }
+
+  nsRefPtr<Request> domRequest = new Request(global, request);
+  nsRefPtr<Headers> domRequestHeaders = domRequest->Headers_();
+
+  nsRefPtr<Headers> headers;
+  if (aInit.mHeaders.WasPassed()) {
+    headers = Headers::Constructor(aGlobal, aInit.mHeaders.Value(), aRv);
+    if (aRv.Failed()) {
+      return nullptr;
+    }
+  } else {
+    headers = new Headers(*domRequestHeaders);
+  }
+
+  domRequestHeaders->Clear();
+
+  if (domRequest->Mode() == RequestMode::No_cors) {
+    nsCString method;
+    domRequest->GetMethod(method);
+    ToLowerCase(method);
+    if (!method.EqualsASCII("get") &&
+        !method.EqualsASCII("head") &&
+        !method.EqualsASCII("post")) {
+      NS_ConvertUTF8toUTF16 label(method);
+      aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
+      return nullptr;
+    }
+
+    domRequestHeaders->SetGuard(HeadersGuardEnum::Request_no_cors, aRv);
+    if (aRv.Failed()) {
+      return nullptr;
+    }
+  }
+
+  domRequestHeaders->Fill(*headers, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  if (aInit.mBody.WasPassed()) {
+    const OwningArrayBufferOrArrayBufferViewOrScalarValueStringOrURLSearchParams& bodyInit = aInit.mBody.Value();
+    nsCOMPtr<nsIInputStream> stream;
+    nsCString contentType;
+    aRv = ExtractByteStreamFromBody(bodyInit,
+                                    getter_AddRefs(stream), contentType);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
+    request->SetBody(stream);
+
+    if (!contentType.IsVoid() &&
+        !domRequestHeaders->Has(NS_LITERAL_CSTRING("Content-Type"), aRv)) {
+      domRequestHeaders->Append(NS_LITERAL_CSTRING("Content-Type"),
+                                contentType, aRv);
+    }
+
+    if (aRv.Failed()) {
+      return nullptr;
+    }
+  }
+
+  // Extract mime type.
+  nsTArray<nsCString> contentTypeValues;
+  domRequestHeaders->GetAll(NS_LITERAL_CSTRING("Content-Type"),
+                            contentTypeValues, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  // HTTP ABNF states Content-Type may have only one value.
+  // This is from the "parse a header value" of the fetch spec.
+  if (contentTypeValues.Length() == 1) {
+    domRequest->mMimeType = contentTypeValues[0];
+    ToLowerCase(domRequest->mMimeType);
+  }
+
+  return domRequest.forget();
 }
 
 already_AddRefed<Request>
 Request::Clone() const
 {
-  nsRefPtr<Request> request = new Request(mOwner);
+  // FIXME(nsm): Bug 1073231. This is incorrect, but the clone method isn't
+  // well defined yet.
+  nsRefPtr<Request> request = new Request(mOwner,
+                                          new InternalRequest(*mRequest));
   return request.forget();
 }
 
+namespace {
+nsresult
+DecodeUTF8(const nsCString& aBuffer, nsString& aDecoded)
+{
+  nsCOMPtr<nsIUnicodeDecoder> decoder =
+    EncodingUtils::DecoderForEncoding("UTF-8");
+  if (!decoder) {
+    return NS_ERROR_FAILURE;
+  }
+
+  int32_t destBufferLen;
+  nsresult rv =
+    decoder->GetMaxLength(aBuffer.get(), aBuffer.Length(), &destBufferLen);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  if (!aDecoded.SetCapacity(destBufferLen, fallible_t())) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  char16_t* destBuffer = aDecoded.BeginWriting();
+  int32_t srcLen = (int32_t) aBuffer.Length();
+  int32_t outLen = destBufferLen;
+  rv = decoder->Convert(aBuffer.get(), &srcLen, destBuffer, &outLen);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  MOZ_ASSERT(outLen <= destBufferLen);
+  aDecoded.SetLength(outLen);
+  return NS_OK;
+}
+}
+
+already_AddRefed<Promise>
+Request::ConsumeBody(ConsumeType aType, ErrorResult& aRv)
+{
+  nsRefPtr<Promise> promise = Promise::Create(mOwner, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  if (BodyUsed()) {
+    aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
+    return nullptr;
+  }
+
+  SetBodyUsed();
+
+  // While the spec says to do this asynchronously, all the body constructors
+  // right now only accept bodies whose streams are backed by an in-memory
+  // buffer that can be read without blocking. So I think this is fine.
+  nsCOMPtr<nsIInputStream> stream;
+  mRequest->GetBody(getter_AddRefs(stream));
+
+  if (!stream) {
+    aRv = NS_NewByteInputStream(getter_AddRefs(stream), "", 0,
+                                NS_ASSIGNMENT_COPY);
+    if (aRv.Failed()) {
+      return nullptr;
+    }
+  }
+
+  AutoJSAPI api;
+  api.Init(mOwner);
+  JSContext* cx = api.cx();
+
+  // We can make this assertion because for now we only support memory backed
+  // structures for the body argument for a Request.
+  MOZ_ASSERT(NS_InputStreamIsBuffered(stream));
+  nsCString buffer;
+  uint64_t len;
+  aRv = stream->Available(&len);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  aRv = NS_ReadInputStreamToString(stream, buffer, len);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  buffer.SetLength(len);
+
+  switch (aType) {
+    case CONSUME_ARRAYBUFFER: {
+      JS::Rooted<JSObject*> arrayBuffer(cx);
+      arrayBuffer =
+        ArrayBuffer::Create(cx, buffer.Length(),
+                            reinterpret_cast<const uint8_t*>(buffer.get()));
+      JS::Rooted<JS::Value> val(cx);
+      val.setObjectOrNull(arrayBuffer);
+      promise->MaybeResolve(cx, val);
+      return promise.forget();
+    }
+    case CONSUME_BLOB: {
+      // XXXnsm it is actually possible to avoid these duplicate allocations
+      // for the Blob case by having the Blob adopt the stream's memory
+      // directly, but I've not added a special case for now.
+      //
+      // This is similar to nsContentUtils::CreateBlobBuffer, but also deals
+      // with worker wrapping.
+      uint32_t blobLen = buffer.Length();
+      void* blobData = moz_malloc(blobLen);
+      nsCOMPtr<nsIDOMBlob> blob;
+      if (blobData) {
+        memcpy(blobData, buffer.BeginReading(), blobLen);
+        blob = DOMFile::CreateMemoryFile(blobData, blobLen,
+                                         NS_ConvertUTF8toUTF16(mMimeType));
+      } else {
+        aRv = NS_ERROR_OUT_OF_MEMORY;
+        return nullptr;
+      }
+
+      JS::Rooted<JS::Value> jsBlob(cx);
+      if (NS_IsMainThread()) {
+        aRv = nsContentUtils::WrapNative(cx, blob, &jsBlob);
+        if (aRv.Failed()) {
+          return nullptr;
+        }
+      } else {
+        jsBlob.setObject(*workers::file::CreateBlob(cx, blob));
+      }
+      promise->MaybeResolve(cx, jsBlob);
+      return promise.forget();
+    }
+    case CONSUME_JSON: {
+      nsString decoded;
+      aRv = DecodeUTF8(buffer, decoded);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
+
+      JS::Rooted<JS::Value> json(cx);
+      if (!JS_ParseJSON(cx, decoded.get(), decoded.Length(), &json)) {
+        JS::Rooted<JS::Value> exn(cx);
+        if (JS_GetPendingException(cx, &exn)) {
+          JS_ClearPendingException(cx);
+          promise->MaybeReject(cx, exn);
+        }
+      }
+      promise->MaybeResolve(cx, json);
+      return promise.forget();
+    }
+    case CONSUME_TEXT: {
+      nsString decoded;
+      aRv = DecodeUTF8(buffer, decoded);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
+
+      promise->MaybeResolve(decoded);
+      return promise.forget();
+    }
+  }
+
+  NS_NOTREACHED("Unexpected consume body type");
+  // Silence warnings.
+  return nullptr;
+}
+
 already_AddRefed<Promise>
 Request::ArrayBuffer(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
-  MOZ_ASSERT(global);
-  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
-  return promise.forget();
+  return ConsumeBody(CONSUME_ARRAYBUFFER, aRv);
 }
 
 already_AddRefed<Promise>
 Request::Blob(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
-  MOZ_ASSERT(global);
-  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
-  return promise.forget();
+  return ConsumeBody(CONSUME_BLOB, aRv);
 }
 
 already_AddRefed<Promise>
 Request::Json(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
-  MOZ_ASSERT(global);
-  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
-  return promise.forget();
+  return ConsumeBody(CONSUME_JSON, aRv);
 }
 
 already_AddRefed<Promise>
 Request::Text(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
-  MOZ_ASSERT(global);
-  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
-  return promise.forget();
-}
-
-bool
-Request::BodyUsed()
-{
-  return false;
+  return ConsumeBody(CONSUME_TEXT, aRv);
 }
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -4,74 +4,82 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Request_h
 #define mozilla_dom_Request_h
 
 #include "nsISupportsImpl.h"
 #include "nsWrapperCache.h"
 
+#include "mozilla/dom/InternalRequest.h"
+// Required here due to certain WebIDL enums/classes being declared in both
+// files.
 #include "mozilla/dom/RequestBinding.h"
 #include "mozilla/dom/UnionTypes.h"
 
-
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Headers;
 class Promise;
 
 class Request MOZ_FINAL : public nsISupports
                         , public nsWrapperCache
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Request)
 
 public:
-  Request(nsISupports* aOwner);
+  Request(nsIGlobalObject* aOwner, InternalRequest* aRequest);
 
   JSObject*
   WrapObject(JSContext* aCx)
   {
     return RequestBinding::Wrap(aCx, this);
   }
 
   void
   GetUrl(DOMString& aUrl) const
   {
-    aUrl.AsAString() = EmptyString();
+    aUrl.AsAString() = NS_ConvertUTF8toUTF16(mRequest->mURL);
   }
 
   void
   GetMethod(nsCString& aMethod) const
   {
-    aMethod = EmptyCString();
+    aMethod = mRequest->mMethod;
   }
 
   RequestMode
   Mode() const
   {
-    return RequestMode::Same_origin;
+    return mRequest->mMode;
   }
 
   RequestCredentials
   Credentials() const
   {
-    return RequestCredentials::Omit;
+    return mRequest->mCredentialsMode;
   }
 
   void
   GetReferrer(DOMString& aReferrer) const
   {
-    aReferrer.AsAString() = EmptyString();
+    if (mRequest->ReferrerIsNone()) {
+      aReferrer.AsAString() = EmptyString();
+      return;
+    }
+
+    // FIXME(nsm): Spec doesn't say what to do if referrer is client.
+    aReferrer.AsAString() = NS_ConvertUTF8toUTF16(mRequest->mReferrerURL);
   }
 
-  Headers* Headers_() const { return mHeaders; }
+  Headers* Headers_() const { return mRequest->Headers_(); }
 
   static already_AddRefed<Request>
   Constructor(const GlobalObject& aGlobal, const RequestOrScalarValueString& aInput,
               const RequestInit& aInit, ErrorResult& rv);
 
   nsISupports* GetParentObject() const
   {
     return mOwner;
@@ -88,20 +96,46 @@ public:
 
   already_AddRefed<Promise>
   Json(ErrorResult& aRv);
 
   already_AddRefed<Promise>
   Text(ErrorResult& aRv);
 
   bool
-  BodyUsed();
+  BodyUsed() const
+  {
+    return mBodyUsed;
+  }
+
+  already_AddRefed<InternalRequest>
+  GetInternalRequest();
 private:
+  enum ConsumeType
+  {
+    CONSUME_ARRAYBUFFER,
+    CONSUME_BLOB,
+    // FormData not supported right now,
+    CONSUME_JSON,
+    CONSUME_TEXT,
+  };
+
   ~Request();
 
-  nsCOMPtr<nsISupports> mOwner;
-  nsRefPtr<Headers> mHeaders;
+  already_AddRefed<Promise>
+  ConsumeBody(ConsumeType aType, ErrorResult& aRv);
+
+  void
+  SetBodyUsed()
+  {
+    mBodyUsed = true;
+  }
+
+  nsCOMPtr<nsIGlobalObject> mOwner;
+  nsRefPtr<InternalRequest> mRequest;
+  bool mBodyUsed;
+  nsCString mMimeType;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Request_h
--- a/dom/fetch/moz.build
+++ b/dom/fetch/moz.build
@@ -1,22 +1,26 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS.mozilla.dom += [
+    'Fetch.h',
     'Headers.h',
+    'InternalRequest.h',
     'Request.h',
     'Response.h',
 ]
 
 UNIFIED_SOURCES += [
+    'Fetch.cpp',
     'Headers.cpp',
+    'InternalRequest.cpp',
     'Request.cpp',
     'Response.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '../workers',
 ]
 
new file mode 100644
--- /dev/null
+++ b/dom/ipc/CPOWManagerGetter.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_CPOWManagerGetter_h
+#define mozilla_dom_CPOWManagerGetter_h
+
+namespace mozilla {
+
+namespace jsipc {
+class JavaScriptShared;
+} /* namespace jsipc */
+
+namespace dom {
+class CPOWManagerGetter
+{
+public:
+  virtual mozilla::jsipc::JavaScriptShared* GetCPOWManager() = 0;
+};
+} /* namespace dom */
+
+} /* namespace mozilla */
+
+#endif /* mozilla_dom_CPOWManagerGetter_h */
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -93,17 +93,17 @@ ContentBridgeChild::SendPBrowserConstruc
                                                       aID,
                                                       aIsForApp,
                                                       aIsForBrowser);
 }
 
 // This implementation is identical to ContentChild::GetCPOWManager but we can't
 // move it to nsIContentChild because it calls ManagedPJavaScriptChild() which
 // only exists in PContentChild and PContentBridgeChild.
-jsipc::JavaScriptChild *
+jsipc::JavaScriptShared*
 ContentBridgeChild::GetCPOWManager()
 {
   if (ManagedPJavaScriptChild().Length()) {
     return static_cast<JavaScriptChild*>(ManagedPJavaScriptChild()[0]);
   }
   JavaScriptChild* actor = static_cast<JavaScriptChild*>(SendPJavaScriptConstructor());
   return actor;
 }
--- a/dom/ipc/ContentBridgeChild.h
+++ b/dom/ipc/ContentBridgeChild.h
@@ -31,17 +31,17 @@ public:
                                 const ClonedMessageData& aData,
                                 const InfallibleTArray<jsipc::CpowEntry>& aCpows,
                                 const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
   virtual PBlobChild*
   SendPBlobConstructor(PBlobChild* actor,
                        const BlobConstructorParams& params);
 
-  jsipc::JavaScriptChild* GetCPOWManager();
+  jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
   virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
                                        const uint64_t& aID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -143,17 +143,17 @@ bool
 ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
 {
   return nsIContentParent::DeallocPBrowserParent(aParent);
 }
 
 // This implementation is identical to ContentParent::GetCPOWManager but we can't
 // move it to nsIContentParent because it calls ManagedPJavaScriptParent() which
 // only exists in PContentParent and PContentBridgeParent.
-jsipc::JavaScriptParent*
+jsipc::JavaScriptShared*
 ContentBridgeParent::GetCPOWManager()
 {
   if (ManagedPJavaScriptParent().Length()) {
     return static_cast<JavaScriptParent*>(ManagedPJavaScriptParent()[0]);
   }
   JavaScriptParent* actor = static_cast<JavaScriptParent*>(SendPJavaScriptConstructor());
   return actor;
 }
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -34,17 +34,17 @@ public:
   virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* aActor,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
                           const uint64_t& aID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) MOZ_OVERRIDE;
 
-  jsipc::JavaScriptParent* GetCPOWManager();
+  jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
   virtual uint64_t ChildID() MOZ_OVERRIDE
   {
     return mChildID;
   }
   virtual bool IsForApp() MOZ_OVERRIDE
   {
     return mIsForApp;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1241,17 +1241,17 @@ ContentChild::AllocPTestShellChild()
 
 bool
 ContentChild::DeallocPTestShellChild(PTestShellChild* shell)
 {
     delete shell;
     return true;
 }
 
-jsipc::JavaScriptChild *
+jsipc::JavaScriptShared*
 ContentChild::GetCPOWManager()
 {
     if (ManagedPJavaScriptChild().Length()) {
         return static_cast<JavaScriptChild*>(ManagedPJavaScriptChild()[0]);
     }
     JavaScriptChild* actor = static_cast<JavaScriptChild*>(SendPJavaScriptConstructor());
     return actor;
 }
@@ -1726,17 +1726,17 @@ bool
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                const ClonedMessageData& aData,
                                const InfallibleTArray<CpowEntry>& aCpows,
                                const IPC::Principal& aPrincipal)
 {
     nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
     if (cpm) {
         StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
-        CpowIdHolder cpows(GetCPOWManager(), aCpows);
+        CpowIdHolder cpows(this, aCpows);
         cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
                             aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
     }
     return true;
 }
 
 bool
 ContentChild::RecvGeolocationUpdate(const GeoPosition& somewhere)
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -29,17 +29,17 @@ class RemoteSpellcheckEngineChild;
 
 namespace ipc {
 class OptionalURIParams;
 class PFileDescriptorSetChild;
 class URIParams;
 }// namespace ipc
 
 namespace jsipc {
-class JavaScriptChild;
+class JavaScriptShared;
 }
 
 namespace layers {
 class PCompositorChild;
 } // namespace layers
 
 namespace dom {
 
@@ -189,17 +189,17 @@ public:
 
     virtual bool
     RecvDataStoreNotify(const uint32_t& aAppId, const nsString& aName,
                         const nsString& aManifestURL) MOZ_OVERRIDE;
 
     virtual PTestShellChild* AllocPTestShellChild() MOZ_OVERRIDE;
     virtual bool DeallocPTestShellChild(PTestShellChild*) MOZ_OVERRIDE;
     virtual bool RecvPTestShellConstructor(PTestShellChild*) MOZ_OVERRIDE;
-    jsipc::JavaScriptChild *GetCPOWManager();
+    jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
     PMobileConnectionChild*
     SendPMobileConnectionConstructor(PMobileConnectionChild* aActor,
                                      const uint32_t& aClientId);
     virtual PMobileConnectionChild*
     AllocPMobileConnectionChild(const uint32_t& aClientId) MOZ_OVERRIDE;
     virtual bool
     DeallocPMobileConnectionChild(PMobileConnectionChild* aActor) MOZ_OVERRIDE;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1772,17 +1772,17 @@ ContentParent::NotifyTabDestroyed(PBrows
     if (ManagedPBrowserParent().Length() == 1) {
         MessageLoop::current()->PostTask(
             FROM_HERE,
             NewRunnableMethod(this, &ContentParent::ShutDownProcess,
                               /* force */ false));
     }
 }
 
-jsipc::JavaScriptParent*
+jsipc::JavaScriptShared*
 ContentParent::GetCPOWManager()
 {
     if (ManagedPJavaScriptParent().Length()) {
         return static_cast<JavaScriptParent*>(ManagedPJavaScriptParent()[0]);
     }
     return nullptr;
 }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -40,17 +40,17 @@ class PRemoteSpellcheckEngineParent;
 namespace ipc {
 class OptionalURIParams;
 class PFileDescriptorSetParent;
 class URIParams;
 class TestShellParent;
 } // namespace ipc
 
 namespace jsipc {
-class JavaScriptParent;
+class JavaScriptShared;
 class PJavaScriptParent;
 }
 
 namespace layers {
 class PCompositorParent;
 class PSharedBufferManagerParent;
 } // namespace layers
 
@@ -172,17 +172,17 @@ public:
     void NotifyTabDestroying(PBrowserParent* aTab);
     /** Notify that a tab was destroyed during normal operation. */
     void NotifyTabDestroyed(PBrowserParent* aTab,
                             bool aNotifiedDestroying);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
-    jsipc::JavaScriptParent *GetCPOWManager();
+    jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
     virtual bool IsForApp() MOZ_OVERRIDE;
     virtual bool IsForBrowser() MOZ_OVERRIDE
     {
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -2569,17 +2569,17 @@ TabChild::RecvAsyncMessage(const nsStrin
                            const InfallibleTArray<CpowEntry>& aCpows,
                            const IPC::Principal& aPrincipal)
 {
   if (mTabChildGlobal) {
     nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(GetGlobal());
     StructuredCloneData cloneData = UnpackClonedMessageDataForChild(aData);
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get());
-    CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
+    CpowIdHolder cpows(Manager(), aCpows);
     mm->ReceiveMessage(static_cast<EventTarget*>(mTabChildGlobal),
                        aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
 
 class UnloadScriptEvent : public nsRunnable
 {
@@ -2905,17 +2905,17 @@ TabChild::DoSendBlockingMessage(JSContex
                                 InfallibleTArray<nsString>* aJSONRetVal,
                                 bool aIsSync)
 {
   ClonedMessageData data;
   if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
-  if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+  if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
     return false;
   }
   if (aIsSync) {
     return SendSyncMessage(PromiseFlatString(aMessage), data, cpows,
                            Principal(aPrincipal), aJSONRetVal);
   }
 
   return CallRpcMessage(PromiseFlatString(aMessage), data, cpows,
@@ -2929,17 +2929,17 @@ TabChild::DoSendAsyncMessage(JSContext* 
                              JS::Handle<JSObject *> aCpows,
                              nsIPrincipal* aPrincipal)
 {
   ClonedMessageData data;
   if (!BuildClonedMessageDataForChild(Manager(), aData, data)) {
     return false;
   }
   InfallibleTArray<CpowEntry> cpows;
-  if (!Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
+  if (aCpows && !Manager()->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) {
     return false;
   }
   return SendAsyncMessage(PromiseFlatString(aMessage), data, cpows,
                           Principal(aPrincipal));
 }
 
 TabChild*
 TabChild::GetFrom(nsIPresShell* aPresShell)
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1109,17 +1109,17 @@ TabParent::RecvSyncMessage(const nsStrin
     ContentParent* parent = Manager()->AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
-  CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
+  CpowIdHolder cpows(Manager(), aCpows);
   return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
 }
 
 bool
 TabParent::AnswerRpcMessage(const nsString& aMessage,
                             const ClonedMessageData& aData,
                             const InfallibleTArray<CpowEntry>& aCpows,
                             const IPC::Principal& aPrincipal,
@@ -1131,17 +1131,17 @@ TabParent::AnswerRpcMessage(const nsStri
     ContentParent* parent = Manager()->AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
-  CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
+  CpowIdHolder cpows(Manager(), aCpows);
   return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal);
 }
 
 bool
 TabParent::RecvAsyncMessage(const nsString& aMessage,
                             const ClonedMessageData& aData,
                             const InfallibleTArray<CpowEntry>& aCpows,
                             const IPC::Principal& aPrincipal)
@@ -1152,17 +1152,17 @@ TabParent::RecvAsyncMessage(const nsStri
     ContentParent* parent = Manager()->AsContentParent();
     if (!ContentParent::IgnoreIPCPrincipal() &&
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
-  CpowIdHolder cpows(Manager()->GetCPOWManager(), aCpows);
+  CpowIdHolder cpows(Manager(), aCpows);
   return ReceiveMessage(aMessage, false, &cloneData, &cpows, aPrincipal, nullptr);
 }
 
 bool
 TabParent::RecvSetCursor(const uint32_t& aCursor, const bool& aForce)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -15,16 +15,17 @@ EXPORTS.mozilla.dom.ipc += [
 ]
 
 EXPORTS.mozilla.dom += [
     'ContentBridgeChild.h',
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
+    'CPOWManagerGetter.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
     'FilePickerParent.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
     'TabChild.h',
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -115,17 +115,17 @@ bool
 nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   const InfallibleTArray<CpowEntry>& aCpows,
                                   const IPC::Principal& aPrincipal)
 {
   nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
   if (cpm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
-    CpowIdHolder cpows(GetCPOWManager(), aCpows);
+    CpowIdHolder cpows(this, aCpows);
     cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
                         aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
 
 } // dom
 } // mozilla
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -4,46 +4,47 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_nsIContentChild_h
 #define mozilla_dom_nsIContentChild_h
 
 #include "nsISupports.h"
 #include "nsTArrayForwardDeclare.h"
+#include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTCHILD_IID                                    \
   { 0x4eed2e73, 0x94ba, 0x48a8,                                 \
     { 0xa2, 0xd1, 0xa5, 0xed, 0x86, 0xd7, 0xbb, 0xe4 } }
 
 class nsIDOMBlob;
 class nsString;
 
 namespace IPC {
 class Principal;
 } // IPC
 
 namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptChild;
-class JavaScriptChild;
 class CpowEntry;
 } // jsipc
 
 namespace dom {
 
 class BlobChild;
 class BlobConstructorParams;
 class ClonedMessageData;
 class IPCTabContext;
 class PBlobChild;
 class PBrowserChild;
 
 class nsIContentChild : public nsISupports
+                      , public CPOWManagerGetter
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTCHILD_IID)
 
   BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
@@ -51,17 +52,16 @@ public:
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
                           const uint64_t& aID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) = 0;
-  virtual jsipc::JavaScriptChild* GetCPOWManager() = 0;
 protected:
   virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
   virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);
 
   virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
                                             const uint64_t& aID,
                                             const bool& aIsForApp,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -180,18 +180,17 @@ nsIContentParent::RecvSyncMessage(const 
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
-    CpowIdHolder cpows(GetCPOWManager(), aCpows);
-
+    CpowIdHolder cpows(this, aCpows);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                         aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
   }
   return true;
 }
 
 bool
 nsIContentParent::AnswerRpcMessage(const nsString& aMsg,
@@ -208,17 +207,17 @@ nsIContentParent::AnswerRpcMessage(const
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
-    CpowIdHolder cpows(GetCPOWManager(), aCpows);
+    CpowIdHolder cpows(this, aCpows);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                         aMsg, true, &cloneData, &cpows, aPrincipal, aRetvals);
   }
   return true;
 }
 
 bool
 nsIContentParent::RecvAsyncMessage(const nsString& aMsg,
@@ -234,17 +233,17 @@ nsIContentParent::RecvAsyncMessage(const
         parent && principal && !AssertAppPrincipal(parent, principal)) {
       return false;
     }
   }
 
   nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
   if (ppm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData);
-    CpowIdHolder cpows(GetCPOWManager(), aCpows);
+    CpowIdHolder cpows(this, aCpows);
     ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
                         aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -4,47 +4,48 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_nsIContentParent_h
 #define mozilla_dom_nsIContentParent_h
 
 #include "nsFrameMessageManager.h"
 #include "nsISupports.h"
+#include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTPARENT_IID                                   \
   { 0xeeec9ebf, 0x8ecf, 0x4e38,                                 \
     { 0x81, 0xda, 0xb7, 0x34, 0x13, 0x7e, 0xac, 0xf3 } }
 
 class nsFrameMessageManager;
 class nsIDOMBlob;
 
 namespace IPC {
 class Principal;
 } // namespace IPC
 
 namespace mozilla {
 
 namespace jsipc {
 class PJavaScriptParent;
-class JavaScriptParent;
 class CpowEntry;
 } // namespace jsipc
 
 namespace dom {
 
 class BlobConstructorParams;
 class BlobParent;
 class ContentParent;
 class IPCTabContext;
 class PBlobParent;
 class PBrowserParent;
 
 class nsIContentParent : public nsISupports
                        , public mozilla::dom::ipc::MessageManagerCallback
+                       , public CPOWManagerGetter
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)
 
   nsIContentParent();
 
   BlobParent* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
 
@@ -59,18 +60,16 @@ public:
   virtual PBrowserParent* SendPBrowserConstructor(
     PBrowserParent* actor,
     const IPCTabContext& context,
     const uint32_t& chromeFlags,
     const uint64_t& aId,
     const bool& aIsForApp,
     const bool& aIsForBrowser) NS_WARN_UNUSED_RESULT = 0;
 
-  virtual jsipc::JavaScriptParent *GetCPOWManager() = 0;
-
   virtual bool IsContentParent() { return false; }
   ContentParent* AsContentParent();
 
 protected: // methods
   bool CanOpenBrowser(const IPCTabContext& aContext);
 
 protected: // IPDL methods
   virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScriptParent();
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -17,17 +17,17 @@
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsRefPtrHashtable.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
-#include "StructuredCloneTags.h"
+#include "mozilla/dom/StructuredCloneTags.h"
 
 #include "Queue.h"
 #include "WorkerFeature.h"
 
 class JSAutoStructuredCloneBuffer;
 class nsIChannel;
 class nsIDocument;
 class nsIEventTarget;
--- a/dom/workers/test/fetch/mochitest.ini
+++ b/dom/workers/test/fetch/mochitest.ini
@@ -1,5 +1,7 @@
 [DEFAULT]
 support-files =
   worker_interfaces.js
+  worker_test_request.js
 
 [test_interfaces.html]
+[test_request.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/fetch/test_request.html
@@ -0,0 +1,48 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug XXXXXX - Test Request object in worker</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  function checkEnabled() {
+    var worker = new Worker("worker_test_request.js");
+    worker.onmessage = function(event) {
+
+      if (event.data.type == 'finish') {
+        SimpleTest.finish();
+      } else if (event.data.type == 'status') {
+        ok(event.data.status, event.data.msg);
+      }
+    }
+
+    worker.onerror = function(event) {
+      ok(false, "Worker had an error: " + event.message + " at " + event.lineno);
+      SimpleTest.finish();
+    };
+
+    worker.postMessage(true);
+  }
+
+  SimpleTest.waitForExplicitFinish();
+
+  SpecialPowers.pushPrefEnv({"set": [
+    ["dom.fetch.enabled", true]
+  ]}, function() {
+    checkEnabled();
+  });
+</script>
+</pre>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/fetch/worker_test_request.js
@@ -0,0 +1,215 @@
+function ok(a, msg) {
+  dump("OK: " + !!a + "  =>  " + a + " " + msg + "\n");
+  postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
+}
+
+function is(a, b, msg) {
+  dump("IS: " + (a===b) + "  =>  " + a + " | " + b + " " + msg + "\n");
+  postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
+}
+
+function testDefaultCtor() {
+  var req = new Request("");
+  is(req.method, "GET", "Default Request method is GET");
+  ok(req.headers instanceof Headers, "Request should have non-null Headers object");
+  is(req.url, self.location.href, "URL should be resolved with entry settings object's API base URL");
+  is(req.referrer, "", "Default referrer is `client` which serializes to empty string.");
+  is(req.mode, "cors", "Request mode for string input is cors");
+  is(req.credentials, "omit", "Default Request credentials is omit");
+
+  var req = new Request(req);
+  is(req.method, "GET", "Default Request method is GET");
+  ok(req.headers instanceof Headers, "Request should have non-null Headers object");
+  is(req.url, self.location.href, "URL should be resolved with entry settings object's API base URL");
+  is(req.referrer, "", "Default referrer is `client` which serializes to empty string.");
+  is(req.mode, "cors", "Request mode string input is cors");
+  is(req.credentials, "omit", "Default Request credentials is omit");
+}
+
+function testClone() {
+  var req = (new Request("./cloned_request.txt", {
+              method: 'POST',
+              headers: { "Content-Length": 5 },
+              body: "Sample body",
+              mode: "same-origin",
+              credentials: "same-origin",
+            })).clone();
+  ok(req.method === "POST", "Request method is POST");
+  ok(req.headers instanceof Headers, "Request should have non-null Headers object");
+  is(req.headers.get('content-length'), "5", "Request content-length should be 5.");
+  ok(req.url === (new URL("./cloned_request.txt", self.location.href)).href,
+       "URL should be resolved with entry settings object's API base URL");
+  ok(req.referrer === "", "Default referrer is `client` which serializes to empty string.");
+  ok(req.mode === "same-origin", "Request mode is same-origin");
+  ok(req.credentials === "same-origin", "Default credentials is same-origin");
+}
+
+function testUsedRequest() {
+  // Passing a used request should fail.
+  var req = new Request("", { body: "This is foo" });
+  var p1 = req.text().then(function(v) {
+    try {
+      var req2 = new Request(req);
+      ok(false, "Used Request cannot be passed to new Request");
+    } catch(e) {
+      ok(true, "Used Request cannot be passed to new Request");
+    }
+  });
+
+  // Passing a request should set the request as used.
+  var reqA = new Request("", { body: "This is foo" });
+  var reqB = new Request(reqA);
+  is(reqA.bodyUsed, true, "Passing a Request to another Request should set the former as used");
+  return p1;
+}
+
+function testSimpleUrlParse() {
+  // Just checks that the URL parser is actually being used.
+  var req = new Request("/file.html");
+  is(req.url, (new URL("/file.html", self.location.href)).href, "URL parser should be used to resolve Request URL");
+}
+
+function testMethod() {
+  var allowed = ["delete", "get", "head", "options", "post", "put"];
+  for (var i = 0; i < allowed.length; ++i) {
+    try {
+      var r = new Request("", { method: allowed[i] });
+      ok(true, "Method " + allowed[i] + " should be allowed");
+    } catch(e) {
+      ok(false, "Method " + allowed[i] + " should be allowed");
+    }
+  }
+
+  var forbidden = ["aardvark", "connect", "trace", "track"];
+  for (var i = 0; i < forbidden.length; ++i) {
+    try {
+      var r = new Request("", { method: forbidden[i] });
+      ok(false, "Method " + forbidden[i] + " should be forbidden");
+    } catch(e) {
+      ok(true, "Method " + forbidden[i] + " should be forbidden");
+    }
+  }
+
+  var allowedNoCors = ["get", "head", "post"];
+  for (var i = 0; i < allowedNoCors.length; ++i) {
+    try {
+      var r = new Request("", { method: allowedNoCors[i], mode: "no-cors" });
+      ok(true, "Method " + allowedNoCors[i] + " should be allowed in no-cors mode");
+    } catch(e) {
+      ok(false, "Method " + allowedNoCors[i] + " should be allowed in no-cors mode");
+    }
+  }
+
+  var forbiddenNoCors = ["aardvark", "delete", "options", "put"];
+  for (var i = 0; i < forbiddenNoCors.length; ++i) {
+    try {
+      var r = new Request("", { method: forbiddenNoCors[i], mode: "no-cors" });
+      ok(false, "Method " + forbiddenNoCors[i] + " should be forbidden in no-cors mode");
+    } catch(e) {
+      ok(true, "Method " + forbiddenNoCors[i] + " should be forbidden in no-cors mode");
+    }
+  }
+}
+
+function testUrlFragment() {
+  var req = new Request("./request#withfragment");
+  ok(req.url, (new URL("./request", self.location.href)).href, "request.url should be serialized with exclude fragment flag set");
+}
+
+function testBodyUsed() {
+  var req = new Request("./bodyused", { body: "Sample body" });
+  is(req.bodyUsed, false, "bodyUsed is initially false.");
+  return req.text().then((v) => {
+    is(v, "Sample body", "Body should match");
+    is(req.bodyUsed, true, "After reading body, bodyUsed should be true.");
+  }).then((v) => {
+    return req.blob().then((v) => {
+      ok(false, "Attempting to read body again should fail.");
+    }, (e) => {
+      ok(true, "Attempting to read body again should fail.");
+    })
+  });
+}
+
+// FIXME(nsm): Bug 1071290: We can't use Blobs as the body yet.
+function testBodyCreation() {
+  var text = "κόσμε";
+  var req1 = new Request("", { body: text });
+  var p1 = req1.text().then(function(v) {
+    ok(typeof v === "string", "Should resolve to string");
+    is(text, v, "Extracted string should match");
+  });
+
+  var req2 = new Request("", { body: new Uint8Array([72, 101, 108, 108, 111]) });
+  var p2 = req2.text().then(function(v) {
+    is("Hello", v, "Extracted string should match");
+  });
+
+  var req2b = new Request("", { body: (new Uint8Array([72, 101, 108, 108, 111])).buffer });
+  var p2b = req2b.text().then(function(v) {
+    is("Hello", v, "Extracted string should match");
+  });
+
+  var params = new URLSearchParams();
+  params.append("item", "Geckos");
+  params.append("feature", "stickyfeet");
+  params.append("quantity", "700");
+  var req3 = new Request("", { body: params });
+  var p3 = req3.text().then(function(v) {
+    var extracted = new URLSearchParams(v);
+    is(extracted.get("item"), "Geckos", "Param should match");
+    is(extracted.get("feature"), "stickyfeet", "Param should match");
+    is(extracted.get("quantity"), "700", "Param should match");
+  });
+
+  return Promise.all([p1, p2, p2b, p3]);
+}
+
+function testBodyExtraction() {
+  var text = "κόσμε";
+  var newReq = function() { return new Request("", { body: text }); }
+  return newReq().text().then(function(v) {
+    ok(typeof v === "string", "Should resolve to string");
+    is(text, v, "Extracted string should match");
+  }).then(function() {
+    return newReq().blob().then(function(v) {
+      ok(v instanceof Blob, "Should resolve to Blob");
+      var fs = new FileReaderSync();
+      is(fs.readAsText(v), text, "Decoded Blob should match original");
+    });
+  }).then(function() {
+    return newReq().json().then(function(v) {
+      ok(false, "Invalid json should reject");
+    }, function(e) {
+      ok(true, "Invalid json should reject");
+    })
+  }).then(function() {
+    return newReq().arrayBuffer().then(function(v) {
+      ok(v instanceof ArrayBuffer, "Should resolve to ArrayBuffer");
+      var dec = new TextDecoder();
+      is(dec.decode(new Uint8Array(v)), text, "UTF-8 decoded ArrayBuffer should match original");
+    });
+  })
+}
+
+onmessage = function() {
+  var done = function() { postMessage({ type: 'finish' }) }
+
+  testDefaultCtor();
+  testClone();
+  testSimpleUrlParse();
+  testUrlFragment();
+  testMethod();
+
+  Promise.resolve()
+    .then(testBodyCreation)
+    .then(testBodyUsed)
+    .then(testBodyExtraction)
+    .then(testUsedRequest)
+    // Put more promise based tests here.
+    .then(done)
+    .catch(function(e) {
+      ok(false, "Some Request tests failed " + e);
+      done();
+    })
+}
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -8,16 +8,17 @@
 
 #include "Units.h"                      // for ScreenPoint
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/gfx/Point.h"          // for IntSize, Point
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for Float
 #include "mozilla/layers/CompositorTypes.h"  // for DiagnosticTypes, etc
+#include "mozilla/layers/FenceUtils.h"  // for FenceHandle
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"
 #include <vector>
 #include "mozilla/WidgetUtils.h"
 
 /**
  * Different elements of a web pages are rendered into separate "layers" before
@@ -348,16 +349,21 @@ public:
 
   /**
    * Flush the current frame to the screen and tidy up.
    */
   virtual void EndFrame() = 0;
 
   virtual void SetFBAcquireFence(Layer* aLayer) {}
 
+  virtual FenceHandle GetReleaseFence()
+  {
+    return FenceHandle();
+  }
+
   /**
    * Post-rendering stuff if the rendering is done outside of this Compositor
    * e.g., by Composer2D.
    * aTransform is the transform from user space to window space.
    */
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) = 0;
 
   /**
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -353,17 +353,17 @@ public:
    * If the texture flags contain TextureFlags::DEALLOCATE_CLIENT, the destruction
    * will be synchronously coordinated with the compositor side, otherwise it
    * will be done asynchronously.
    */
   void ForceRemove();
 
   virtual void SetReleaseFenceHandle(FenceHandle aReleaseFenceHandle)
   {
-    mReleaseFenceHandle = aReleaseFenceHandle;
+    mReleaseFenceHandle.Merge(aReleaseFenceHandle);
   }
 
   const FenceHandle& GetReleaseFenceHandle() const
   {
     return mReleaseFenceHandle;
   }
 
   virtual void SetAcquireFenceHandle(FenceHandle aAcquireFenceHandle)
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -75,18 +75,16 @@ public:
 
   ~TextureParent();
 
   bool Init(const SurfaceDescriptor& aSharedData,
             const TextureFlags& aFlags);
 
   void CompositorRecycle();
 
-  void SendFenceHandleIfPresent();
-
   virtual bool RecvClientRecycle() MOZ_OVERRIDE;
 
   virtual bool RecvClearTextureHostSync() MOZ_OVERRIDE;
 
   virtual bool RecvRemoveTexture() MOZ_OVERRIDE;
 
   TextureHost* GetTextureHost() { return mTextureHost; }
 
@@ -142,24 +140,16 @@ TextureHost::AsTextureHost(PTextureParen
 }
 
 PTextureParent*
 TextureHost::GetIPDLActor()
 {
   return mActor;
 }
 
-// static
-void
-TextureHost::SendFenceHandleIfPresent(PTextureParent* actor)
-{
-  TextureParent* parent = static_cast<TextureParent*>(actor);
-  parent->SendFenceHandleIfPresent();
-}
-
 FenceHandle
 TextureHost::GetAndResetReleaseFenceHandle()
 {
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   TextureHostOGL* hostOGL = this->AsHostOGL();
   if (!hostOGL) {
     return FenceHandle();
   }
@@ -709,48 +699,25 @@ static void RecycleCallback(TextureHost*
   TextureParent* tp = reinterpret_cast<TextureParent*>(aClosure);
   tp->CompositorRecycle();
 }
 
 void
 TextureParent::CompositorRecycle()
 {
   mTextureHost->ClearRecycleCallback();
-  SendFenceHandleIfPresent();
 
   if (mTextureHost->GetFlags() & TextureFlags::RECYCLE) {
     mozilla::unused << SendCompositorRecycle();
     // Don't forget to prepare for the next reycle
     // if TextureClient request it.
     mWaitForClientRecycle = mTextureHost;
   }
 }
 
-void
-TextureParent::SendFenceHandleIfPresent()
-{
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
-  if (mTextureHost) {
-    TextureHostOGL* hostOGL = mTextureHost->AsHostOGL();
-    if (!hostOGL) {
-      return;
-    }
-    android::sp<android::Fence> fence = hostOGL->GetAndResetReleaseFence();
-    if (fence.get() && fence->isValid()) {
-      // HWC might not provide Fence.
-      // In this case, HWC implicitly handles buffer's fence.
-
-      FenceHandle handle = FenceHandle(fence);
-      RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(handle);
-      mCompositableManager->SendFenceHandle(tracker, this, handle);
-    }
-  }
-#endif
-}
-
 bool
 TextureParent::RecvClientRecycle()
 {
   // This will allow the RecycleCallback to be called once the compositor
   // releases any external references to TextureHost.
   mTextureHost->SetRecycleCallback(RecycleCallback, this);
   if (!mWaitForClientRecycle) {
     RECYCLE_LOG("Not a recycable tile");
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -416,18 +416,16 @@ public:
   /**
    * Return a pointer to the IPDLActor.
    *
    * This is to be used with IPDL messages only. Do not store the returned
    * pointer.
    */
   PTextureParent* GetIPDLActor();
 
-  static void SendFenceHandleIfPresent(PTextureParent* actor);
-
   FenceHandle GetAndResetReleaseFenceHandle();
 
   /**
    * Specific to B2G's Composer2D
    * XXX - more doc here
    */
   virtual LayerRenderState GetRenderState()
   {
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -157,45 +157,46 @@ CompositableParentManager::ReceiveCompos
     case CompositableOperation::TOpRemoveTexture: {
       const OpRemoveTexture& op = aEdit.get_OpRemoveTexture();
       CompositableHost* compositable = AsCompositable(op);
       RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
 
       MOZ_ASSERT(tex.get());
       compositable->RemoveTextureHost(tex);
       // send FenceHandle if present.
-      TextureHost::SendFenceHandleIfPresent(op.textureParent());
+      SendFenceHandleIfPresent(op.textureParent(), compositable);
       break;
     }
     case CompositableOperation::TOpRemoveTextureAsync: {
       const OpRemoveTextureAsync& op = aEdit.get_OpRemoveTextureAsync();
       CompositableHost* compositable = AsCompositable(op);
       RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
 
       MOZ_ASSERT(tex.get());
       compositable->RemoveTextureHost(tex);
 
       if (!IsAsync() && GetChildProcessId()) {
         // send FenceHandle if present via ImageBridge.
         ImageBridgeParent::SendFenceHandleToTrackerIfPresent(
                              GetChildProcessId(),
                              op.holderId(),
                              op.transactionId(),
-                             op.textureParent());
+                             op.textureParent(),
+                             compositable);
 
         // If the message is recievied via PLayerTransaction,
         // Send message back via PImageBridge.
         ImageBridgeParent::ReplyRemoveTexture(
                              GetChildProcessId(),
                              OpReplyRemoveTexture(true, // isMain
                                                   op.holderId(),
                                                   op.transactionId()));
       } else {
         // send FenceHandle if present.
-        TextureHost::SendFenceHandleIfPresent(op.textureParent());
+        SendFenceHandleIfPresent(op.textureParent(), compositable);
 
         ReplyRemoveTexture(OpReplyRemoveTexture(false, // isMain
                                                 op.holderId(),
                                                 op.transactionId()));
       }
       break;
     }
     case CompositableOperation::TOpUseTexture: {
@@ -253,11 +254,47 @@ CompositableParentManager::ReceiveCompos
     default: {
       MOZ_ASSERT(false, "bad type");
     }
   }
 
   return true;
 }
 
+void
+CompositableParentManager::SendPendingAsyncMessges()
+{
+  if (mPendingAsyncMessage.empty()) {
+    return;
+  }
+
+  // Some type of AsyncParentMessageData message could have
+  // one file descriptor (e.g. OpDeliverFence).
+  // A number of file descriptors per gecko ipc message have a limitation
+  // on OS_POSIX (MACOSX or LINUX).
+#if defined(OS_POSIX)
+  static const uint32_t kMaxMessageNumber = FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE;
+#else
+  // default number that works everywhere else
+  static const uint32_t kMaxMessageNumber = 250;
+#endif
+
+  InfallibleTArray<AsyncParentMessageData> messages;
+  messages.SetCapacity(mPendingAsyncMessage.size());
+  for (size_t i = 0; i < mPendingAsyncMessage.size(); i++) {
+    messages.AppendElement(mPendingAsyncMessage[i]);
+    // Limit maximum number of messages.
+    if (messages.Length() >= kMaxMessageNumber) {
+      SendAsyncMessage(messages);
+      // Initialize Messages.
+      messages.Clear();
+    }
+  }
+
+  if (messages.Length() > 0) {
+    SendAsyncMessage(messages);
+  }
+  mPendingAsyncMessage.clear();
+}
+
 } // namespace
 } // namespace
 
--- a/gfx/layers/ipc/CompositableTransactionParent.h
+++ b/gfx/layers/ipc/CompositableTransactionParent.h
@@ -25,22 +25,27 @@ typedef std::vector<mozilla::layers::Edi
 // Since PCompositble has two potential manager protocols, we can't just call
 // the Manager() method usually generated when there's one manager protocol,
 // so both manager protocols implement this and we keep a reference to them
 // through this interface.
 class CompositableParentManager : public ISurfaceAllocator
                                 , public AsyncTransactionTrackersHolder
 {
 public:
+  virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
+                                        CompositableHost* aCompositableHost) = 0;
+
   virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
                                PTextureParent* aTexture,
                                const FenceHandle& aFence) = 0;
 
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) = 0;
 
+  void SendPendingAsyncMessges();
+
   /**
    * Get child side's process Id.
    */
   virtual base::ProcessId GetChildProcessId() = 0;
 
 protected:
   /**
    * Handle the IPDL messages that affect PCompositable actors.
@@ -52,14 +57,15 @@ protected:
   /**
    * Return true if this protocol is asynchronous with respect to the content
    * thread (ImageBridge for instance).
    */
   virtual bool IsAsync() const { return false; }
 
   virtual void ReplyRemoveTexture(const OpReplyRemoveTexture& aReply) {}
 
+  std::vector<AsyncParentMessageData> mPendingAsyncMessage;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/ipc/FenceUtils.h
+++ b/gfx/layers/ipc/FenceUtils.h
@@ -21,16 +21,17 @@ namespace layers {
 
 struct FenceHandleFromChild;
 
 struct FenceHandle {
   FenceHandle() {}
   explicit FenceHandle(const FenceHandleFromChild& aFenceHandle) {}
   bool operator==(const FenceHandle&) const { return false; }
   bool IsValid() const { return false; }
+  void Merge(const FenceHandle& aFenceHandle) {}
 };
 
 struct FenceHandleFromChild {
   FenceHandleFromChild() {}
   explicit FenceHandleFromChild(const FenceHandle& aFence) {}
   bool operator==(const FenceHandle&) const { return false; }
   bool operator==(const FenceHandleFromChild&) const { return false; }
   bool IsValid() const { return false; }
--- a/gfx/layers/ipc/FenceUtilsGonk.cpp
+++ b/gfx/layers/ipc/FenceUtilsGonk.cpp
@@ -44,38 +44,45 @@ ParamTraits<FenceHandle>::Write(Message*
   // which returned by getFlattenedSize() and getFdCount() are not changed.
   // So we change nbytes and nfds back by call corresponding calls.
   nbytes = flattenable->getFlattenedSize();
   nfds = flattenable->getFdCount();
 #else
   flattenable->flatten(data, nbytes, fds, nfds);
 #endif
   aMsg->WriteSize(nbytes);
+  aMsg->WriteSize(nfds);
   aMsg->WriteBytes(data, nbytes);
   for (size_t n = 0; n < nfds; ++n) {
     // These buffers can't die in transit because they're created
     // synchonously and the parent-side buffer can only be dropped if
     // there's a crash.
     aMsg->WriteFileDescriptor(FileDescriptor(fds[n], false));
   }
 }
 
 bool
 ParamTraits<FenceHandle>::Read(const Message* aMsg,
                                void** aIter, paramType* aResult)
 {
   size_t nbytes;
+  size_t nfds;
   const char* data;
 
   if (!aMsg->ReadSize(aIter, &nbytes) ||
+      !aMsg->ReadSize(aIter, &nfds) ||
       !aMsg->ReadBytes(aIter, &data, nbytes)) {
     return false;
   }
 
-  size_t nfds = aMsg->num_fds();
+  // Check if nfds is correct.
+  // aMsg->num_fds() could include fds of another ParamTraits<>s.
+  if (nfds > aMsg->num_fds()) {
+    return false;
+  }
   int fds[nfds];
 
   for (size_t n = 0; n < nfds; ++n) {
     FileDescriptor fd;
     if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
       return false;
     }
     // If the GraphicBuffer was shared cross-process, SCM_RIGHTS does
@@ -133,16 +140,17 @@ ParamTraits<FenceHandleFromChild>::Write
   // which returned by getFlattenedSize() and getFdCount() are not changed.
   // So we change nbytes and nfds back by call corresponding calls.
   nbytes = flattenable->getFlattenedSize();
   nfds = flattenable->getFdCount();
 #else
   flattenable->flatten(data, nbytes, fds, nfds);
 #endif
   aMsg->WriteSize(nbytes);
+  aMsg->WriteSize(nfds);
   aMsg->WriteBytes(data, nbytes);
   for (size_t n = 0; n < nfds; ++n) {
     // If the Fence was shared cross-process, SCM_RIGHTS does
     // the right thing and dup's the fd.  If it's shared cross-thread,
     // SCM_RIGHTS doesn't dup the fd.  That's surprising, but we just
     // deal with it here.  NB: only the "default" (master) process can
     // alloc gralloc buffers.
     bool sameProcess = (XRE_GetProcessType() == GeckoProcessType_Default);
@@ -156,24 +164,30 @@ ParamTraits<FenceHandleFromChild>::Write
   }
 }
 
 bool
 ParamTraits<FenceHandleFromChild>::Read(const Message* aMsg,
                                         void** aIter, paramType* aResult)
 {
   size_t nbytes;
+  size_t nfds;
   const char* data;
 
   if (!aMsg->ReadSize(aIter, &nbytes) ||
+      !aMsg->ReadSize(aIter, &nfds) ||
       !aMsg->ReadBytes(aIter, &data, nbytes)) {
     return false;
   }
 
-  size_t nfds = aMsg->num_fds();
+  // Check if nfds is correct.
+  // aMsg->num_fds() could include fds of another ParamTraits<>s.
+  if (nfds > aMsg->num_fds()) {
+    return false;
+  }
   int fds[nfds];
 
   for (size_t n = 0; n < nfds; ++n) {
     FileDescriptor fd;
     if (!aMsg->ReadFileDescriptor(aIter, &fd)) {
       return false;
     }
     fds[n] = fd.fd;
@@ -206,15 +220,39 @@ FenceHandle::FenceHandle(const sp<Fence>
   : mFence(aFence)
 {
 }
 
 FenceHandle::FenceHandle(const FenceHandleFromChild& aFenceHandle) {
   mFence = aFenceHandle.mFence;
 }
 
+void
+FenceHandle::Merge(const FenceHandle& aFenceHandle)
+{
+  if (!aFenceHandle.IsValid()) {
+    return;
+  }
+
+  if (!IsValid()) {
+    mFence = aFenceHandle.mFence;
+  } else {
+    android::sp<android::Fence> mergedFence = android::Fence::merge(
+                  android::String8::format("FenceHandle"),
+                  mFence, aFenceHandle.mFence);
+    if (!mergedFence.get()) {
+      // synchronization is broken, the best we can do is hope fences
+      // signal in order so the new fence will act like a union.
+      // This error handling is same as android::ConsumerBase does.
+      mFence = aFenceHandle.mFence;
+      return;
+    }
+    mFence = mergedFence;
+  }
+}
+
 FenceHandleFromChild::FenceHandleFromChild(const sp<Fence>& aFence)
   : mFence(aFence)
 {
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/ipc/FenceUtilsGonk.h
+++ b/gfx/layers/ipc/FenceUtilsGonk.h
@@ -18,40 +18,42 @@ namespace layers {
 
 struct FenceHandleFromChild;
 
 struct FenceHandle {
   typedef android::Fence Fence;
 
   FenceHandle()
   { }
-  FenceHandle(const android::sp<Fence>& aFence);
+  explicit FenceHandle(const android::sp<Fence>& aFence);
 
-  FenceHandle(const FenceHandleFromChild& aFenceHandle);
+  explicit FenceHandle(const FenceHandleFromChild& aFenceHandle);
 
   bool operator==(const FenceHandle& aOther) const {
     return mFence.get() == aOther.mFence.get();
   }
 
   bool IsValid() const
   {
     return mFence.get() && mFence->isValid();
   }
 
+  void Merge(const FenceHandle& aFenceHandle);
+
   android::sp<Fence> mFence;
 };
 
 struct FenceHandleFromChild {
   typedef android::Fence Fence;
 
   FenceHandleFromChild()
   { }
-  FenceHandleFromChild(const android::sp<Fence>& aFence);
+  explicit FenceHandleFromChild(const android::sp<Fence>& aFence);
 
-  FenceHandleFromChild(const FenceHandle& aFence) {
+  explicit FenceHandleFromChild(const FenceHandle& aFence) {
     mFence = aFence.mFence;
   }
 
   bool operator==(const FenceHandle& aOther) const {
     return mFence.get() == aOther.mFence.get();
   }
 
   bool operator==(const FenceHandleFromChild& aOther) const {
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -91,19 +91,35 @@ ImageBridgeParent::GetCompositorBackendT
 void
 ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   MessageLoop::current()->PostTask(
     FROM_HERE,
     NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
 }
 
+class MOZ_STACK_CLASS AutoImageBridgeParentAsyncMessageSender
+{
+public:
+  explicit AutoImageBridgeParentAsyncMessageSender(ImageBridgeParent* aImageBridge)
+    : mImageBridge(aImageBridge) {}
+
+  ~AutoImageBridgeParentAsyncMessageSender()
+  {
+    mImageBridge->SendPendingAsyncMessges();
+  }
+private:
+  ImageBridgeParent* mImageBridge;
+};
+
 bool
 ImageBridgeParent::RecvUpdate(const EditArray& aEdits, EditReplyArray* aReply)
 {
+  AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this);
+
   // If we don't actually have a compositor, then don't bother
   // creating any textures.
   if (Compositor::GetBackend() == LayersBackend::LAYERS_NONE) {
     return true;
   }
 
   EditReplyVector replyv;
   for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
@@ -331,66 +347,121 @@ ImageBridgeParent::CloneToplevel(const I
 bool ImageBridgeParent::IsSameProcess() const
 {
   return OtherProcess() == ipc::kInvalidProcessHandle;
 }
 
 void
 ImageBridgeParent::ReplyRemoveTexture(const OpReplyRemoveTexture& aReply)
 {
-  InfallibleTArray<AsyncParentMessageData> messages;
-  messages.AppendElement(aReply);
-  mozilla::unused << SendParentAsyncMessages(messages);
+  mPendingAsyncMessage.push_back(aReply);
 }
 
 /*static*/ void
 ImageBridgeParent::ReplyRemoveTexture(base::ProcessId aChildProcessId,
                                       const OpReplyRemoveTexture& aReply)
 {
   ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
   if (!imageBridge) {
     return;
   }
   imageBridge->ReplyRemoveTexture(aReply);
 }
 
-/*static*/ void
-ImageBridgeParent::SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
-                                                     uint64_t aTransactionId,
-                                                     PTextureParent* aTexture)
+void
+ImageBridgeParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
+                                            CompositableHost* aCompositableHost)
 {
   RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
   if (!texture) {
     return;
   }
+
+  // Send a ReleaseFence of CompositorOGL.
+  if (aCompositableHost && aCompositableHost->GetCompositor()) {
+    FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
+    if (fence.IsValid()) {
+      RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
+      HoldUntilComplete(tracker);
+      mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
+                                                    aTexture, nullptr,
+                                                    fence));
+    }
+  }
+
+  // Send a ReleaseFence that is set by HwcComposer2D.
   FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
-  if (!fence.IsValid()) {
+  if (fence.IsValid()) {
+    RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
+    HoldUntilComplete(tracker);
+    mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
+                                                  aTexture, nullptr,
+                                                  fence));
+  }
+}
+
+void
+ImageBridgeParent::SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
+                                                     uint64_t aTransactionId,
+                                                     PTextureParent* aTexture,
+                                                     CompositableHost* aCompositableHost)
+{
+  RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
+  if (!texture) {
     return;
   }
 
-  RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
-  HoldUntilComplete(tracker);
-  InfallibleTArray<AsyncParentMessageData> messages;
-  messages.AppendElement(OpDeliverFenceToTracker(tracker->GetId(),
-                                                 aDestHolderId,
-                                                 aTransactionId,
-                                                 fence));
-  mozilla::unused << SendParentAsyncMessages(messages);
+  // Send a ReleaseFence of CompositorOGL.
+  if (aCompositableHost && aCompositableHost->GetCompositor()) {
+    FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
+    if (fence.IsValid()) {
+      RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
+      HoldUntilComplete(tracker);
+      mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(tracker->GetId(),
+                                                             aDestHolderId,
+                                                             aTransactionId,
+                                                             fence));
+    }
+  }
+
+  // Send a ReleaseFence that is set by HwcComposer2D.
+  FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
+  if (fence.IsValid()) {
+    RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
+    HoldUntilComplete(tracker);
+    mPendingAsyncMessage.push_back(OpDeliverFenceToTracker(tracker->GetId(),
+                                                           aDestHolderId,
+                                                           aTransactionId,
+                                                           fence));
+  }
 }
 
 /*static*/ void
 ImageBridgeParent::SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProcessId,
                                                      uint64_t aDestHolderId,
                                                      uint64_t aTransactionId,
-                                                     PTextureParent* aTexture)
+                                                     PTextureParent* aTexture,
+                                                     CompositableHost* aCompositableHost)
 {
   ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
   if (!imageBridge) {
     return;
   }
   imageBridge->SendFenceHandleToTrackerIfPresent(aDestHolderId,
                                                  aTransactionId,
-                                                 aTexture);
+                                                 aTexture,
+                                                 aCompositableHost);
 }
 
+/*static*/ void
+ImageBridgeParent::SendPendingAsyncMessges(base::ProcessId aChildProcessId)
+{
+#ifdef MOZ_WIDGET_GONK
+  ImageBridgeParent* imageBridge = ImageBridgeParent::GetInstance(aChildProcessId);
+  if (!imageBridge) {
+    return;
+  }
+  imageBridge->SendPendingAsyncMessges();
+#endif
+}
 
 } // layers
 } // mozilla
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -51,16 +51,19 @@ public:
   virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
   static PImageBridgeParent*
   Create(Transport* aTransport, ProcessId aChildProcessId);
 
   // CompositableParentManager
+  virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
+                                        CompositableHost* aCompositableHost) MOZ_OVERRIDE;
+
   virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
                                PTextureParent* aTexture,
                                const FenceHandle& aFence) MOZ_OVERRIDE;
 
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) MOZ_OVERRIDE;
 
   virtual base::ProcessId GetChildProcessId() MOZ_OVERRIDE
   {
@@ -117,22 +120,27 @@ public:
 
   virtual void ReplyRemoveTexture(const OpReplyRemoveTexture& aReply) MOZ_OVERRIDE;
 
   static void ReplyRemoveTexture(base::ProcessId aChildProcessId,
                                  const OpReplyRemoveTexture& aReply);
 
   void SendFenceHandleToTrackerIfPresent(uint64_t aDestHolderId,
                                          uint64_t aTransactionId,
-                                         PTextureParent* aTexture);
+                                         PTextureParent* aTexture,
+                                         CompositableHost* aCompositableHost);
 
   static void SendFenceHandleToTrackerIfPresent(base::ProcessId aChildProcessId,
                                                 uint64_t aDestHolderId,
                                                 uint64_t aTransactionId,
-                                                PTextureParent* aTexture);
+                                                PTextureParent* aTexture,
+                                                CompositableHost* aCompositableHost);
+
+  using CompositableParentManager::SendPendingAsyncMessges;
+  static void SendPendingAsyncMessges(base::ProcessId aChildProcessId);
 
   static ImageBridgeParent* GetInstance(ProcessId aId);
 
   // Overriden from IToplevelProtocol
   IToplevelProtocol*
   CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
                 base::ProcessHandle aPeerProcess,
                 mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -13,16 +13,17 @@
 #include "ShadowLayerParent.h"          // for ShadowLayerParent
 #include "CompositableTransactionParent.h"  // for EditReplyVector
 #include "ShadowLayersManager.h"        // for ShadowLayersManager
 #include "mozilla/gfx/BasePoint3D.h"    // for BasePoint3D
 #include "mozilla/layers/CanvasLayerComposite.h"
 #include "mozilla/layers/ColorLayerComposite.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ContainerLayerComposite.h"
+#include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
 #include "mozilla/layers/ImageLayerComposite.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for PGrallocBufferParent
 #include "mozilla/layers/LayersTypes.h"  // for MOZ_LAYERS_LOG
 #include "mozilla/layers/PCompositableParent.h"
 #include "mozilla/layers/PLayerParent.h"  // for PLayerParent
 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
@@ -187,16 +188,31 @@ LayerTransactionParent::RecvUpdateNoSwap
                                          const bool& isRepeatTransaction,
                                          const mozilla::TimeStamp& aTransactionStart)
 {
   return RecvUpdate(cset, aTransactionId, targetConfig, isFirstPaint,
       scheduleComposite, paintSequenceNumber, isRepeatTransaction,
       aTransactionStart, nullptr);
 }
 
+class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender
+{
+public:
+  explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction)
+    : mLayerTransaction(aLayerTransaction) {}
+
+  ~AutoLayerTransactionParentAsyncMessageSender()
+  {
+    mLayerTransaction->SendPendingAsyncMessges();
+    ImageBridgeParent::SendPendingAsyncMessges(mLayerTransaction->GetChildProcessId());
+  }
+private:
+  LayerTransactionParent* mLayerTransaction;
+};
+
 bool
 LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
                                    const uint64_t& aTransactionId,
                                    const TargetConfig& targetConfig,
                                    const bool& isFirstPaint,
                                    const bool& scheduleComposite,
                                    const uint32_t& paintSequenceNumber,
                                    const bool& isRepeatTransaction,
@@ -218,16 +234,17 @@ LayerTransactionParent::RecvUpdate(const
   }
 
   if (mLayerManager && mLayerManager->GetCompositor() &&
       !targetConfig.naturalBounds().IsEmpty()) {
     mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());
   }
 
   EditReplyVector replyv;
+  AutoLayerTransactionParentAsyncMessageSender autoAsyncMessageSender(this);
 
   {
     AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
     layer_manager()->BeginTransaction();
   }
 
   for (EditArray::index_type i = 0; i < cset.Length(); ++i) {
     const Edit& edit = cset[i];
@@ -886,16 +903,48 @@ LayerTransactionParent::ActorDestroy(Act
 }
 
 bool LayerTransactionParent::IsSameProcess() const
 {
   return OtherProcess() == ipc::kInvalidProcessHandle;
 }
 
 void
+LayerTransactionParent::SendFenceHandleIfPresent(PTextureParent* aTexture,
+                                                 CompositableHost* aCompositableHost)
+{
+  RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
+  if (!texture) {
+    return;
+  }
+
+  // Send a ReleaseFence of CompositorOGL.
+  if (aCompositableHost && aCompositableHost->GetCompositor()) {
+    FenceHandle fence = aCompositableHost->GetCompositor()->GetReleaseFence();
+    if (fence.IsValid()) {
+      RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
+      HoldUntilComplete(tracker);
+      mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
+                                                    aTexture, nullptr,
+                                                    fence));
+    }
+  }
+
+  // Send a ReleaseFence that is set by HwcComposer2D.
+  FenceHandle fence = texture->GetAndResetReleaseFenceHandle();
+  if (fence.IsValid()) {
+    RefPtr<FenceDeliveryTracker> tracker = new FenceDeliveryTracker(fence);
+    HoldUntilComplete(tracker);
+    mPendingAsyncMessage.push_back(OpDeliverFence(tracker->GetId(),
+                                                  aTexture, nullptr,
+                                                  fence));
+  }
+}
+
+void
 LayerTransactionParent::SendFenceHandle(AsyncTransactionTracker* aTracker,
                                         PTextureParent* aTexture,
                                         const FenceHandle& aFence)
 {
   HoldUntilComplete(aTracker);
   InfallibleTArray<AsyncParentMessageData> messages;
   messages.AppendElement(OpDeliverFence(aTracker->GetId(),
                                         aTexture, nullptr,
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -81,16 +81,19 @@ public:
   virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE;
 
   virtual bool IsSameProcess() const MOZ_OVERRIDE;
 
   const uint64_t& GetPendingTransactionId() { return mPendingTransaction; }
   void SetPendingTransactionId(uint64_t aId) { mPendingTransaction = aId; }
 
   // CompositableParentManager
+  virtual void SendFenceHandleIfPresent(PTextureParent* aTexture,
+                                        CompositableHost* aCompositableHost) MOZ_OVERRIDE;
+
   virtual void SendFenceHandle(AsyncTransactionTracker* aTracker,
                                PTextureParent* aTexture,
                                const FenceHandle& aFence) MOZ_OVERRIDE;
 
   virtual void SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) MOZ_OVERRIDE;
 
   virtual base::ProcessId GetChildProcessId() MOZ_OVERRIDE
   {
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -1393,59 +1393,43 @@ CompositorOGL::SetFBAcquireFence(Layer* 
   // FBAcquireFence is FramebufferSurface's AcquireFence.
   // AcquireFence will be signaled when a buffer's content is available.
   // See Bug 974152.
 
   if (!aLayer) {
     return;
   }
 
-  const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
-  if (visibleRegion.IsEmpty()) {
-      return;
+  android::sp<android::Fence> fence = new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd());
+  if (fence.get() && fence->isValid()) {
+    FenceHandle handle = FenceHandle(fence);
+    mReleaseFenceHandle.Merge(handle);
   }
-
-  // Set FBAcquireFence on ContainerLayer's childs
-  ContainerLayer* container = aLayer->AsContainerLayer();
-  if (container) {
-    for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
-      SetFBAcquireFence(child);
-    }
-    return;
-  }
+}
 
-  // Set FBAcquireFence as tiles' ReleaseFence on TiledLayerComposer.
-  TiledLayerComposer* composer = nullptr;
-  LayerComposite* shadow = aLayer->AsLayerComposite();
-  // Only ask for the composer if we have a compositable host. Timing
-  // may make it so that we don't - see bug 1000634.
-  if (shadow && shadow->GetCompositableHost()) {
-    composer = shadow->GetTiledLayerComposer();
-    if (composer) {
-      composer->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
-      return;
-    }
+FenceHandle
+CompositorOGL::GetReleaseFence()
+{
+  if (!mReleaseFenceHandle.IsValid()) {
+    return FenceHandle();
   }
+  return FenceHandle(new android::Fence(mReleaseFenceHandle.mFence->dup()));
+}
 
-  // Set FBAcquireFence as layer buffer's ReleaseFence
-  LayerRenderState state = aLayer->GetRenderState();
-  if (!state.mTexture) {
-    return;
-  }
-  TextureHostOGL* texture = state.mTexture->AsHostOGL();
-  if (!texture) {
-    return;
-  }
-  texture->SetReleaseFence(new android::Fence(GetGonkDisplay()->GetPrevFBAcquireFd()));
-}
 #else
 void
 CompositorOGL::SetFBAcquireFence(Layer* aLayer)
 {
 }
+
+FenceHandle
+CompositorOGL::GetReleaseFence()
+{
+  return FenceHandle();
+}
 #endif
 
 void
 CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
 {
   // This lets us reftest and screenshot content rendered externally
   if (mTarget) {
     MakeCurrent();
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -204,16 +204,17 @@ public:
   virtual void DrawQuad(const gfx::Rect& aRect,
                         const gfx::Rect& aClipRect,
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE;
 
   virtual void EndFrame() MOZ_OVERRIDE;
   virtual void SetFBAcquireFence(Layer* aLayer) MOZ_OVERRIDE;
+  virtual FenceHandle GetReleaseFence() MOZ_OVERRIDE;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE;
   virtual void AbortFrame() MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE;
 
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE
   {
     if (!mGLContext)
@@ -388,14 +389,16 @@ private:
 
   bool mDestroyed;
 
   /**
    * Height of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation.
    */
   GLint mHeight;
+
+  FenceHandle mReleaseFenceHandle;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_COMPOSITOROGL_H */
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=4 sw=4 et tw=80:
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "JavaScriptShared.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/CPOWManagerGetter.h"
 #include "mozilla/dom/TabChild.h"
 #include "jsfriendapi.h"
 #include "xpcprivate.h"
 #include "WrapperFactory.h"
 #include "mozilla/Preferences.h"
 
 using namespace js;
 using namespace JS;
@@ -510,19 +511,31 @@ JavaScriptShared::toDescriptor(JSContext
             out.setSetter(JS_StrictPropertyStub);
         else
             out.setSetter(UnknownStrictPropertyStub);
     }
 
     return true;
 }
 
+CpowIdHolder::CpowIdHolder(dom::CPOWManagerGetter *managerGetter, const InfallibleTArray<CpowEntry> &cpows)
+  : js_(nullptr),
+    cpows_(cpows)
+{
+    // Only instantiate the CPOW manager if we might need it later.
+    if (cpows.Length())
+        js_ = managerGetter->GetCPOWManager();
+}
+
 bool
 CpowIdHolder::ToObject(JSContext *cx, JS::MutableHandleObject objp)
 {
+    if (!cpows_.Length())
+        return true;
+
     return js_->Unwrap(cx, cpows_, objp);
 }
 
 bool
 JavaScriptShared::Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows,
                          JS::MutableHandleObject objp)
 {
     objp.set(nullptr);
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -9,16 +9,21 @@
 #define mozilla_jsipc_JavaScriptShared_h__
 
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/jsipc/PJavaScript.h"
 #include "nsJSUtils.h"
 #include "nsFrameMessageManager.h"
 
 namespace mozilla {
+
+namespace dom {
+class CPOWManagerGetter;
+}
+
 namespace jsipc {
 
 class ObjectId {
   public:
     // Use 47 bits at most, to be safe, since jsval privates are encoded as
     // doubles. See bug 1065811 comment 12 for an explanation.
     static const size_t SERIAL_NUMBER_BITS = 47;
     static const size_t FLAG_BITS = 1;
@@ -58,21 +63,17 @@ class ObjectId {
     bool hasXrayWaiver_ : 1;
 };
 
 class JavaScriptShared;
 
 class CpowIdHolder : public CpowHolder
 {
   public:
-    CpowIdHolder(JavaScriptShared *js, const InfallibleTArray<CpowEntry> &cpows)
-      : js_(js),
-        cpows_(cpows)
-    {
-    }
+    CpowIdHolder(dom::CPOWManagerGetter *managerGetter, const InfallibleTArray<CpowEntry> &cpows);
 
     bool ToObject(JSContext *cx, JS::MutableHandleObject objp);
 
   private:
     JavaScriptShared *js_;
     const InfallibleTArray<CpowEntry> &cpows_;
 };
 
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -157,20 +157,16 @@ class RemoteOptions(ReftestOptions):
             f.close()
 
         # httpd-path is specified by standard makefile targets and may be specified
         # on the command line to select a particular version of httpd.js. If not
         # specified, try to select the one from hostutils.zip, as required in bug 882932.
         if not options.httpdPath:
             options.httpdPath = os.path.join(options.utilityPath, "components")
 
-        # Android does not run leak tests, but set some reasonable defaults to avoid errors.
-        options.leakThresholds = {}
-        options.ignoreMissingLeaks = []
-
         # TODO: Copied from main, but I think these are no longer used in a post xulrunner world
         #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner'
         #options.utilityPath = options.testRoot + self.automation._product + '/bin'
         return options
 
 class ReftestServer:
     """ Web server used to serve Reftests, for closer fidelity to the real web.
         It is virtually identical to the server used in mochitest and will only
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -339,17 +339,17 @@ class RefTest(object):
                                  cmdlineArgs,
                                  utilityPath = options.utilityPath,
                                  xrePath=options.xrePath,
                                  debuggerInfo=debuggerInfo,
                                  symbolsPath=options.symbolsPath,
                                  # give the JS harness 30 seconds to deal
                                  # with its own timeouts
                                  timeout=options.timeout + 30.0)
-      processLeakLog(self.leakLogFile, options.leakThresholds, options.ignoreMissingLeaks)
+      processLeakLog(self.leakLogFile, options)
       self.automation.log.info("\nREFTEST INFO | runreftest.py | Running tests: end.")
     finally:
       self.cleanup(profileDir)
     return status
 
   def copyExtraFilesToProfile(self, options, profile):
     "Copy extra files or dirs specified on the command line to the testing profile."
     profileDir = profile.profile
@@ -507,17 +507,16 @@ class ReftestOptions(OptionParser):
       if options.totalChunks is not None and options.thisChunk is None:
         self.error("cannot specify thisChunk or totalChunks with parallel tests")
       if options.focusFilterMode != "all":
         self.error("cannot specify focusFilterMode with parallel tests")
       if options.debugger is not None:
         self.error("cannot specify a debugger with parallel tests")
 
     options.leakThresholds = {"default": options.defaultLeakThreshold}
-    options.ignoreMissingLeaks = []
 
     return options
 
 def main():
   automation = Automation()
   parser = ReftestOptions(automation)
   reftest = RefTest(automation)
 
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -198,20 +198,16 @@ class B2GOptions(ReftestOptions):
             f.close()
 
         # httpd-path is specified by standard makefile targets and may be specified
         # on the command line to select a particular version of httpd.js. If not
         # specified, try to select the one from from the xre bundle, as required in bug 882932.
         if not options.httpdPath:
             options.httpdPath = os.path.join(options.xrePath, "components")
 
-        # B2G reftests do not do leak checking, but set some reasonable defaults to avoid errors.
-        options.leakThresholds = {}
-        options.ignoreMissingLeaks = []
-
         return options
 
 
 class ProfileConfigParser(ConfigParser.RawConfigParser):
     """Subclass of RawConfigParser that outputs .ini files in the exact
        format expected for profiles.ini, which is slightly different
        than the default format.
     """
new file mode 100644
--- /dev/null
+++ b/mozglue/linker/BaseElf.cpp
@@ -0,0 +1,55 @@
+/* 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 "BaseElf.h"
+#include "Elfxx.h"
+#include "Logging.h"
+
+using namespace Elf;
+
+unsigned long
+BaseElf::Hash(const char *symbol)
+{
+  const unsigned char *sym = reinterpret_cast<const unsigned char *>(symbol);
+  unsigned long h = 0, g;
+  while (*sym) {
+    h = (h << 4) + *sym++;
+    g = h & 0xf0000000;
+    h ^= g;
+    h ^= g >> 24;
+  }
+  return h;
+}
+
+void *
+BaseElf::GetSymbolPtr(const char *symbol, unsigned long hash) const
+{
+  const Sym *sym = GetSymbol(symbol, hash);
+  void *ptr = nullptr;
+  if (sym && sym->st_shndx != SHN_UNDEF)
+    ptr = GetPtr(sym->st_value);
+  DEBUG_LOG("BaseElf::GetSymbolPtr(%p [\"%s\"], \"%s\") = %p",
+            reinterpret_cast<const void *>(this), GetPath(), symbol, ptr);
+  return ptr;
+}
+
+const Sym *
+BaseElf::GetSymbol(const char *symbol, unsigned long hash) const
+{
+  /* Search symbol with the buckets and chains tables.
+   * The hash computed from the symbol name gives an index in the buckets
+   * table. The corresponding value in the bucket table is an index in the
+   * symbols table and in the chains table.
+   * If the corresponding symbol in the symbols table matches, we're done.
+   * Otherwise, the corresponding value in the chains table is a new index
+   * in both tables, which corresponding symbol is tested and so on and so
+   * forth */
+  size_t bucket = hash % buckets.numElements();
+  for (size_t y = buckets[bucket]; y != STN_UNDEF; y = chains[y]) {
+    if (strcmp(symbol, strtab.GetStringAt(symtab[y].st_name)))
+      continue;
+    return &symtab[y];
+  }
+  return nullptr;
+}
new file mode 100644
--- /dev/null
+++ b/mozglue/linker/BaseElf.h
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BaseElf_h
+#define BaseElf_h
+
+#include "ElfLoader.h"
+#include "Elfxx.h"
+
+
+/**
+ * Base class for ELF libraries. This class includes things that will be
+ * common between SystemElfs and CustomElfs.
+ */
+class BaseElf: public LibHandle
+{
+public:
+  /**
+   * Hash function for symbol lookup, as defined in ELF standard for System V.
+   */
+  static unsigned long Hash(const char *symbol);
+
+  /**
+   * Returns the address corresponding to the given symbol name (with a
+   * pre-computed hash).
+   */
+  void *GetSymbolPtr(const char *symbol, unsigned long hash) const;
+
+  /**
+   * Returns a pointer to the Elf Symbol in the Dynamic Symbol table
+   * corresponding to the given symbol name (with a pre-computed hash).
+   */
+  const Elf::Sym *GetSymbol(const char *symbol, unsigned long hash) const;
+
+  BaseElf(const char *path)
+  : LibHandle(path) { }
+
+protected:
+   /**
+    * Inherited from LibHandle. Those are temporary and are not supposed to
+    * be used.
+    */
+   virtual void *GetSymbolPtr(const char *symbol) const { return NULL; };
+   virtual bool Contains(void *addr) const { return false; };
+   virtual void *GetBase() const { return GetPtr(0); }
+
+#ifdef __ARM_EABI__
+  virtual const void *FindExidx(int *pcount) const { return NULL; };
+#endif
+
+  virtual Mappable *GetMappable() const { return NULL; };
+
+public:
+/* private: */
+  /**
+   * Returns a pointer relative to the base address where the library is
+   * loaded.
+   */
+  void *GetPtr(const Elf::Addr offset) const
+  {
+    if (reinterpret_cast<void *>(offset) > base)
+      return reinterpret_cast<void *>(offset);
+    return base + offset;
+  }
+
+  /**
+   * Like the above, but returns a typed (const) pointer
+   */
+  template <typename T>
+  const T *GetPtr(const Elf::Addr offset) const
+  {
+    if (reinterpret_cast<void *>(offset) > base)
+      return reinterpret_cast<const T *>(offset);
+    return reinterpret_cast<const T *>(base + offset);
+  }
+
+  /* Base address where the library is loaded */
+  MappedPtr base;
+
+  /* Buckets and chains for the System V symbol hash table */
+  Array<Elf::Word> buckets;
+  UnsizedArray<Elf::Word> chains;
+
+/* protected: */
+  /* String table */
+  Elf::Strtab strtab;
+
+  /* Symbol table */
+  UnsizedArray<Elf::Sym> symtab;
+};
+
+#endif /* BaseElf_h */
--- a/mozglue/linker/CustomElf.cpp
+++ b/mozglue/linker/CustomElf.cpp
@@ -2,17 +2,19 @@
  * 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 <cstring>
 #include <sys/mman.h>
 #include <vector>
 #include <dlfcn.h>
 #include <signal.h>
+#include <string.h>
 #include "CustomElf.h"
+#include "BaseElf.h"
 #include "Mappable.h"
 #include "Logging.h"
 
 using namespace Elf;
 using namespace mozilla;
 
 /* TODO: Fill ElfLoader::Singleton.lastError on errors. */
 
@@ -274,53 +276,20 @@ CustomElf::~CustomElf()
   CallFini();
   /* Normally, __cxa_finalize is called by the .fini function. However,
    * Android NDK before r6b doesn't do that. Our wrapped cxa_finalize only
    * calls destructors once, so call it in all cases. */
   ElfLoader::__wrap_cxa_finalize(this);
   ElfLoader::Singleton.Forget(this);
 }
 
-namespace {
-
-/**
- * Hash function for symbol lookup, as defined in ELF standard for System V
- */
-unsigned long
-ElfHash(const char *symbol)
-{
-  const unsigned char *sym = reinterpret_cast<const unsigned char *>(symbol);
-  unsigned long h = 0, g;
-  while (*sym) {
-    h = (h << 4) + *sym++;
-    if ((g = h & 0xf0000000))
-      h ^= g >> 24;
-    h &= ~g;
-  }
-  return h;
-}
-
-} /* anonymous namespace */
-
 void *
 CustomElf::GetSymbolPtr(const char *symbol) const
 {
-  return GetSymbolPtr(symbol, ElfHash(symbol));
-}
-
-void *
-CustomElf::GetSymbolPtr(const char *symbol, unsigned long hash) const
-{
-  const Sym *sym = GetSymbol(symbol, hash);
-  void *ptr = nullptr;
-  if (sym && sym->st_shndx != SHN_UNDEF)
-    ptr = GetPtr(sym->st_value);
-  DEBUG_LOG("CustomElf::GetSymbolPtr(%p [\"%s\"], \"%s\") = %p",
-            reinterpret_cast<const void *>(this), GetPath(), symbol, ptr);
-  return ptr;
+  return BaseElf::GetSymbolPtr(symbol, Hash(symbol));
 }
 
 void *
 CustomElf::GetSymbolPtrInDeps(const char *symbol) const
 {
   /* Resolve dlopen and related functions to point to ours */
   if (symbol[0] == 'd' && symbol[1] == 'l') {
     if (strcmp(symbol + 2, "open") == 0)
@@ -367,69 +336,48 @@ CustomElf::GetSymbolPtrInDeps(const char
   // so stub those out here
   if (strncmp(symbol,
               MISSING_FLASH_SYMNAME_START,
               sizeof(MISSING_FLASH_SYMNAME_START) - 1) == 0) {
     return FunctionPtr(__void_stub);
   }
 
   void *sym;
-  /* Search the symbol in the main program. Note this also tries all libraries
-   * the system linker will have loaded RTLD_GLOBAL. Unfortunately, that doesn't
-   * work with bionic, but its linker doesn't normally search the main binary
-   * anyways. Moreover, on android, the main binary is dalvik. */
-#ifdef __GLIBC__
-  sym = dlsym(RTLD_DEFAULT, symbol);
-  DEBUG_LOG("dlsym(RTLD_DEFAULT, \"%s\") = %p", symbol, sym);
-  if (sym)
-    return sym;
-#endif
+
+  unsigned long hash = Hash(symbol);
+
+  /* self_elf should never be NULL, but better safe than sorry. */
+  if (ElfLoader::Singleton.self_elf) {
+    /* We consider the library containing this code a permanent LD_PRELOAD,
+     * so, check if the symbol exists here first. */
+    sym = ElfLoader::Singleton.self_elf->GetSymbolPtr(symbol, hash);
+    if (sym)
+      return sym;
+  }
 
   /* Then search the symbol in our dependencies. Since we already searched in
    * libraries the system linker loaded, skip those (on glibc systems). We
    * also assume the symbol is to be found in one of the dependent libraries
    * directly, not in their own dependent libraries. Building libraries with
    * --no-allow-shlib-undefined ensures such indirect symbol dependency don't
    * happen. */
-  unsigned long hash = ElfHash(symbol);
   for (std::vector<RefPtr<LibHandle> >::const_iterator it = dependencies.begin();
        it < dependencies.end(); ++it) {
     if (!(*it)->IsSystemElf()) {
-      sym = reinterpret_cast<CustomElf *>((*it).get())->GetSymbolPtr(symbol, hash);
-#ifndef __GLIBC__
+      sym = static_cast<BaseElf *>(
+        static_cast<CustomElf *>((*it).get()))->GetSymbolPtr(symbol, hash);
     } else {
       sym = (*it)->GetSymbolPtr(symbol);
-#endif
     }
     if (sym)
       return sym;
   }
   return nullptr;
 }
 
-const Sym *
-CustomElf::GetSymbol(const char *symbol, unsigned long hash) const
-{
-  /* Search symbol with the buckets and chains tables.
-   * The hash computed from the symbol name gives an index in the buckets
-   * table. The corresponding value in the bucket table is an index in the
-   * symbols table and in the chains table.
-   * If the corresponding symbol in the symbols table matches, we're done.
-   * Otherwise, the corresponding value in the chains table is a new index
-   * in both tables, which corresponding symbol is tested and so on and so
-   * forth */
-  size_t bucket = hash % buckets.numElements();
-  for (size_t y = buckets[bucket]; y != STN_UNDEF; y = chains[y]) {
-    if (strcmp(symbol, strtab.GetStringAt(symtab[y].st_name)))
-      continue;
-    return &symtab[y];
-  }
-  return nullptr;
-}
-
 bool
 CustomElf::Contains(void *addr) const
 {
   return base.Contains(addr);
 }
 
 #ifdef __ARM_EABI__
 const void *
--- a/mozglue/linker/CustomElf.h
+++ b/mozglue/linker/CustomElf.h
@@ -1,24 +1,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CustomElf_h
 #define CustomElf_h
 
 #include "ElfLoader.h"
+#include "BaseElf.h"
 #include "Logging.h"
 #include "Elfxx.h"
 
 /**
  * Library Handle class for ELF libraries we don't let the system linker
  * handle.
  */
-class CustomElf: public LibHandle, private ElfLoader::link_map
+class CustomElf: public BaseElf, private ElfLoader::link_map
 {
   friend class ElfLoader;
   friend class SEGVHandler;
 public:
   /**
    * Returns a new CustomElf using the given file descriptor to map ELF
    * content. The file descriptor ownership is stolen, and it will be closed
    * in CustomElf's destructor if an instance is created, or by the Load
@@ -26,17 +27,17 @@ public:
    * are the same kind of flags that would be given to dlopen(), though
    * currently, none are supported and the behaviour is more or less that of
    * RTLD_GLOBAL | RTLD_BIND_NOW.
    */
   static mozilla::TemporaryRef<LibHandle> Load(Mappable *mappable,
                                                const char *path, int flags);
 
   /**
-   * Inherited from LibHandle
+   * Inherited from LibHandle/BaseElf
    */
   virtual ~CustomElf();
   virtual void *GetSymbolPtr(const char *symbol) const;
   virtual bool Contains(void *addr) const;
   virtual void *GetBase() const { return GetPtr(0); }
 
 #ifdef __ARM_EABI__
   virtual const void *FindExidx(int *pcount) const;
@@ -50,65 +51,35 @@ public:
    * Shows some stats about the Mappable instance. The when argument is to be
    * used by the caller to give an identifier of the when the stats call is
    * made.
    */
   void stats(const char *when) const;
 
 private:
   /**
-   * Returns a pointer to the Elf Symbol in the Dynamic Symbol table
-   * corresponding to the given symbol name (with a pre-computed hash).
-   */
-  const Elf::Sym *GetSymbol(const char *symbol, unsigned long hash) const;
-
-  /**
-   * Returns the address corresponding to the given symbol name (with a
-   * pre-computed hash).
-   */
-  void *GetSymbolPtr(const char *symbol, unsigned long hash) const;
-
-  /**
    * Scan dependent libraries to find the address corresponding to the
    * given symbol name. This is used to find symbols that are undefined
    * in the Elf object.
    */
   void *GetSymbolPtrInDeps(const char *symbol) const;
 
   /**
    * Private constructor
    */
   CustomElf(Mappable *mappable, const char *path)
-  : LibHandle(path)
+  : BaseElf(path)
   , mappable(mappable)
   , init(0)
   , fini(0)
   , initialized(false)
   , has_text_relocs(false)
   { }
 
   /**
-   * Returns a pointer relative to the base address where the library is
-   * loaded.
-   */
-  void *GetPtr(const Elf::Addr offset) const
-  {
-    return base + offset;
-  }
-
-  /**
-   * Like the above, but returns a typed (const) pointer
-   */
-  template <typename T>
-  const T *GetPtr(const Elf::Addr offset) const
-  {
-    return reinterpret_cast<const T *>(base + offset);
-  }
-
-  /**
    * Loads an Elf segment defined by the given PT_LOAD header.
    * Returns whether this succeeded or failed.
    */
   bool LoadSegment(const Elf::Phdr *pt_load) const;
 
   /**
    * Initializes the library according to information found in the given
    * PT_DYNAMIC header.
@@ -162,29 +133,16 @@ private:
   void CallFunction(Elf::Addr addr) const
   {
     return CallFunction(GetPtr(addr));
   }
 
   /* Appropriated Mappable */
   mozilla::RefPtr<Mappable> mappable;
 
-  /* Base address where the library is loaded */
-  MappedPtr base;
-
-  /* String table */
-  Elf::Strtab strtab;
-
-  /* Symbol table */
-  UnsizedArray<Elf::Sym> symtab;
-
-  /* Buckets and chains for the System V symbol hash table */
-  Array<Elf::Word> buckets;
-  UnsizedArray<Elf::Word> chains;
-
   /* List of dependent libraries */
   std::vector<mozilla::RefPtr<LibHandle> > dependencies;
 
   /* List of .rel.dyn/.rela.dyn relocations */
   Array<Elf::Reloc> relocations;
 
   /* List of .rel.plt/.rela.plt relocation */
   Array<Elf::Reloc> jumprels;
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -6,16 +6,17 @@
 #include <cstring>
 #include <cstdlib>
 #include <cstdio>
 #include <dlfcn.h>
 #include <unistd.h>
 #include <algorithm>
 #include <fcntl.h>
 #include "ElfLoader.h"
+#include "BaseElf.h"
 #include "CustomElf.h"
 #include "Mappable.h"
 #include "Logging.h"
 #include <inttypes.h>
 
 #if defined(ANDROID)
 #include <sys/syscall.h>
 
@@ -33,16 +34,20 @@ inline int sigaltstack(const stack_t *ss
 #endif /* __ANDROID_API__ */
 #endif /* ANDROID */
 
 #ifdef __ARM_EABI__
 extern "C" MOZ_EXPORT const void *
 __gnu_Unwind_Find_exidx(void *pc, int *pcount) __attribute__((weak));
 #endif
 
+/* Pointer to the PT_DYNAMIC section of the executable or library
+ * containing this code. */
+extern "C" Elf::Dyn _DYNAMIC[];
+
 using namespace mozilla;
 
 /**
  * dlfcn.h replacements functions
  */
 
 void *
 __wrap_dlopen(const char *path, int flags)
@@ -326,16 +331,20 @@ SystemElf::FindExidx(int *pcount) const
 ElfLoader ElfLoader::Singleton;
 
 TemporaryRef<LibHandle>
 ElfLoader::Load(const char *path, int flags, LibHandle *parent)
 {
   /* Ensure logging is initialized or refresh if environment changed. */
   Logging::Init();
 
+  /* Ensure self_elf initialization. */
+  if (!self_elf)
+    Init();
+
   RefPtr<LibHandle> handle;
 
   /* Handle dlopen(nullptr) directly. */
   if (!path) {
     handle = SystemElf::Load(nullptr, flags);
     return handle;
   }
 
@@ -461,16 +470,64 @@ ElfLoader::Forget(LibHandle *handle)
       dbg.Remove(static_cast<CustomElf *>(handle));
     handles.erase(it);
   } else {
     DEBUG_LOG("ElfLoader::Forget(%p [\"%s\"]): Handle not found",
               reinterpret_cast<void *>(handle), handle->GetPath());
   }
 }
 
+void
+ElfLoader::Init()
+{
+  Dl_info info;
+  /* On Android < 4.1 can't reenter dl* functions. So when the library
+   * containing this code is dlopen()ed, it can't call dladdr from a
+   * static initializer. */
+  if (dladdr(_DYNAMIC, &info) != 0) {
+    /* Ideally, we wouldn't be initializing self_elf this way, but until
+     * SystemElf actually inherits from BaseElf, we'll just do it this
+     * (gross) way. */
+    UniquePtr<BaseElf> elf = mozilla::MakeUnique<BaseElf>(info.dli_fname);
+    elf->base.Assign(info.dli_fbase, -1);
+    size_t symnum = 0;
+    for (const Elf::Dyn *dyn = _DYNAMIC; dyn->d_tag; dyn++) {
+      switch (dyn->d_tag) {
+        case DT_HASH:
+          {
+            DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_HASH", dyn->d_un.d_val);
+            const Elf::Word *hash_table_header = \
+              elf->GetPtr<Elf::Word>(dyn->d_un.d_ptr);
+            symnum = hash_table_header[1];
+            elf->buckets.Init(&hash_table_header[2], hash_table_header[0]);
+            elf->chains.Init(&*elf->buckets.end());
+          }
+          break;
+        case DT_STRTAB:
+          DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_STRTAB", dyn->d_un.d_val);
+          elf->strtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
+          break;
+        case DT_SYMTAB:
+          DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_SYMTAB", dyn->d_un.d_val);
+          elf->symtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
+          break;
+      }
+    }
+    if (!elf->buckets || !symnum) {
+      ERROR("%s: Missing or broken DT_HASH", info.dli_fname);
+    } else if (!elf->strtab) {
+      ERROR("%s: Missing DT_STRTAB", info.dli_fname);
+    } else if (!elf->symtab) {
+      ERROR("%s: Missing DT_SYMTAB", info.dli_fname);
+    } else {
+      self_elf = Move(elf);
+    }
+  }
+}
+
 ElfLoader::~ElfLoader()
 {
   LibHandleList list;
   /* Build up a list of all library handles with direct (external) references.
    * We actually skip system library handles because we want to keep at least
    * some of these open. Most notably, Mozilla codebase keeps a few libgnome
    * libraries deliberately open because of the mess that libORBit destruction
    * is. dlclose()ing these libraries actually leads to problems. */
@@ -502,16 +559,20 @@ ElfLoader::~ElfLoader()
                   "[%d direct refs, %d refs total]", (*it)->GetPath(),
                   (*it)->DirectRefCount(), (*it)->refCount());
         /* Not removing, since it could have references to other libraries,
          * destroying them as a side effect, and possibly leaving dangling
          * pointers in the handle list we're scanning */
       }
     }
   }
+  /* Avoid self_elf->base destructor unmapping something that doesn't actually
+   * belong to it. */
+  if (self_elf)
+    self_elf->base.release();
 }
 
 void
 ElfLoader::stats(const char *when)
 {
   for (LibHandleList::iterator it = Singleton.handles.begin();
        it < Singleton.handles.end(); ++it)
     if (!(*it)->IsSystemElf())
--- a/mozglue/linker/ElfLoader.h
+++ b/mozglue/linker/ElfLoader.h
@@ -4,16 +4,17 @@
 
 #ifndef ElfLoader_h
 #define ElfLoader_h
 
 #include <vector>
 #include <dlfcn.h>
 #include <signal.h>
 #include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
 #include "Zip.h"
 #include "Elfxx.h"
 #include "Mappable.h"
 
 /**
  * dlfcn.h replacement functions
  */
 extern "C" {
@@ -58,16 +59,19 @@ MFBT_API void *
 MFBT_API void
 __dl_munmap(void *handle, void *addr, size_t length);
 
 MFBT_API bool
 IsSignalHandlingBroken();
 
 }
 
+/* Forward declaration because BaseElf.h includes ElfLoader.h */
+class BaseElf;
+
 /**
  * Specialize RefCounted template for LibHandle. We may get references to
  * LibHandles during the execution of their destructor, so we need
  * RefCounted<LibHandle>::Release to support some reentrancy. See further
  * below.
  */
 class LibHandle;
 
@@ -434,16 +438,23 @@ protected:
   friend const char *__wrap_dlerror(void);
   friend void *__wrap_dlsym(void *handle, const char *symbol);
   friend int __wrap_dlclose(void *handle);
   const char *lastError;
 
 private:
   ~ElfLoader();
 
+  /* Initialization code that can't run during static initialization. */
+  void Init();
+
+  /* System loader handle for the library/program containing our code. This
+   * is used to resolve wrapped functions. */
+  mozilla::UniquePtr<BaseElf> self_elf;
+
   /* Bookkeeping */
   typedef std::vector<LibHandle *> LibHandleList;
   LibHandleList handles;
 
 protected:
   friend class CustomElf;
   /**
    * Show some stats about Mappables in CustomElfs. The when argument is to
@@ -552,23 +563,31 @@ private:
      * is in when the function above is called. */
     enum {
       RT_CONSISTENT, /* Changes are complete */
       RT_ADD,        /* Beginning to add a new object */
       RT_DELETE      /* Beginning to remove an object */
     } r_state;
   };
 
+  /* Memory representation of ELF Auxiliary Vectors */
+  struct AuxVector {
+    Elf::Addr type;
+    Elf::Addr value;
+  };
+
   /* Helper class used to integrate libraries loaded by this linker in
    * r_debug */
   class DebuggerHelper
   {
   public:
     DebuggerHelper();
 
+    void Init(AuxVector *auvx);
+
     operator bool()
     {
       return dbg;
     }
 
     /* Make the debugger aware of a new loaded object */
     void Add(link_map *map);
 
--- a/mozglue/linker/Utils.h
+++ b/mozglue/linker/Utils.h
@@ -285,16 +285,20 @@ public:
   }
 
   ~GenericMappedPtr()
   {
     if (get() != MAP_FAILED)
       static_cast<T *>(this)->munmap(get(), GetLength());
   }
 
+  void release()
+  {
+    MemoryRange::Assign(MAP_FAILED, 0);
+  }
 };
 
 struct MappedPtr: public GenericMappedPtr<MappedPtr>
 {
   MappedPtr(void *buf, size_t length)
   : GenericMappedPtr<MappedPtr>(buf, length) { }
   MappedPtr(const MemoryRange& other)
   : GenericMappedPtr<MappedPtr>(other) { }
--- a/mozglue/linker/moz.build
+++ b/mozglue/linker/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 SOURCES += [
+    'BaseElf.cpp',
     'CustomElf.cpp',
     'ElfLoader.cpp',
     'Mappable.cpp',
     'SeekableZStream.cpp',
     'Zip.cpp',
 ]
 
 Library('linker')
--- a/python/mach/mach/base.py
+++ b/python/mach/mach/base.py
@@ -72,39 +72,34 @@ class MethodHandler(object):
         'name',
 
         # String category this command belongs to.
         'category',
 
         # Description of the purpose of this command.
         'description',
 
-        # Whether to allow all arguments from the parser.
-        'allow_all_arguments',
-
         # Functions used to 'skip' commands if they don't meet the conditions
         # in a given context.
         'conditions',
 
         # argparse.ArgumentParser instance to use as the basis for command
         # arguments.
         'parser',
 
         # Arguments added to this command's parser. This is a 2-tuple of
         # positional and named arguments, respectively.
         'arguments',
     )
 
     def __init__(self, cls, method, name, category=None, description=None,
-        allow_all_arguments=False, conditions=None, parser=None, arguments=None,
-        pass_context=False):
+        conditions=None, parser=None, arguments=None, pass_context=False):
 
         self.cls = cls
         self.method = method
         self.name = name
         self.category = category
         self.description = description
-        self.allow_all_arguments = allow_all_arguments
         self.conditions = conditions or []
         self.parser = parser
         self.arguments = arguments or []
         self.pass_context = pass_context
 
--- a/python/mach/mach/decorators.py
+++ b/python/mach/mach/decorators.py
@@ -1,14 +1,15 @@
 # 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/.
 
 from __future__ import unicode_literals
 
+import argparse
 import collections
 import inspect
 import types
 
 from .base import (
     MachError,
     MethodHandler
 )
@@ -51,18 +52,18 @@ def CommandProvider(cls):
     # define commands multiple times. We also sort keys so commands defined in
     # the same class are grouped in a sane order.
     for attr in sorted(cls.__dict__.keys()):
         value = cls.__dict__[attr]
 
         if not isinstance(value, types.FunctionType):
             continue
 
-        command_name, category, description, allow_all, conditions, parser = getattr(
-            value, '_mach_command', (None, None, None, None, None, None))
+        command_name, category, description, conditions, parser = getattr(
+            value, '_mach_command', (None, None, None, None, None))
 
         if command_name is None:
             continue
 
         if conditions is None and Registrar.require_conditions:
             continue
 
         msg = 'Mach command \'%s\' implemented incorrectly. ' + \
@@ -77,19 +78,18 @@ def CommandProvider(cls):
         for c in conditions:
             if not hasattr(c, '__call__'):
                 msg = msg % (command_name, type(c))
                 raise MachError(msg)
 
         arguments = getattr(value, '_mach_command_args', None)
 
         handler = MethodHandler(cls, attr, command_name, category=category,
-            description=description, allow_all_arguments=allow_all,
-            conditions=conditions, parser=parser, arguments=arguments,
-            pass_context=pass_context)
+            description=description, conditions=conditions, parser=parser,
+            arguments=arguments, pass_context=pass_context)
 
         Registrar.register_command_handler(handler)
 
     return cls
 
 
 class Command(object):
     """Decorator for functions or methods that provide a mach subcommand.
@@ -97,40 +97,36 @@ class Command(object):
     The decorator accepts arguments that define basic attributes of the
     command. The following arguments are recognized:
 
          category -- The string category to which this command belongs. Mach's
              help will group commands by category.
 
          description -- A brief description of what the command does.
 
-         allow_all_args -- Bool indicating whether to allow unknown arguments
-             through to the command.
-
          parser -- an optional argparse.ArgumentParser instance to use as
              the basis for the command arguments.
 
     For example:
 
         @Command('foo', category='misc', description='Run the foo action')
         def foo(self):
             pass
     """
-    def __init__(self, name, category=None, description=None,
-                 allow_all_args=False, conditions=None, parser=None):
+    def __init__(self, name, category=None, description=None, conditions=None,
+                 parser=None):
         self._name = name
         self._category = category
         self._description = description
-        self._allow_all_args = allow_all_args
         self._conditions = conditions
         self._parser = parser
 
     def __call__(self, func):
         func._mach_command = (self._name, self._category, self._description,
-                              self._allow_all_args, self._conditions, self._parser)
+                              self._conditions, self._parser)
 
         return func
 
 
 class CommandArgument(object):
     """Decorator for additional arguments to mach subcommands.
 
     This decorator should be used to add arguments to mach commands. Arguments
@@ -140,16 +136,21 @@ class CommandArgument(object):
 
         @Command('foo', help='Run the foo action')
         @CommandArgument('-b', '--bar', action='store_true', default=False,
             help='Enable bar mode.')
         def foo(self):
             pass
     """
     def __init__(self, *args, **kwargs):
+        if kwargs.get('nargs') == argparse.REMAINDER:
+            # These are the assertions we make in dispatcher.py about
+            # those types of CommandArguments.
+            assert len(args) == 1
+            assert all(k in ('default', 'nargs', 'help') for k in kwargs)
         self._command_args = (args, kwargs)
 
     def __call__(self, func):
         command_args = getattr(func, '_mach_command_args', [])
 
         command_args.insert(0, self._command_args)
 
         func._mach_command_args = command_args
--- a/python/mach/mach/dispatcher.py
+++ b/python/mach/mach/dispatcher.py
@@ -130,38 +130,71 @@ class CommandAction(argparse.Action):
         # We create a new parser, populate it with the command's arguments,
         # then feed all remaining arguments to it, merging the results
         # with ourselves. This is essentially what argparse subparsers
         # do.
 
         parser_args = {
             'add_help': False,
             'usage': '%(prog)s [global arguments] ' + command +
-                ' command arguments]',
+                ' [command arguments]',
         }
 
-        if handler.allow_all_arguments:
-            parser_args['prefix_chars'] = '+'
-
         if handler.parser:
             subparser = handler.parser
         else:
             subparser = argparse.ArgumentParser(**parser_args)
 
+        remainder = None
+
         for arg in handler.arguments:
-            subparser.add_argument(*arg[0], **arg[1])
+            if arg[1].get('nargs') == argparse.REMAINDER:
+                # parse_known_args expects all argparse.REMAINDER ('...')
+                # arguments to be all stuck together. Instead, we want them to
+                # pick any extra argument, wherever they are.
+                # Assume a limited CommandArgument for those arguments.
+                assert len(arg[0]) == 1
+                assert all(k in ('default', 'nargs', 'help') for k in arg[1])
+                remainder = arg
+            else:
+                subparser.add_argument(*arg[0], **arg[1])
 
         # We define the command information on the main parser result so as to
         # not interfere with arguments passed to the command.
         setattr(namespace, 'mach_handler', handler)
         setattr(namespace, 'command', command)
 
         command_namespace, extra = subparser.parse_known_args(args)
         setattr(namespace, 'command_args', command_namespace)
-        if extra:
+        if remainder:
+            (name,), options = remainder
+            # parse_known_args usefully puts all arguments after '--' in
+            # extra, but also puts '--' there. We don't want to pass it down
+            # to the command handler. Note that if multiple '--' are on the
+            # command line, only the first one is removed, so that subsequent
+            # ones are passed down.
+            if '--' in extra:
+                extra.remove('--')
+
+            # Commands with argparse.REMAINDER arguments used to force the
+            # other arguments to be '+' prefixed. If a user now passes such
+            # an argument, if will silently end up in extra. So, check if any
+            # of the allowed arguments appear in a '+' prefixed form, and error
+            # out if that's the case.
+            for args, _ in handler.arguments:
+                for arg in args:
+                    arg = arg.replace('-', '+', 1)
+                    if arg in extra:
+                        raise UnrecognizedArgumentError(command, [arg])
+
+            if extra:
+                setattr(command_namespace, name, extra)
+            else:
+                setattr(command_namespace, name, options.get('default', []))
+        elif extra:
             raise UnrecognizedArgumentError(command, extra)
 
     def _handle_main_help(self, parser, verbose):
         # Since we don't need full sub-parser support for the main help output,
         # we create groups in the ArgumentParser and populate each group with
         # arguments corresponding to command names. This has the side-effect
         # that argparse renders it nicely.
         r = self._mach_registrar
@@ -229,19 +262,16 @@ class CommandAction(argparse.Action):
         # just the command data then supplement the main help's output with
         # this 2nd parser's. We use a custom formatter class to ignore some of
         # the help output.
         parser_args = {
             'formatter_class': CommandFormatter,
             'add_help': False,
         }
 
-        if handler.allow_all_arguments:
-            parser_args['prefix_chars'] = '+'
-
         if handler.parser:
             c_parser = handler.parser
             c_parser.formatter_class = NoUsageFormatter
             # Accessing _action_groups is a bit shady. We are highly dependent
             # on the argparse implementation not changing. We fail fast to
             # detect upstream changes so we can intelligently react to them.
             group = c_parser._action_groups[1]
 
--- a/python/mach_commands.py
+++ b/python/mach_commands.py
@@ -20,17 +20,16 @@ from mach.decorators import (
     CommandProvider,
     Command,
 )
 
 
 @CommandProvider
 class MachCommands(MachCommandBase):
     @Command('python', category='devenv',
-        allow_all_args=True,
         description='Run Python.')
     @CommandArgument('args', nargs=argparse.REMAINDER)
     def python(self, args):
         # Avoid logging the command
         self.log_manager.terminal_handler.setLevel(logging.CRITICAL)
 
         self._activate_virtualenv()
 
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -805,75 +805,72 @@ def get_run_args(mach_command, params, r
         if not os.path.isdir(path):
             os.makedirs(path)
         args.append('-profile')
         args.append(path)
 
     if params:
         args.extend(params)
 
-    if '--' in args:
-        args.remove('--')
-
     return args
 
 @CommandProvider
 class RunProgram(MachCommandBase):
     """Launch the compiled binary"""
 
-    @Command('run', category='post-build', allow_all_args=True,
+    @Command('run', category='post-build',
         description='Run the compiled program.')
-    @CommandArgument('params', default=None, nargs='...',
+    @CommandArgument('params', nargs='...',
         help='Command-line arguments to be passed through to the program. Not specifying a -profile or -P option will result in a temporary profile being used.')
-    @CommandArgument('+remote', '+r', action='store_true',
+    @CommandArgument('-remote', '-r', action='store_true',
         help='Do not pass the -no-remote argument by default.')
-    @CommandArgument('+background', '+b', action='store_true',
+    @CommandArgument('-background', '-b', action='store_true',
         help='Do not pass the -foreground argument by default on Mac')
-    @CommandArgument('+noprofile', '+n', action='store_true',
+    @CommandArgument('-noprofile', '-n', action='store_true',
         help='Do not pass the -profile argument by default.')
     def run(self, params, remote, background, noprofile):
         args = get_run_args(self, params, remote, background, noprofile)
         if not args:
             return 1
 
         return self.run_process(args=args, ensure_exit_code=False,
             pass_thru=True)
 
 @CommandProvider
 class DebugProgram(MachCommandBase):
     """Debug the compiled binary"""
 
-    @Command('debug', category='post-build', allow_all_args=True,
+    @Command('debug', category='post-build',
         description='Debug the compiled program.')
-    @CommandArgument('params', default=None, nargs='...',
+    @CommandArgument('params', nargs='...',
         help='Command-line arguments to be passed through to the program. Not specifying a -profile or -P option will result in a temporary profile being used.')
-    @CommandArgument('+remote', '+r', action='store_true',
+    @CommandArgument('-remote', '-r', action='store_true',
         help='Do not pass the -no-remote argument by default')
-    @CommandArgument('+background', '+b', action='store_true',
+    @CommandArgument('-background', '-b', action='store_true',
         help='Do not pass the -foreground argument by default on Mac')
-    @CommandArgument('+debugger', default=None, type=str,
+    @CommandArgument('-debugger', default=None, type=str,
         help='Name of debugger to launch')
-    @CommandArgument('+debugparams', default=None, metavar='params', type=str,
+    @CommandArgument('-debugparams', default=None, metavar='params', type=str,
         help='Command-line arguments to pass to the debugger itself; split as the Bourne shell would.')
     # Bug 933807 introduced JS_DISABLE_SLOW_SCRIPT_SIGNALS to avoid clever
     # segfaults induced by the slow-script-detecting logic for Ion/Odin JITted
     # code.  If we don't pass this, the user will need to periodically type
     # "continue" to (safely) resume execution.  There are ways to implement
     # automatic resuming; see the bug.
-    @CommandArgument('+slowscript', action='store_true',
+    @CommandArgument('-slowscript', action='store_true',
         help='Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; when not set, recoverable but misleading SIGSEGV instances may occur in Ion/Odin JIT code')
-    @CommandArgument('+noprofile', '+n', action='store_true',
+    @CommandArgument('-noprofile', '-n', action='store_true',
         help='Do not pass the -profile argument by default.')
     def debug(self, params, remote, background, debugger, debugparams, slowscript, noprofile):
         # Parameters come from the CLI. We need to convert them before their use.
         if debugparams:
             import pymake.process
             argv, badchar = pymake.process.clinetoargv(debugparams, os.getcwd())
             if badchar:
-                print("The +debugparams you passed require a real shell to parse them.")
+                print("The -debugparams you passed require a real shell to parse them.")
                 print("(We can't handle the %r character.)" % (badchar,))
                 return 1
             debugparams = argv;
 
         import mozdebug
 
         if not debugger:
             # No debugger name was provided. Look for the default ones on current OS.
@@ -920,17 +917,17 @@ class DebugProgram(MachCommandBase):
             ensure_exit_code=False, pass_thru=True)
 
 @CommandProvider
 class RunDmd(MachCommandBase):
     """Launch the compiled binary with DMD enabled"""
 
     @Command('dmd', category='post-build',
         description='Run the compiled program with DMD enabled.')
-    @CommandArgument('params', default=None, nargs='...',
+    @CommandArgument('params', nargs='...',
         help=('Command-line arguments to be passed through to the program. '
               'Not specifying a -profile or -P option will result in a '
               'temporary profile being used. If passing -params use a "--" to '
               'indicate the start of params to pass to firefox.'))
     @CommandArgument('--remote', '-r', action='store_true',
         help='Do not pass the -no-remote argument by default.')
     @CommandArgument('--background', '-b', action='store_true',
         help='Do not pass the -foreground argument by default on Mac')
--- a/testing/marionette/client/marionette/tests/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit-tests.ini
@@ -10,29 +10,13 @@ b2g = true
 
 ; true if the test should be skipped
 skip = false
 
 ; marionette unit tests
 [include:unit/unit-tests.ini]
 test_container = true
 
-; webapi tests
-[include:../../../../../dom/bluetooth/tests/marionette/manifest.ini]
-[include:../../../../../dom/telephony/test/marionette/manifest.ini]
-[include:../../../../../dom/voicemail/test/marionette/manifest.ini]
-[include:../../../../../dom/battery/test/marionette/manifest.ini]
-[include:../../../../../dom/mobilemessage/tests/marionette/manifest.ini]
-[include:../../../../../dom/mobileconnection/tests/marionette/manifest.ini]
-[include:../../../../../dom/system/gonk/tests/marionette/manifest.ini]
-[include:../../../../../dom/icc/tests/marionette/manifest.ini]
-[include:../../../../../dom/system/tests/marionette/manifest.ini]
-[include:../../../../../dom/nfc/tests/marionette/manifest.ini]
-[include:../../../../../dom/events/test/marionette/manifest.ini]
-[include:../../../../../dom/wifi/test/marionette/manifest.ini]
-[include:../../../../../dom/cellbroadcast/tests/marionette/manifest.ini]
-[include:../../../../../dom/tethering/tests/marionette/manifest.ini]
-
 ; layout tests
 [include:../../../../../layout/base/tests/marionette/manifest.ini]
 
 ; loop tests
 [include:../../../../../browser/components/loop/manifest.ini]
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -1840,17 +1840,17 @@ class Mochitest(MochitestUtilsMixin):
         self.log.error("Automation Error: Received unexpected exception while running application\n")
         status = 1
 
     finally:
       if options.vmwareRecording:
         self.stopVMwareRecording();
       self.stopServers()
 
-    processLeakLog(self.leak_report_file, options.leakThresholds, options.ignoreMissingLeaks)
+    processLeakLog(self.leak_report_file, options)
 
     if self.nsprLogs:
       with zipfile.ZipFile("%s/nsprlog.zip" % browserEnv["MOZ_UPLOAD_DIR"], "w", zipfile.ZIP_DEFLATED) as logzip:
         for logfile in glob.glob("%s/nspr*.log*" % tempfile.gettempdir()):
           logzip.write(logfile)
           os.remove(logfile)
 
     self.log.info("runtests.py | Running tests: end.")
--- a/testing/mochitest/runtestsb2g.py
+++ b/testing/mochitest/runtestsb2g.py
@@ -197,17 +197,17 @@ class B2GMochitest(MochitestUtilsMixin):
             if status is None:
                 # the runner has timed out
                 status = 124
 
             local_leak_file = tempfile.NamedTemporaryFile()
             self.app_ctx.dm.getFile(self.leak_report_file, local_leak_file.name)
             self.app_ctx.dm.removeFile(self.leak_report_file)
 
-            processLeakLog(local_leak_file.name, options.leakThresholds, options.ignoreMissingLeaks)
+            processLeakLog(local_leak_file.name, options)
         except KeyboardInterrupt:
             self.log.info("runtests.py | Received keyboard interrupt.\n");
             status = -1
         except:
             traceback.print_exc()
             self.log.error("Automation Error: Received unexpected exception while running application\n")
             if hasattr(self, 'runner'):
                 self.runner.check_for_crashes()
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -545,16 +545,21 @@ stage-marionette: make-stage-dir
 	$(NSINSTALL) -D $(MARIONETTE_DIR)/transport
 	@(cd $(topsrcdir)/testing/marionette/client && tar --exclude marionette/tests $(TAR_CREATE_FLAGS) - *) | (cd $(MARIONETTE_DIR)/ && tar -xf -)
 	@(cd $(topsrcdir)/testing/marionette/transport && tar $(TAR_CREATE_FLAGS) - *) | (cd $(MARIONETTE_DIR)/transport && tar -xf -)
 	$(PYTHON) $(topsrcdir)/testing/marionette/client/marionette/tests/print-manifest-dirs.py \
           $(topsrcdir) \
           $(topsrcdir)/testing/marionette/client/marionette/tests/unit-tests.ini \
           | (cd $(topsrcdir) && xargs tar $(TAR_CREATE_FLAGS) -) \
           | (cd $(MARIONETTE_DIR)/tests && tar -xf -)
+	$(PYTHON) $(topsrcdir)/testing/marionette/client/marionette/tests/print-manifest-dirs.py \
+          $(topsrcdir) \
+          $(topsrcdir)/testing/marionette/client/marionette/tests/webapi-tests.ini \
+          | (cd $(topsrcdir) && xargs tar $(TAR_CREATE_FLAGS) -) \
+          | (cd $(MARIONETTE_DIR)/tests && tar -xf -)
 
 stage-mozbase: make-stage-dir
 	$(MAKE) -C $(DEPTH)/testing/mozbase stage-package
 
 stage-web-platform-tests: make-stage-dir
 	$(MAKE) -C $(DEPTH)/testing/web-platform stage-package
 
 stage-instrumentation-tests: make-stage-dir
--- a/tools/mach_commands.py
+++ b/tools/mach_commands.py
@@ -289,17 +289,17 @@ class PastebinProvider(object):
         except urllib2.URLError:
             print('ERROR. Could not connect to pastebin.mozilla.org.')
             return 1
         return 0
 
 
 @CommandProvider
 class ReviewboardToolsProvider(MachCommandBase):
-    @Command('rbt', category='devenv', allow_all_args=True,
+    @Command('rbt', category='devenv',
         description='Run Reviewboard Tools')
     @CommandArgument('args', nargs='...', help='Arguments to rbt tool')
     def rbt(self, args):
         if not args:
             args = ['help']
 
         self._activate_virtualenv()
         self.virtualenv_manager.install_pip_package('RBTools==0.6')