Merge m-c to fx-team a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 27 Oct 2014 18:09:51 -0700
changeset 212546 def2e873550b20acc4b874484785783b96ec8245
parent 212545 0d00ee006544cdd1462f3fce34fb139722908ac0 (current diff)
parent 212523 a255a234946e56aaec852eec75c902af83df01fb (diff)
child 212547 c0e559c7fb5ae6abb35fe2a204a1146cec3cb384
push id27720
push usercbook@mozilla.com
push dateTue, 28 Oct 2014 14:51:21 +0000
treeherdermozilla-central@a2d58c6420f4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.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=merge
dom/ipc/ContentProcessManager.cpp
dom/ipc/ContentProcessManager.h
dom/ipc/IdType.h
dom/ipc/PBrowserOrId.ipdlh
layout/base/tests/marionette/test_selectioncarets_multiplerange.py
testing/marionette/client/marionette/www/test_selectioncarets_multiplerange.html
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,19 +10,19 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0888735b2c5932624808147b85a60d698d9d7352"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <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="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,18 +14,18 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <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="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,18 +12,18 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,19 +10,19 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0888735b2c5932624808147b85a60d698d9d7352"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <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="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,18 +14,18 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <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="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,19 +10,19 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0888735b2c5932624808147b85a60d698d9d7352"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <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="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,18 +12,18 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "9f4db6bcede8557cb8ac746fc977bc50bff2278b", 
+    "revision": "641fa70735be0abcf817d4a86e7ae17d5596c816", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,18 +12,18 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <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="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,18 +10,18 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="575fdbf046e966a5915b1f1e800e5d6ad0ea14c0"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,18 +12,18 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,18 +12,18 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea">
     <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="0888735b2c5932624808147b85a60d698d9d7352"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a7fb482a03c5083ef79b41e7b0dfab27527cd04"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/>
   <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="be8b952fde51d8c83748b41ce232f02b2218451d"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -230,16 +230,17 @@
 @BINPATH@/components/dom_storage.xpt
 @BINPATH@/components/dom_stylesheets.xpt
 @BINPATH@/components/dom_telephony.xpt
 @BINPATH@/components/dom_traversal.xpt
 @BINPATH@/components/dom_voicemail.xpt
 #ifdef MOZ_WEBSPEECH
 @BINPATH@/components/dom_webspeechrecognition.xpt
 #endif
+@BINPATH@/components/dom_workers.xpt
 @BINPATH@/components/dom_xbl.xpt
 @BINPATH@/components/dom_xpath.xpt
 @BINPATH@/components/dom_xul.xpt
 #ifdef MOZ_GAMEPAD
 @BINPATH@/components/dom_gamepad.xpt
 #endif
 @BINPATH@/components/dom_payment.xpt
 @BINPATH@/components/downloads.xpt
--- a/dom/apps/AppsUtils.jsm
+++ b/dom/apps/AppsUtils.jsm
@@ -103,16 +103,17 @@ function _setAppProperties(aObj, aApp) {
   aObj.installerIsBrowser = !!aApp.installerIsBrowser;
   aObj.storeId = aApp.storeId || "";
   aObj.storeVersion = aApp.storeVersion || 0;
   aObj.role = aApp.role || "";
   aObj.redirects = aApp.redirects;
   aObj.widgetPages = aApp.widgetPages || [];
   aObj.kind = aApp.kind;
   aObj.enabled = aApp.enabled !== undefined ? aApp.enabled : true;
+  aObj.sideloaded = aApp.sideloaded;
 }
 
 this.AppsUtils = {
   // Clones a app, without the manifest.
   cloneAppObject: function(aApp) {
     let obj = {};
     _setAppProperties(obj, aApp);
     return obj;
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -83,17 +83,17 @@
 #include "nsIAppsService.h"
 #include "GeckoProfiler.h"
 
 #include "jsapi.h"
 #include "mozilla/dom/HTMLIFrameElement.h"
 #include "mozilla/dom/SVGIFrameElement.h"
 #include "nsSandboxFlags.h"
 #include "JavaScriptParent.h"
-#include "CompositorChild.h"
+#include "mozilla/layers/CompositorChild.h"
 
 #include "mozilla/dom/StructuredCloneUtils.h"
 
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #endif
 
 using namespace mozilla;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -9350,40 +9350,31 @@ nsGlobalWindow::UpdateCommands(const nsA
                                                             anAction));
     }
   }
 
   if (gSelectionCaretPrefEnabled && mDoc && anAction.EqualsLiteral("selectionchange")) {
     SelectionChangeEventInit init;
     init.mBubbles = true;
     if (aSel) {
-      Selection* selection = static_cast<Selection*>(aSel);
-      int32_t rangeCount = selection->GetRangeCount();
-      nsLayoutUtils::RectAccumulator accumulator;
-      for (int32_t idx = 0; idx < rangeCount; ++idx) {
-        nsRange* range = selection->GetRangeAt(idx);
-        nsRange::CollectClientRects(&accumulator, range,
-                                    range->GetStartParent(), range->StartOffset(),
-                                    range->GetEndParent(), range->EndOffset(),
-                                    true, false);
-      }
-      nsRect rect = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect :
-        accumulator.mResultRect;
-      nsRefPtr<DOMRect> domRect = new DOMRect(ToSupports(this));
-      domRect->SetLayoutRect(rect);
-      init.mBoundingClientRect = domRect;
-
-      selection->Stringify(init.mSelectedText);
-      for (uint32_t reasonType = 0;
-           reasonType < static_cast<uint32_t>(SelectionChangeReason::EndGuard_);
-           ++reasonType) {
-        SelectionChangeReason strongReasonType =
-          static_cast<SelectionChangeReason>(reasonType);
-        if (CheckReason(aReason, strongReasonType)) {
-          init.mReasons.AppendElement(strongReasonType);
+      nsCOMPtr<nsIDOMRange> range;
+      nsresult rv = aSel->GetRangeAt(0, getter_AddRefs(range));
+      if (NS_SUCCEEDED(rv) && range) {
+        nsRefPtr<nsRange> nsrange = static_cast<nsRange*>(range.get());
+        init.mBoundingClientRect = nsrange->GetBoundingClientRect(true, false);
+        range->ToString(init.mSelectedText);
+
+        for (uint32_t reasonType = 0;
+             reasonType < static_cast<uint32_t>(SelectionChangeReason::EndGuard_);
+             ++reasonType) {
+          SelectionChangeReason strongReasonType =
+            static_cast<SelectionChangeReason>(reasonType);
+          if (CheckReason(aReason, strongReasonType)) {
+            init.mReasons.AppendElement(strongReasonType);
+          }
         }
       }
 
       nsRefPtr<SelectionChangeEvent> event =
         SelectionChangeEvent::Constructor(mDoc, NS_LITERAL_STRING("mozselectionchange"), init);
 
       event->SetTrusted(true);
       event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -110,18 +110,17 @@ MobileConnectionListener::NotifyUssdRece
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyDataError(const nsAString & message)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnectionListener::NotifyCFStateChanged(bool success,
-                                               uint16_t action,
+MobileConnectionListener::NotifyCFStateChanged(uint16_t action,
                                                uint16_t reason,
                                                const nsAString& number,
                                                uint16_t timeSeconds,
                                                uint16_t serviceClass)
 {
   return NS_OK;
 }
 
--- a/dom/bluetooth2/BluetoothRilListener.cpp
+++ b/dom/bluetooth2/BluetoothRilListener.cpp
@@ -110,18 +110,17 @@ MobileConnectionListener::NotifyUssdRece
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyDataError(const nsAString & message)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnectionListener::NotifyCFStateChanged(bool success,
-                                               uint16_t action,
+MobileConnectionListener::NotifyCFStateChanged(uint16_t action,
                                                uint16_t reason,
                                                const nsAString& number,
                                                uint16_t timeSeconds,
                                                uint16_t serviceClass)
 {
   return NS_OK;
 }
 
--- a/dom/encoding/test/unit/head.js
+++ b/dom/encoding/test/unit/head.js
@@ -83,13 +83,13 @@ let tests = [];
 
 function test(func, msg) {
   tests.push({msg: msg, func: func,
               filename: Components.stack.caller.filename });
 }
 
 function run_test() {
   tests.forEach(function(t) {
-    _log("test_info", {source_file: t.filename,
-                       diagnostic: "test group: " + t.msg});
+    do_print("test group: " + t.msg,
+             {source_file: t.filename});
     t.func();
   });
 };
--- a/dom/html/test/forms/test_input_color_picker_popup.html
+++ b/dom/html/test/forms/test_input_color_picker_popup.html
@@ -4,16 +4,17 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=885996
 -->
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 1234567</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style> label { display: block } </style>
   <script type="application/javascript;version=1.8">
 
   /** Test the behaviour of the <input type='color'> when clicking on it from
       different ways. **/
 
   SimpleTest.waitForExplicitFinish();
 
   var MockColorPicker = SpecialPowers.MockColorPicker;
--- a/dom/ipc/AppProcessChecker.cpp
+++ b/dom/ipc/AppProcessChecker.cpp
@@ -34,125 +34,89 @@ class PContentParent;
 
 class nsIPrincipal;
 #endif
 
 namespace mozilla {
 
 #ifdef MOZ_CHILD_PERMISSIONS
 
-static bool
-CheckAppTypeHelper(mozIApplication* aApp,
-                   AssertAppProcessType aType,
-                   const char* aCapability,
-                   bool aIsBrowserElement)
-{
-  bool aValid = false;
-
-  // isBrowser frames inherit their app descriptor to identify their
-  // data storage, but they don't inherit the capability associated
-  // with that descriptor.
-  if (aApp && (aType == ASSERT_APP_HAS_PERMISSION || !aIsBrowserElement)) {
-    switch (aType) {
-      case ASSERT_APP_HAS_PERMISSION:
-      case ASSERT_APP_PROCESS_PERMISSION:
-        if (!NS_SUCCEEDED(aApp->HasPermission(aCapability, &aValid))) {
-          aValid = false;
-        }
-        break;
-      case ASSERT_APP_PROCESS_MANIFEST_URL: {
-        nsAutoString manifestURL;
-        if (NS_SUCCEEDED(aApp->GetManifestURL(manifestURL)) &&
-            manifestURL.EqualsASCII(aCapability)) {
-          aValid = true;
-        }
-        break;
-      }
-      default:
-        break;
-    }
-  }
-  return aValid;
-}
-
 bool
 AssertAppProcess(PBrowserParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
   if (!aActor) {
     NS_WARNING("Testing process capability for null actor");
     return false;
   }
 
   TabParent* tab = static_cast<TabParent*>(aActor);
   nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
-
-  return CheckAppTypeHelper(app, aType, aCapability, tab->IsBrowserElement());
-}
+  bool aValid = false;
 
-static bool
-CheckAppStatusHelper(mozIApplication* aApp,
-                     unsigned short aStatus)
-{
-  bool valid = false;
-
-  if (aApp) {
-    unsigned short appStatus = 0;
-    if (NS_SUCCEEDED(aApp->GetAppStatus(&appStatus))) {
-      valid = appStatus == aStatus;
+  // isBrowser frames inherit their app descriptor to identify their
+  // data storage, but they don't inherit the capability associated
+  // with that descriptor.
+  if (app && (aType == ASSERT_APP_HAS_PERMISSION || !tab->IsBrowserElement())) {
+    switch (aType) {
+      case ASSERT_APP_HAS_PERMISSION:
+      case ASSERT_APP_PROCESS_PERMISSION:
+        if (!NS_SUCCEEDED(app->HasPermission(aCapability, &aValid))) {
+          aValid = false;
+        }
+        break;
+      case ASSERT_APP_PROCESS_MANIFEST_URL: {
+        nsAutoString manifestURL;
+        if (NS_SUCCEEDED(app->GetManifestURL(manifestURL)) &&
+            manifestURL.EqualsASCII(aCapability)) {
+          aValid = true;
+        }
+        break;
+      }
+      default:
+        break;
     }
   }
-
-  return valid;
+  return aValid;
 }
 
 bool
 AssertAppStatus(PBrowserParent* aActor,
                 unsigned short aStatus)
 {
   if (!aActor) {
     NS_WARNING("Testing process capability for null actor");
     return false;
   }
 
   TabParent* tab = static_cast<TabParent*>(aActor);
   nsCOMPtr<mozIApplication> app = tab->GetOwnOrContainingApp();
 
-  return CheckAppStatusHelper(app, aStatus);
-}
-
-bool
-AssertAppProcess(TabContext& aContext,
-                 AssertAppProcessType aType,
-                 const char* aCapability)
-{
+  bool valid = false;
 
-  nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
-  return CheckAppTypeHelper(app, aType, aCapability, aContext.IsBrowserElement());
-}
+  if (app) {
+    unsigned short appStatus = 0;
+    if (NS_SUCCEEDED(app->GetAppStatus(&appStatus))) {
+      valid = appStatus == aStatus;
+    }
+  }
 
-bool
-AssertAppStatus(TabContext& aContext,
-                unsigned short aStatus)
-{
-
-  nsCOMPtr<mozIApplication> app = aContext.GetOwnOrContainingApp();
-  return CheckAppStatusHelper(app, aStatus);
+  return valid;
 }
 
 bool
 AssertAppProcess(PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
-  nsTArray<TabContext> contextArray =
-    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
-  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
-    if (AssertAppProcess(contextArray[i], aType, aCapability)) {
+  const InfallibleTArray<PBrowserParent*>& browsers =
+    aActor->ManagedPBrowserParent();
+  for (uint32_t i = 0; i < browsers.Length(); ++i) {
+    if (AssertAppProcess(browsers[i], aType, aCapability)) {
       return true;
     }
   }
 
   NS_ERROR(
     nsPrintfCString(
       "Security problem: Content process does not have `%s'.  It will be killed.\n",
       aCapability).get());
@@ -161,20 +125,20 @@ AssertAppProcess(PContentParent* aActor,
 
   return false;
 }
 
 bool
 AssertAppStatus(PContentParent* aActor,
                 unsigned short aStatus)
 {
-  nsTArray<TabContext> contextArray =
-    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
-  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
-    if (AssertAppStatus(contextArray[i], aStatus)) {
+  const InfallibleTArray<PBrowserParent*>& browsers =
+    aActor->ManagedPBrowserParent();
+  for (uint32_t i = 0; i < browsers.Length(); ++i) {
+    if (AssertAppStatus(browsers[i], aStatus)) {
       return true;
     }
   }
 
   NS_ERROR(
     nsPrintfCString(
       "Security problem: Content process does not have `%d' status.  It will be killed.",
       aStatus).get());
@@ -201,23 +165,24 @@ AssertAppPrincipal(PContentParent* aActo
     static_cast<ContentParent*>(aActor)->KillHard();
     return false;
   }
 
   uint32_t principalAppId = aPrincipal->GetAppId();
   bool inBrowserElement = aPrincipal->GetIsInBrowserElement();
 
   // Check if the permission's appId matches a child we manage.
-  nsTArray<TabContext> contextArray =
-    static_cast<ContentParent*>(aActor)->GetManagedTabContext();
-  for (uint32_t i = 0; i < contextArray.Length(); ++i) {
-    if (contextArray[i].OwnOrContainingAppId() == principalAppId) {
+  const InfallibleTArray<PBrowserParent*>& browsers =
+    aActor->ManagedPBrowserParent();
+  for (uint32_t i = 0; i < browsers.Length(); ++i) {
+    TabParent* tab = static_cast<TabParent*>(browsers[i]);
+    if (tab->OwnOrContainingAppId() == principalAppId) {
       // If the child only runs inBrowserElement content and the principal claims
       // it's not in a browser element, it's lying.
-      if (!contextArray[i].IsBrowserElement() || inBrowserElement) {
+      if (!tab->IsBrowserElement() || inBrowserElement) {
         return true;
       }
       break;
     }
   }
 
   NS_WARNING("Principal is invalid, killing app process");
   static_cast<ContentParent*>(aActor)->KillHard();
@@ -317,31 +282,16 @@ AssertAppProcess(mozilla::dom::PBrowserP
 
 bool
 AssertAppStatus(mozilla::dom::PBrowserParent* aActor,
                 unsigned short aStatus)
 {
   return true;
 }
 
-bool
-AssertAppProcess(const mozilla::dom::TabContext& aContext,
-                 AssertAppProcessType aType,
-                 const char* aCapability)
-{
-  return true;
-}
-
-bool
-AssertAppStatus(const mozilla::dom::TabContext& aContext,
-                unsigned short aStatus)
-{
-  return true;
-}
-
 
 bool
 AssertAppProcess(mozilla::dom::PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability)
 {
   return true;
 }
--- a/dom/ipc/AppProcessChecker.h
+++ b/dom/ipc/AppProcessChecker.h
@@ -10,17 +10,16 @@
 
 #include <stdint.h>
 
 class nsIPrincipal;
 
 namespace mozilla {
 
 namespace dom {
-class TabContext;
 class PBrowserParent;
 class PContentParent;
 }
 
 namespace hal_sandbox {
 class PHalParent;
 }
 
@@ -44,34 +43,16 @@ AssertAppProcess(mozilla::dom::PBrowserP
  * Return true if the specified app has the specified status.
  * If this returns false, the browser will be killed.
  */
 bool
 AssertAppStatus(mozilla::dom::PBrowserParent* aActor,
                 unsigned short aStatus);
 
 /**
- * Return true if the specified browser has the specified capability.
- * If this returns false, the browser didn't have the capability and
- * will be killed.
- */
-bool
-AssertAppProcess(const mozilla::dom::TabContext& aContext,
-                 AssertAppProcessType aType,
-                 const char* aCapability);
-
-/**
- * Return true if the specified app has the specified status.
- * If this returns false, the browser will be killed.
- */
-bool
-AssertAppStatus(const mozilla::dom::TabContext& aContext,
-                unsigned short aStatus);
-
-/**
  * Return true if any of the PBrowsers loaded in this content process
  * has the specified capability.  If this returns false, the process
  * didn't have the capability and will be killed.
  */
 bool
 AssertAppProcess(mozilla::dom::PContentParent* aActor,
                  AssertAppProcessType aType,
                  const char* aCapability);
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -76,28 +76,26 @@ PBlobChild*
 ContentBridgeChild::SendPBlobConstructor(PBlobChild* actor,
                                          const BlobConstructorParams& params)
 {
   return PContentBridgeChild::SendPBlobConstructor(actor, params);
 }
 
 bool
 ContentBridgeChild::SendPBrowserConstructor(PBrowserChild* aActor,
-                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const ContentParentId& aCpID,
+                                            const uint64_t& aID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return PContentBridgeChild::SendPBrowserConstructor(aActor,
-                                                      aTabId,
                                                       aContext,
                                                       aChromeFlags,
-                                                      aCpID,
+                                                      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::JavaScriptShared*
@@ -118,51 +116,47 @@ ContentBridgeChild::AllocPJavaScriptChil
 
 bool
 ContentBridgeChild::DeallocPJavaScriptChild(PJavaScriptChild *child)
 {
   return nsIContentChild::DeallocPJavaScriptChild(child);
 }
 
 PBrowserChild*
-ContentBridgeChild::AllocPBrowserChild(const TabId& aTabId,
-                                       const IPCTabContext &aContext,
+ContentBridgeChild::AllocPBrowserChild(const IPCTabContext &aContext,
                                        const uint32_t& aChromeFlags,
-                                       const ContentParentId& aCpID,
+                                       const uint64_t& aID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
-  return nsIContentChild::AllocPBrowserChild(aTabId,
-                                             aContext,
+  return nsIContentChild::AllocPBrowserChild(aContext,
                                              aChromeFlags,
-                                             aCpID,
+                                             aID,
                                              aIsForApp,
                                              aIsForBrowser);
 }
 
 bool
 ContentBridgeChild::DeallocPBrowserChild(PBrowserChild* aChild)
 {
   return nsIContentChild::DeallocPBrowserChild(aChild);
 }
 
 bool
 ContentBridgeChild::RecvPBrowserConstructor(PBrowserChild* aActor,
-                                            const TabId& aTabId,
                                             const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const ContentParentId& aCpID,
+                                            const uint64_t& aID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser)
 {
   return ContentChild::GetSingleton()->RecvPBrowserConstructor(aActor,
-                                                               aTabId,
                                                                aContext,
                                                                aChromeFlags,
-                                                               aCpID,
+                                                               aID,
                                                                aIsForApp,
                                                                aIsForBrowser);
 }
 
 PBlobChild*
 ContentBridgeChild::AllocPBlobChild(const BlobConstructorParams& aParams)
 {
   return nsIContentChild::AllocPBlobChild(aParams);
--- a/dom/ipc/ContentBridgeChild.h
+++ b/dom/ipc/ContentBridgeChild.h
@@ -34,38 +34,35 @@ public:
 
   virtual PBlobChild*
   SendPBlobConstructor(PBlobChild* actor,
                        const BlobConstructorParams& params);
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
   virtual bool SendPBrowserConstructor(PBrowserChild* aActor,
-                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const ContentParentId& aCpID,
+                                       const uint64_t& aID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
 protected:
   virtual ~ContentBridgeChild();
 
-  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
-                                            const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const ContentParentId& aCpID,
+                                            const uint64_t& aID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserChild(PBrowserChild*) MOZ_OVERRIDE;
   virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
-                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const ContentParentId& aCpID,
+                                       const uint64_t& aID,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScriptChild() MOZ_OVERRIDE;
   virtual bool DeallocPJavaScriptChild(mozilla::jsipc::PJavaScriptChild*) MOZ_OVERRIDE;
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
   virtual bool DeallocPBlobChild(PBlobChild*) MOZ_OVERRIDE;
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -82,28 +82,26 @@ PBlobParent*
 ContentBridgeParent::SendPBlobConstructor(PBlobParent* actor,
                                           const BlobConstructorParams& params)
 {
   return PContentBridgeParent::SendPBlobConstructor(actor, params);
 }
 
 PBrowserParent*
 ContentBridgeParent::SendPBrowserConstructor(PBrowserParent* aActor,
-                                             const TabId& aTabId,
                                              const IPCTabContext& aContext,
                                              const uint32_t& aChromeFlags,
-                                             const ContentParentId& aCpID,
+                                             const uint64_t& aID,
                                              const bool& aIsForApp,
                                              const bool& aIsForBrowser)
 {
   return PContentBridgeParent::SendPBrowserConstructor(aActor,
-                                                       aTabId,
                                                        aContext,
                                                        aChromeFlags,
-                                                       aCpID,
+                                                       aID,
                                                        aIsForApp,
                                                        aIsForBrowser);
 }
 
 PBlobParent*
 ContentBridgeParent::AllocPBlobParent(const BlobConstructorParams& aParams)
 {
   return nsIContentParent::AllocPBlobParent(aParams);
@@ -123,27 +121,25 @@ ContentBridgeParent::AllocPJavaScriptPar
 
 bool
 ContentBridgeParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
   return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentBridgeParent::AllocPBrowserParent(const TabId& aTabId,
-                                         const IPCTabContext &aContext,
+ContentBridgeParent::AllocPBrowserParent(const IPCTabContext &aContext,
                                          const uint32_t& aChromeFlags,
-                                         const ContentParentId& aCpID,
+                                         const uint64_t& aID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser)
 {
-  return nsIContentParent::AllocPBrowserParent(aTabId,
-                                               aContext,
+  return nsIContentParent::AllocPBrowserParent(aContext,
                                                aChromeFlags,
-                                               aCpID,
+                                               aID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentBridgeParent::DeallocPBrowserParent(PBrowserParent* aParent)
 {
   return nsIContentParent::DeallocPBrowserParent(aParent);
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -4,17 +4,16 @@
  * 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_ContentBridgeParent_h
 #define mozilla_dom_ContentBridgeParent_h
 
 #include "mozilla/dom/PContentBridgeParent.h"
 #include "mozilla/dom/nsIContentParent.h"
-#include "mozilla/dom/ipc/IdType.h"
 
 namespace mozilla {
 namespace dom {
 
 class ContentBridgeParent : public PContentBridgeParent
                           , public nsIContentParent
 {
 public:
@@ -29,42 +28,41 @@ public:
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
   virtual PBlobParent*
   SendPBlobConstructor(PBlobParent* actor,
                        const BlobConstructorParams& params) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* aActor,
-                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
-                          const ContentParentId& aCpID,
+                          const uint64_t& aID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) MOZ_OVERRIDE;
 
   jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
-  virtual ContentParentId ChildID() MOZ_OVERRIDE
+  virtual uint64_t ChildID() MOZ_OVERRIDE
   {
     return mChildID;
   }
   virtual bool IsForApp() MOZ_OVERRIDE
   {
     return mIsForApp;
   }
   virtual bool IsForBrowser() MOZ_OVERRIDE
   {
     return mIsForBrowser;
   }
 
 protected:
   virtual ~ContentBridgeParent();
 
-  void SetChildID(ContentParentId aId)
+  void SetChildID(uint64_t aId)
   {
     mChildID = aId;
   }
   void SetIsForApp(bool aIsForApp)
   {
     mIsForApp = aIsForApp;
   }
   void SetIsForBrowser(bool aIsForBrowser)
@@ -83,35 +81,34 @@ protected:
                                 const InfallibleTArray<jsipc::CpowEntry>& aCpows,
                                 const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
   virtual jsipc::PJavaScriptParent* AllocPJavaScriptParent() MOZ_OVERRIDE;
   virtual bool
   DeallocPJavaScriptParent(jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
   virtual PBrowserParent*
-  AllocPBrowserParent(const TabId& aTabId,
-                      const IPCTabContext &aContext,
+  AllocPBrowserParent(const IPCTabContext &aContext,
                       const uint32_t& aChromeFlags,
-                      const ContentParentId& aCpID,
+                      const uint64_t& aID,
                       const bool& aIsForApp,
                       const bool& aIsForBrowser) MOZ_OVERRIDE;
   virtual bool DeallocPBrowserParent(PBrowserParent*) MOZ_OVERRIDE;
 
   virtual PBlobParent*
   AllocPBlobParent(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
 
   virtual bool DeallocPBlobParent(PBlobParent*) MOZ_OVERRIDE;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentBridgeParent);
 
 protected: // members
   nsRefPtr<ContentBridgeParent> mSelfRef;
   Transport* mTransport; // owned
-  ContentParentId mChildID;
+  uint64_t mChildID;
   bool mIsForApp;
   bool mIsForBrowser;
 
 private:
   friend class ContentParent;
 };
 
 } // dom
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1104,55 +1104,50 @@ ContentChild::AllocPJavaScriptChild()
 
 bool
 ContentChild::DeallocPJavaScriptChild(PJavaScriptChild *aChild)
 {
     return nsIContentChild::DeallocPJavaScriptChild(aChild);
 }
 
 PBrowserChild*
-ContentChild::AllocPBrowserChild(const TabId& aTabId,
-                                 const IPCTabContext& aContext,
+ContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
                                  const uint32_t& aChromeFlags,
-                                 const ContentParentId& aCpID,
+                                 const uint64_t& aID,
                                  const bool& aIsForApp,
                                  const bool& aIsForBrowser)
 {
-    return nsIContentChild::AllocPBrowserChild(aTabId,
-                                               aContext,
+    return nsIContentChild::AllocPBrowserChild(aContext,
                                                aChromeFlags,
-                                               aCpID,
+                                               aID,
                                                aIsForApp,
                                                aIsForBrowser);
 }
 
 bool
 ContentChild::SendPBrowserConstructor(PBrowserChild* aActor,
-                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const ContentParentId& aCpID,
+                                      const uint64_t& aID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     return PContentChild::SendPBrowserConstructor(aActor,
-                                                  aTabId,
                                                   aContext,
                                                   aChromeFlags,
-                                                  aCpID,
+                                                  aID,
                                                   aIsForApp,
                                                   aIsForBrowser);
 }
 
 bool
 ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor,
-                                      const TabId& aTabId,
                                       const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const ContentParentId& aCpID,
+                                      const uint64_t& aID,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
     // This runs after AllocPBrowserChild() returns and the IPC machinery for this
     // PBrowserChild has been set up.
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     if (os) {
@@ -1166,17 +1161,17 @@ ContentChild::RecvPBrowserConstructor(PB
         hasRunOnce = true;
 
         MOZ_ASSERT(!sFirstIdleTask);
         sFirstIdleTask = NewRunnableFunction(FirstIdle);
         MessageLoop::current()->PostIdleTask(FROM_HERE, sFirstIdleTask);
 
         // Redo InitProcessAttributes() when the app or browser is really
         // launching so the attributes will be correct.
-        mID = aCpID;
+        mID = aID;
         mIsForApp = aIsForApp;
         mIsForBrowser = aIsForBrowser;
         InitProcessAttributes();
     }
 
     return true;
 }
 
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -126,20 +126,19 @@ public:
 #endif
 
     virtual bool RecvSetProcessSandbox() MOZ_OVERRIDE;
 
     PBackgroundChild*
     AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess)
                           MOZ_OVERRIDE;
 
-    virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
-                                              const IPCTabContext& aContext,
+    virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
-                                              const ContentParentId& aCpID,
+                                              const uint64_t& aID,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
     virtual bool DeallocPBrowserChild(PBrowserChild*);
 
     virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequestChild(const DeviceStorageParams&);
     virtual bool DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*);
 
     virtual PFileSystemRequestChild* AllocPFileSystemRequestChild(const FileSystemParams&);
@@ -350,44 +349,42 @@ public:
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
 
     // Get the directory for IndexedDB files. We query the parent for this and
     // cache the value
     nsString &GetIndexedDBPath();
 
-    ContentParentId GetID() { return mID; }
+    uint64_t GetID() { return mID; }
 
     bool IsForApp() { return mIsForApp; }
     bool IsForBrowser() { return mIsForBrowser; }
 
     virtual PBlobChild*
     SendPBlobConstructor(PBlobChild* actor,
                          const BlobConstructorParams& params) MOZ_OVERRIDE;
 
     virtual PFileDescriptorSetChild*
     AllocPFileDescriptorSetChild(const FileDescriptor&) MOZ_OVERRIDE;
 
     virtual bool
     DeallocPFileDescriptorSetChild(PFileDescriptorSetChild*) MOZ_OVERRIDE;
 
     virtual bool SendPBrowserConstructor(PBrowserChild* actor,
-                                         const TabId& aTabId,
                                          const IPCTabContext& context,
                                          const uint32_t& chromeFlags,
-                                         const ContentParentId& aCpID,
+                                         const uint64_t& aID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
 
     virtual bool RecvPBrowserConstructor(PBrowserChild* aCctor,
-                                         const TabId& aTabId,
                                          const IPCTabContext& aContext,
                                          const uint32_t& aChromeFlags,
-                                         const ContentParentId& aCpID,
+                                         const uint64_t& aID,
                                          const bool& aIsForApp,
                                          const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual PDocAccessibleChild* AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) MOZ_OVERRIDE;
     virtual bool DeallocPDocAccessibleChild(PDocAccessibleChild*) MOZ_OVERRIDE;
 
     void GetAvailableDictionaries(InfallibleTArray<nsString>& aDictionaries);
 
 private:
@@ -410,17 +407,17 @@ private:
 
     /**
      * An ID unique to the process containing our corresponding
      * content parent.
      *
      * We expect our content parent to set this ID immediately after opening a
      * channel to us.
      */
-    ContentParentId mID;
+    uint64_t mID;
 
     AppInfo mAppInfo;
 
 #ifdef ANDROID
     gfxIntSize mScreenSize;
 #endif
 
     bool mIsForApp;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -126,17 +126,16 @@
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "gfxPrefs.h"
 #include "prio.h"
 #include "private/pprio.h"
-#include "ContentProcessManager.h"
 
 #if defined(ANDROID) || defined(LINUX)
 #include "nsSystemInfo.h"
 #endif
 
 #if defined(XP_LINUX)
 #include "mozilla/Hal.h"
 #endif
@@ -841,24 +840,27 @@ ContentParent::PreallocatedProcessReady(
 {
 #ifdef MOZ_NUWA_PROCESS
     return PreallocatedProcessManager::PreallocatedProcessReady();
 #else
     return true;
 #endif
 }
 
+typedef std::map<ContentParent*, std::set<ContentParent*> > GrandchildMap;
+static GrandchildMap sGrandchildProcessMap;
+
+std::map<uint64_t, ContentParent*> sContentParentMap;
+
 bool
 ContentParent::RecvCreateChildProcess(const IPCTabContext& aContext,
                                       const hal::ProcessPriority& aPriority,
-                                      const TabId& aOpenerTabId,
-                                      ContentParentId* aCpId,
+                                      uint64_t* aId,
                                       bool* aIsForApp,
-                                      bool* aIsForBrowser,
-                                      TabId* aTabId)
+                                      bool* aIsForBrowser)
 {
 #if 0
     if (!CanOpenBrowser(aContext)) {
         return false;
     }
 #endif
     nsRefPtr<ContentParent> cp;
     MaybeInvalidTabContext tc(aContext);
@@ -877,143 +879,114 @@ ContentParent::RecvCreateChildProcess(co
     }
     else {
         cp = GetNewOrUsedBrowserProcess(/* isBrowserElement = */ true,
                                         aPriority,
                                         this);
     }
 
     if (!cp) {
-        *aCpId = 0;
+        *aId = 0;
         *aIsForApp = false;
         *aIsForBrowser = false;
         return true;
     }
 
-    *aCpId = cp->ChildID();
+    *aId = cp->ChildID();
     *aIsForApp = cp->IsForApp();
     *aIsForBrowser = cp->IsForBrowser();
-
-    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
-    cpm->AddContentProcess(cp, this->ChildID());
-
-    if (cpm->AddGrandchildProcess(this->ChildID(), cp->ChildID())) {
-        // Pre-allocate a TabId here to save one time IPC call at app startup.
-        *aTabId = AllocateTabId(aOpenerTabId,
-                                aContext,
-                                cp->ChildID());
-        return (*aTabId != 0);
+    sContentParentMap[*aId] = cp;
+    auto iter = sGrandchildProcessMap.find(this);
+    if (iter == sGrandchildProcessMap.end()) {
+        std::set<ContentParent*> children;
+        children.insert(cp);
+        sGrandchildProcessMap[this] = children;
+    } else {
+        iter->second.insert(cp);
     }
-
-    return false;
+    return true;
 }
 
 bool
-ContentParent::AnswerBridgeToChildProcess(const ContentParentId& aCpId)
+ContentParent::AnswerBridgeToChildProcess(const uint64_t& id)
 {
-    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
-    ContentParent* cp = cpm->GetContentProcessById(aCpId);
-
-    if (cp) {
-        ContentParentId parentId;
-        if (cpm->GetParentProcessId(cp->ChildID(), &parentId) &&
-            parentId == this->ChildID()) {
-            return PContentBridge::Bridge(this, cp);
-        }
+    ContentParent* cp = sContentParentMap[id];
+    auto iter = sGrandchildProcessMap.find(this);
+    if (iter != sGrandchildProcessMap.end() &&
+        iter->second.find(cp) != iter->second.end()) {
+        return PContentBridge::Bridge(this, cp);
+    } else {
+        // You can't bridge to a process you didn't open!
+        KillHard();
+        return false;
     }
-
-    // You can't bridge to a process you didn't open!
-    KillHard();
-    return false;
-}
-
-static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement)
-{
-    // Propagate the private-browsing status of the element's parent
-    // docshell to the remote docshell, via the chrome flags.
-    nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
-    MOZ_ASSERT(frameElement);
-    nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
-    if (!win) {
-        NS_WARNING("Remote frame has no window");
-        return nullptr;
-    }
-    nsIDocShell* docShell = win->GetDocShell();
-    if (!docShell) {
-        NS_WARNING("Remote frame has no docshell");
-        return nullptr;
-    }
-
-    return docShell;
 }
 
 /*static*/ TabParent*
 ContentParent::CreateBrowserOrApp(const TabContext& aContext,
                                   Element* aFrameElement,
                                   ContentParent* aOpenerContentParent)
 {
     if (!sCanLaunchSubprocesses) {
         return nullptr;
     }
 
     ProcessPriority initialPriority = GetInitialProcessPriority(aFrameElement);
     bool isInContentProcess = (XRE_GetProcessType() != GeckoProcessType_Default);
-    TabId tabId;
-
-    nsIDocShell* docShell = GetOpenerDocShellHelper(aFrameElement);
-    TabId openerTabId;
-    if (docShell) {
-        openerTabId = TabParent::GetTabIdFrom(docShell);
-    }
 
     if (aContext.IsBrowserElement() || !aContext.HasOwnApp()) {
         nsRefPtr<TabParent> tp;
         nsRefPtr<nsIContentParent> constructorSender;
         if (isInContentProcess) {
             MOZ_ASSERT(aContext.IsBrowserElement());
-            constructorSender = CreateContentBridgeParent(aContext,
-                                                          initialPriority,
-                                                          openerTabId,
-                                                          &tabId);
+            constructorSender =
+                CreateContentBridgeParent(aContext, initialPriority);
         } else {
-            if (aOpenerContentParent) {
-                constructorSender = aOpenerContentParent;
-            } else {
-                constructorSender =
-                    GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
-                                               initialPriority);
-            }
-            tabId = AllocateTabId(openerTabId,
-                                  aContext.AsIPCTabContext(),
-                                  constructorSender->ChildID());
+          if (aOpenerContentParent) {
+            constructorSender = aOpenerContentParent;
+          } else {
+            constructorSender =
+                GetNewOrUsedBrowserProcess(aContext.IsBrowserElement(),
+                                           initialPriority);
+          }
         }
         if (constructorSender) {
             uint32_t chromeFlags = 0;
 
+            // Propagate the private-browsing status of the element's parent
+            // docshell to the remote docshell, via the chrome flags.
+            nsCOMPtr<Element> frameElement = do_QueryInterface(aFrameElement);
+            MOZ_ASSERT(frameElement);
+            nsPIDOMWindow* win = frameElement->OwnerDoc()->GetWindow();
+            if (!win) {
+                NS_WARNING("Remote frame has no window");
+                return nullptr;
+            }
+            nsIDocShell* docShell = win->GetDocShell();
+            if (!docShell) {
+                NS_WARNING("Remote frame has no docshell");
+                return nullptr;
+            }
             nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
             if (loadContext && loadContext->UsePrivateBrowsing()) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
             }
             bool affectLifetime;
             docShell->GetAffectPrivateSessionLifetime(&affectLifetime);
             if (affectLifetime) {
                 chromeFlags |= nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME;
             }
 
-            if (tabId == 0) {
-                return nullptr;
-            }
-            nsRefPtr<TabParent> tp(new TabParent(constructorSender, tabId,
+            nsRefPtr<TabParent> tp(new TabParent(constructorSender,
                                                  aContext, chromeFlags));
             tp->SetOwnerElement(aFrameElement);
 
             PBrowserParent* browser = constructorSender->SendPBrowserConstructor(
                 // DeallocPBrowserParent() releases this ref.
                 tp.forget().take(),
-                tabId,
                 aContext.AsIPCTabContext(),
                 chromeFlags,
                 constructorSender->ChildID(),
                 constructorSender->IsForApp(),
                 constructorSender->IsForBrowser());
             return static_cast<TabParent*>(browser);
         }
         return nullptr;
@@ -1023,20 +996,17 @@ ContentParent::CreateBrowserOrApp(const 
     // shouldn't be null, because we otherwise would have gone into the
     // !HasOwnApp() branch above.
     nsRefPtr<nsIContentParent> parent;
     bool reused = false;
     bool tookPreallocated = false;
     nsAutoString manifestURL;
 
     if (isInContentProcess) {
-      parent = CreateContentBridgeParent(aContext,
-                                         initialPriority,
-                                         openerTabId,
-                                         &tabId);
+      parent = CreateContentBridgeParent(aContext, initialPriority);
     }
     else {
         nsCOMPtr<mozIApplication> ownApp = aContext.GetOwnApp();
 
         if (!sAppContentParents) {
             sAppContentParents =
                 new nsDataHashtable<nsStringHashKey, ContentParent*>();
         }
@@ -1074,19 +1044,16 @@ ContentParent::CreateBrowserOrApp(const 
                 if (app &&
                     NS_SUCCEEDED(app->GetAppStatus(&appStatus)) &&
                     appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
                     parentApp &&
                     NS_SUCCEEDED(parentApp->GetAppStatus(&parentAppStatus)) &&
                     parentAppStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
                     // Check if we can re-use the process of the parent app.
                     p = sAppContentParents->Get(parentAppManifestURL);
-                    tabId = AllocateTabId(openerTabId,
-                                          aContext.AsIPCTabContext(),
-                                          p->ChildID());
                 }
             }
         }
 
         if (p) {
             // Check that the process is still alive and set its priority.
             // Hopefully the process won't die after this point, if this call
             // succeeds.
@@ -1098,35 +1065,31 @@ ContentParent::CreateBrowserOrApp(const 
         reused = !!p;
         if (!p) {
             p = GetNewOrPreallocatedAppProcess(ownApp,
                                                initialPriority,
                                                nullptr,
                                                &tookPreallocated);
             MOZ_ASSERT(p);
             sAppContentParents->Put(manifestURL, p);
-            tabId = AllocateTabId(openerTabId,
-                                  aContext.AsIPCTabContext(),
-                                  p->ChildID());
         }
         parent = static_cast<nsIContentParent*>(p);
     }
 
-    if (!parent || (tabId == 0)) {
+    if (!parent) {
         return nullptr;
     }
 
     uint32_t chromeFlags = 0;
 
-    nsRefPtr<TabParent> tp = new TabParent(parent, tabId, aContext, chromeFlags);
+    nsRefPtr<TabParent> tp = new TabParent(parent, aContext, chromeFlags);
     tp->SetOwnerElement(aFrameElement);
     PBrowserParent* browser = parent->SendPBrowserConstructor(
         // DeallocPBrowserParent() releases this ref.
         nsRefPtr<TabParent>(tp).forget().take(),
-        tabId,
         aContext.AsIPCTabContext(),
         chromeFlags,
         parent->ChildID(),
         parent->IsForApp(),
         parent->IsForBrowser());
 
     if (isInContentProcess) {
         // Just return directly without the following check in content process.
@@ -1159,43 +1122,37 @@ ContentParent::CreateBrowserOrApp(const 
 
     parent->AsContentParent()->MaybeTakeCPUWakeLock(aFrameElement);
 
     return static_cast<TabParent*>(browser);
 }
 
 /*static*/ ContentBridgeParent*
 ContentParent::CreateContentBridgeParent(const TabContext& aContext,
-                                         const hal::ProcessPriority& aPriority,
-                                         const TabId& aOpenerTabId,
-                                         /*out*/ TabId* aTabId)
+                                         const hal::ProcessPriority& aPriority)
 {
-    MOZ_ASSERT(aTabId);
-
     ContentChild* child = ContentChild::GetSingleton();
-    ContentParentId cpId;
+    uint64_t id;
     bool isForApp;
     bool isForBrowser;
     if (!child->SendCreateChildProcess(aContext.AsIPCTabContext(),
                                        aPriority,
-                                       aOpenerTabId,
-                                       &cpId,
+                                       &id,
                                        &isForApp,
-                                       &isForBrowser,
-                                       aTabId)) {
+                                       &isForBrowser)) {
         return nullptr;
     }
-    if (cpId == 0) {
+    if (id == 0) {
         return nullptr;
     }
-    if (!child->CallBridgeToChildProcess(cpId)) {
+    if (!child->CallBridgeToChildProcess(id)) {
         return nullptr;
     }
     ContentBridgeParent* parent = child->GetLastBridge();
-    parent->SetChildID(cpId);
+    parent->SetChildID(id);
     parent->SetIsForApp(isForApp);
     parent->SetIsForBrowser(isForBrowser);
     return parent;
 }
 
 void
 ContentParent::GetAll(nsTArray<ContentParent*>& aArray)
 {
@@ -1514,16 +1471,23 @@ ContentParent::MarkAsDead()
         sPrivateContent->RemoveElement(this);
         if (!sPrivateContent->Length()) {
             delete sPrivateContent;
             sPrivateContent = nullptr;
         }
     }
 
     mIsAlive = false;
+
+    sGrandchildProcessMap.erase(this);
+    for (auto iter = sGrandchildProcessMap.begin();
+         iter != sGrandchildProcessMap.end();
+         iter++) {
+        iter->second.erase(this);
+    }
 }
 
 void
 ContentParent::OnChannelError()
 {
     nsRefPtr<ContentParent> content(this);
 #ifdef MOZ_NUWA_PROCESS
     // Handle app or Nuwa process exit before normal channel error handling.
@@ -1751,27 +1715,27 @@ ContentParent::ActorDestroy(ActorDestroy
     // |this|.  If so, when we go out of scope here, we're deleted and
     // all hell breaks loose.
     //
     // This runnable ensures that a reference to |this| lives on at
     // least until after the current task finishes running.
     NS_DispatchToCurrentThread(new DelayedDeleteContentParentTask(this));
 
     // Destroy any processes created by this ContentParent
-    ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
-    nsTArray<ContentParentId> childIDArray =
-        cpm->GetAllChildProcessById(this->ChildID());
-    for(uint32_t i = 0; i < childIDArray.Length(); i++) {
-        ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]);
-        MessageLoop::current()->PostTask(
-            FROM_HERE,
-            NewRunnableMethod(cp, &ContentParent::ShutDownProcess,
-                              /* closeWithError */ false));
+    auto iter = sGrandchildProcessMap.find(this);
+    if (iter != sGrandchildProcessMap.end()) {
+        for(auto child = iter->second.begin();
+            child != iter->second.end();
+            child++) {
+            MessageLoop::current()->PostTask(
+                FROM_HERE,
+                NewRunnableMethod(*child, &ContentParent::ShutDownProcess,
+                                  /* closeWithError */ false));
+        }
     }
-    cpm->RemoveContentProcess(this->ChildID());
 }
 
 void
 ContentParent::NotifyTabDestroying(PBrowserParent* aTab)
 {
     // There can be more than one PBrowser for a given app process
     // because of popup windows.  PBrowsers can also destroy
     // concurrently.  When all the PBrowsers are destroying, kick off
@@ -1924,18 +1888,16 @@ ContentParent::ContentParent(mozIApplica
     }
     mSubprocess->LaunchAndWaitForProcessHandle(extraArgs);
 
     Open(mSubprocess->GetChannel(), mSubprocess->GetOwnedChildProcessHandle());
 
     InitInternal(aInitialPriority,
                  true, /* Setup off-main thread compositing */
                  true  /* Send registered chrome */);
-
-    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static const mozilla::ipc::FileDescriptor*
 FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
                         ProtocolId aProtoId)
 {
     for (unsigned int i = 0; i < aFds.Length(); i++) {
@@ -2003,18 +1965,16 @@ ContentParent::ContentParent(ContentPare
         priority = PROCESS_PRIORITY_PREALLOC;
     } else {
         priority = PROCESS_PRIORITY_FOREGROUND;
     }
 
     InitInternal(priority,
                  false, /* Setup Off-main thread compositing */
                  false  /* Send registered chrome */);
-
-    ContentProcessManager::GetSingleton()->AddContentProcess(this);
 }
 #endif  // MOZ_NUWA_PROCESS
 
 ContentParent::~ContentParent()
 {
     if (mForceKillTask) {
         mForceKillTask->Cancel();
     }
@@ -2815,20 +2775,20 @@ ContentParent::AllocPBackgroundParent(Tr
 PSharedBufferManagerParent*
 ContentParent::AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTransport,
                                                 base::ProcessId aOtherProcess)
 {
     return SharedBufferManagerParent::Create(aTransport, aOtherProcess);
 }
 
 bool
-ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
+ContentParent::RecvGetProcessAttributes(uint64_t* aId,
                                         bool* aIsForApp, bool* aIsForBrowser)
 {
-    *aCpId = mChildID;
+    *aId = mChildID;
     *aIsForApp = IsForApp();
     *aIsForBrowser = mIsForBrowser;
 
     return true;
 }
 
 bool
 ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
@@ -2866,27 +2826,25 @@ ContentParent::AllocPJavaScriptParent()
 
 bool
 ContentParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
 {
     return nsIContentParent::DeallocPJavaScriptParent(parent);
 }
 
 PBrowserParent*
-ContentParent::AllocPBrowserParent(const TabId& aTabId,
-                                   const IPCTabContext& aContext,
+ContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
                                    const uint32_t& aChromeFlags,
-                                   const ContentParentId& aCpId,
+                                   const uint64_t& aId,
                                    const bool& aIsForApp,
                                    const bool& aIsForBrowser)
 {
-    return nsIContentParent::AllocPBrowserParent(aTabId,
-                                                 aContext,
+    return nsIContentParent::AllocPBrowserParent(aContext,
                                                  aChromeFlags,
-                                                 aCpId,
+                                                 aId,
                                                  aIsForApp,
                                                  aIsForBrowser);
 }
 
 bool
 ContentParent::DeallocPBrowserParent(PBrowserParent* frame)
 {
     return nsIContentParent::DeallocPBrowserParent(frame);
@@ -3862,28 +3820,26 @@ bool
 ContentParent::RecvSystemMessageHandled()
 {
     SystemMessageHandledListener::OnSystemMessageHandled();
     return true;
 }
 
 PBrowserParent*
 ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
-                                       const TabId& aTabId,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
-                                       const ContentParentId& aCpId,
+                                       const uint64_t& aId,
                                        const bool& aIsForApp,
                                        const bool& aIsForBrowser)
 {
     return PContentParent::SendPBrowserConstructor(aActor,
-                                                   aTabId,
                                                    aContext,
                                                    aChromeFlags,
-                                                   aCpId,
+                                                   aId,
                                                    aIsForApp,
                                                    aIsForBrowser);
 }
 
 bool
 ContentParent::RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint)
 {
 #ifdef MOZ_WIDGET_GONK
@@ -4172,76 +4128,16 @@ ContentParent::NotifyUpdatedDictionaries
     InfallibleTArray<nsString> dictionaries;
     spellChecker->GetDictionaryList(&dictionaries);
 
     for (size_t i = 0; i < processes.Length(); ++i) {
         unused << processes[i]->SendUpdateDictionaryList(dictionaries);
     }
 }
 
-/*static*/ TabId
-ContentParent::AllocateTabId(const TabId& aOpenerTabId,
-                             const IPCTabContext& aContext,
-                             const ContentParentId& aCpId)
-{
-    TabId tabId;
-    if (XRE_GetProcessType() == GeckoProcessType_Default) {
-        ContentProcessManager *cpm = ContentProcessManager::GetSingleton();
-        tabId = cpm->AllocateTabId(aOpenerTabId, aContext, aCpId);
-    }
-    else {
-        ContentChild::GetSingleton()->SendAllocateTabId(aOpenerTabId,
-                                                        aContext,
-                                                        aCpId,
-                                                        &tabId);
-    }
-    return tabId;
-}
-
-/*static*/ void
-ContentParent::DeallocateTabId(const TabId& aTabId,
-                               const ContentParentId& aCpId)
-{
-    if (XRE_GetProcessType() == GeckoProcessType_Default) {
-        ContentProcessManager::GetSingleton()->DeallocateTabId(aCpId,
-                                                               aTabId);
-    }
-    else {
-        ContentChild::GetSingleton()->SendDeallocateTabId(aTabId);
-    }
-}
-
-bool
-ContentParent::RecvAllocateTabId(const TabId& aOpenerTabId,
-                                 const IPCTabContext& aContext,
-                                 const ContentParentId& aCpId,
-                                 TabId* aTabId)
-{
-    *aTabId = AllocateTabId(aOpenerTabId, aContext, aCpId);
-    if (!(*aTabId)) {
-        return false;
-    }
-    return true;
-}
-
-bool
-ContentParent::RecvDeallocateTabId(const TabId& aTabId)
-{
-    DeallocateTabId(aTabId, this->ChildID());
-    return true;
-}
-
-nsTArray<TabContext>
-ContentParent::GetManagedTabContext()
-{
-    return Move(ContentProcessManager::GetSingleton()->
-        GetTabContextByContentProcess(this->ChildID()));
-}
-
-
 } // namespace dom
 } // namespace mozilla
 
 NS_IMPL_ISUPPORTS(ParentIdleListener, nsIObserver)
 
 NS_IMETHODIMP
 ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) {
     mozilla::unused << mParent->SendNotifyIdleObserver(mObserver,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -138,22 +138,20 @@ public:
     static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
     static bool IgnoreIPCPrincipal();
 
     static void NotifyUpdatedDictionaries();
 
     virtual bool RecvCreateChildProcess(const IPCTabContext& aContext,
                                         const hal::ProcessPriority& aPriority,
-                                        const TabId& aOpenerTabId,
-                                        ContentParentId* aCpId,
+                                        uint64_t* aId,
                                         bool* aIsForApp,
-                                        bool* aIsForBrowser,
-                                        TabId* aTabId) MOZ_OVERRIDE;
-    virtual bool AnswerBridgeToChildProcess(const ContentParentId& aCpId) MOZ_OVERRIDE;
+                                        bool* aIsForBrowser) MOZ_OVERRIDE;
+    virtual bool AnswerBridgeToChildProcess(const uint64_t& id) MOZ_OVERRIDE;
 
     NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
 
     /**
@@ -176,23 +174,16 @@ public:
     void NotifyTabDestroyed(PBrowserParent* aTab,
                             bool aNotifiedDestroying);
 
     TestShellParent* CreateTestShell();
     bool DestroyTestShell(TestShellParent* aTestShell);
     TestShellParent* GetTestShellSingleton();
     jsipc::JavaScriptShared* GetCPOWManager() MOZ_OVERRIDE;
 
-    static TabId
-    AllocateTabId(const TabId& aOpenerTabId,
-                  const IPCTabContext& aContext,
-                  const ContentParentId& aCpId);
-    static void
-    DeallocateTabId(const TabId& aTabId, const ContentParentId& aCpId);
-
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
     virtual bool IsForApp() MOZ_OVERRIDE;
     virtual bool IsForBrowser() MOZ_OVERRIDE
     {
       return mIsForBrowser;
@@ -221,17 +212,17 @@ public:
 
     /**
      * Kill our subprocess and make sure it dies.  Should only be used
      * in emergency situations since it bypasses the normal shutdown
      * process.
      */
     void KillHard();
 
-    ContentParentId ChildID() MOZ_OVERRIDE { return mChildID; }
+    uint64_t ChildID() MOZ_OVERRIDE { return mChildID; }
     const nsString& AppManifestURL() const { return mAppManifestURL; }
 
     bool IsPreallocated();
 
     /**
      * Get a user-friendly name for this ContentParent.  We make no guarantees
      * about this name: It might not be unique, apps can spoof special names,
      * etc.  So please don't use this name to make any decisions about the
@@ -286,24 +277,16 @@ public:
     bool CycleCollectWithLogs(bool aDumpAllTraces,
                               nsICycleCollectorLogSink* aSink,
                               nsIDumpGCAndCCLogsCallback* aCallback);
 
     virtual PBlobParent* SendPBlobConstructor(
         PBlobParent* aActor,
         const BlobConstructorParams& aParams) MOZ_OVERRIDE;
 
-    virtual bool RecvAllocateTabId(const TabId& aOpenerTabId,
-                                   const IPCTabContext& aContext,
-                                   const ContentParentId& aCpId,
-                                   TabId* aTabId) MOZ_OVERRIDE;
-
-    virtual bool RecvDeallocateTabId(const TabId& aTabId) MOZ_OVERRIDE;
-
-    nsTArray<TabContext> GetManagedTabContext();
 protected:
     void OnChannelConnected(int32_t pid) MOZ_OVERRIDE;
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
 
 private:
@@ -322,28 +305,25 @@ private:
     GetNewOrPreallocatedAppProcess(mozIApplication* aApp,
                                    hal::ProcessPriority aInitialPriority,
                                    ContentParent* aOpener,
                                    /*out*/ bool* aTookPreAllocated = nullptr);
 
     static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
 
     static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext,
-                                                          const hal::ProcessPriority& aPriority,
-                                                          const TabId& aOpenerTabId,
-                                                          /*out*/ TabId* aTabId);
+                                                          const hal::ProcessPriority& aPriority);
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     virtual PBrowserParent* SendPBrowserConstructor(
         PBrowserParent* actor,
-        const TabId& aTabId,
         const IPCTabContext& context,
         const uint32_t& chromeFlags,
-        const ContentParentId& aCpId,
+        const uint64_t& aId,
         const bool& aIsForApp,
         const bool& aIsForBrowser) MOZ_OVERRIDE;
     using PContentParent::SendPTestShellConstructor;
 
     // No more than one of !!aApp, aIsForBrowser, and aIsForPreallocated may be
     // true.
     ContentParent(mozIApplication* aApp,
                   ContentParent* aOpener,
@@ -424,31 +404,30 @@ private:
 
     PSharedBufferManagerParent*
     AllocPSharedBufferManagerParent(mozilla::ipc::Transport* aTranport,
                                      base::ProcessId aOtherProcess) MOZ_OVERRIDE;
     PBackgroundParent*
     AllocPBackgroundParent(Transport* aTransport, ProcessId aOtherProcess)
                            MOZ_OVERRIDE;
 
-    virtual bool RecvGetProcessAttributes(ContentParentId* aCpId,
+    virtual bool RecvGetProcessAttributes(uint64_t* aId,
                                           bool* aIsForApp,
                                           bool* aIsForBrowser) MOZ_OVERRIDE;
     virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
                                                InfallibleTArray<nsString>* dictionaries,
                                                ClipboardCapabilities* clipboardCaps)
         MOZ_OVERRIDE;
 
     virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*) MOZ_OVERRIDE;
 
     virtual bool DeallocPRemoteSpellcheckEngineParent(PRemoteSpellcheckEngineParent*) MOZ_OVERRIDE;
-    virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
-                                                const IPCTabContext& aContext,
+    virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
                                                 const uint32_t& aChromeFlags,
-                                                const ContentParentId& aCpId,
+                                                const uint64_t& aId,
                                                 const bool& aIsForApp,
                                                 const bool& aIsForBrowser) MOZ_OVERRIDE;
     virtual bool DeallocPBrowserParent(PBrowserParent* frame) MOZ_OVERRIDE;
 
     virtual PDeviceStorageRequestParent*
     AllocPDeviceStorageRequestParent(const DeviceStorageParams&) MOZ_OVERRIDE;
     virtual bool DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) MOZ_OVERRIDE;
 
@@ -708,17 +687,17 @@ private:
 
     // If you add strong pointers to cycle collected objects here, be sure to
     // release these objects in ShutDownProcess.  See the comment there for more
     // details.
 
     GeckoChildProcessHost* mSubprocess;
     ContentParent* mOpener;
 
-    ContentParentId mChildID;
+    uint64_t mChildID;
     int32_t mGeolocationWatchID;
 
     nsString mAppManifestURL;
 
     /**
      * We cache mAppName instead of looking it up using mAppManifestURL when we
      * need it because it turns out that getting an app from the apps service is
      * expensive.
deleted file mode 100644
--- a/dom/ipc/ContentProcessManager.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et ft=cpp : */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "ContentProcessManager.h"
-#include "ContentParent.h"
-
-#include "mozilla/StaticPtr.h"
-#include "mozilla/ClearOnShutdown.h"
-
-#include "nsPrintfCString.h"
-
-// XXX need another bug to move this to a common header.
-#ifdef DISABLE_ASSERTS_FOR_FUZZING
-#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
-#else
-#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
-#endif
-
-namespace mozilla {
-namespace dom {
-
-static uint64_t gTabId = 0;
-
-/* static */
-StaticAutoPtr<ContentProcessManager>
-ContentProcessManager::sSingleton;
-
-/* static */ ContentProcessManager*
-ContentProcessManager::GetSingleton()
-{
-  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
-
-  if (!sSingleton) {
-    sSingleton = new ContentProcessManager();
-    ClearOnShutdown(&sSingleton);
-  }
-  return sSingleton;
-}
-
-void
-ContentProcessManager::AddContentProcess(ContentParent* aChildCp,
-                                         const ContentParentId& aParentCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aChildCp);
-
-  ContentProcessInfo info;
-  info.mCp = aChildCp;
-  info.mParentCpId = aParentCpId;
-  mContentParentMap[aChildCp->ChildID()] = info;
-}
-
-void
-ContentProcessManager::RemoveContentProcess(const ContentParentId& aChildCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(mContentParentMap.find(aChildCpId) != mContentParentMap.end());
-
-  mContentParentMap.erase(aChildCpId);
-  for (auto iter = mContentParentMap.begin();
-       iter != mContentParentMap.end();
-       ++iter) {
-    if (!iter->second.mChildrenCpId.empty()) {
-      iter->second.mChildrenCpId.erase(aChildCpId);
-    }
-  }
-}
-
-bool
-ContentProcessManager::AddGrandchildProcess(const ContentParentId& aParentCpId,
-                                            const ContentParentId& aChildCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  auto iter = mContentParentMap.find(aParentCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING("Parent process should be already in map!");
-    return false;
-  }
-  iter->second.mChildrenCpId.insert(aChildCpId);
-  return true;
-}
-
-bool
-ContentProcessManager::GetParentProcessId(const ContentParentId& aChildCpId,
-                                          /*out*/ ContentParentId* aParentCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  auto iter = mContentParentMap.find(aChildCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return false;
-  }
-  *aParentCpId = iter->second.mParentCpId;
-  return true;
-}
-
-ContentParent*
-ContentProcessManager::GetContentProcessById(const ContentParentId& aChildCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  auto iter = mContentParentMap.find(aChildCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return nullptr;
-  }
-  return iter->second.mCp;
-}
-
-nsTArray<ContentParentId>
-ContentProcessManager::GetAllChildProcessById(const ContentParentId& aParentCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsTArray<ContentParentId> cpIdArray;
-  auto iter = mContentParentMap.find(aParentCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return Move(cpIdArray);
-  }
-
-  for (auto cpIter = iter->second.mChildrenCpId.begin();
-       cpIter != iter->second.mChildrenCpId.end();
-       ++cpIter) {
-    cpIdArray.AppendElement(*cpIter);
-  }
-
-  return Move(cpIdArray);
-}
-
-TabId
-ContentProcessManager::AllocateTabId(const TabId& aOpenerTabId,
-                                     const IPCTabContext& aContext,
-                                     const ContentParentId& aChildCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  auto iter = mContentParentMap.find(aChildCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return TabId(0);
-  }
-
-  struct RemoteFrameInfo info;
-
-  const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
-  // If it's a PopupIPCTabContext, it's the case that a TabChild want to
-  // open a new tab. aOpenerTabId has to be it's parent frame's opener id.
-  if (appBrowser.type() == IPCTabAppBrowserContext::TPopupIPCTabContext) {
-    auto remoteFrameIter = iter->second.mRemoteFrames.find(aOpenerTabId);
-    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
-      ASSERT_UNLESS_FUZZING("Failed to find parent frame's opener id.");
-      return TabId(0);
-    }
-
-    info.mOpenerTabId = remoteFrameIter->second.mOpenerTabId;
-
-    const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
-    MOZ_ASSERT(ipcContext.opener().type() == PBrowserOrId::TTabId);
-
-    remoteFrameIter = iter->second.mRemoteFrames.find(ipcContext.opener().get_TabId());
-    if (remoteFrameIter == iter->second.mRemoteFrames.end()) {
-      ASSERT_UNLESS_FUZZING("Failed to find tab id.");
-      return TabId(0);
-    }
-
-    info.mContext = remoteFrameIter->second.mContext;
-  }
-  else {
-    MaybeInvalidTabContext tc(aContext);
-    if (!tc.IsValid()) {
-      NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
-                               "the child process. (%s)",
-                               tc.GetInvalidReason()).get());
-      return TabId(0);
-    }
-    info.mOpenerTabId = aOpenerTabId;
-    info.mContext = tc.GetTabContext();
-  }
-
-  mUniqueId = ++gTabId;
-  iter->second.mRemoteFrames[mUniqueId] = info;
-
-  return mUniqueId;
-}
-
-void
-ContentProcessManager::DeallocateTabId(const ContentParentId& aChildCpId,
-                                       const TabId& aChildTabId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  auto iter = mContentParentMap.find(aChildCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return;
-  }
-
-  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
-  if (remoteFrameIter != iter->second.mRemoteFrames.end()) {
-    iter->second.mRemoteFrames.erase(aChildTabId);
-  }
-}
-
-nsTArray<uint64_t>
-ContentProcessManager::GetAppIdsByContentProcess(const ContentParentId& aChildCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsTArray<uint64_t> appIdArray;
-  auto iter = mContentParentMap.find(aChildCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return Move(appIdArray);
-  }
-
-  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
-       remoteFrameIter != iter->second.mRemoteFrames.end();
-       ++remoteFrameIter) {
-    appIdArray.AppendElement(remoteFrameIter->second.mContext.OwnOrContainingAppId());
-  }
-
-  return Move(appIdArray);
-}
-
-nsTArray<TabContext>
-ContentProcessManager::GetTabContextByContentProcess(const ContentParentId& aChildCpId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsTArray<TabContext> tabContextArray;
-  auto iter = mContentParentMap.find(aChildCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return Move(tabContextArray);
-  }
-
-  for (auto remoteFrameIter = iter->second.mRemoteFrames.begin();
-       remoteFrameIter != iter->second.mRemoteFrames.end();
-       ++remoteFrameIter) {
-    tabContextArray.AppendElement(remoteFrameIter->second.mContext);
-  }
-
-  return Move(tabContextArray);
-}
-
-bool
-ContentProcessManager::GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
-                                                 const TabId& aChildTabId,
-                                                 /*out*/TabId* aOpenerTabId)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  auto iter = mContentParentMap.find(aChildCpId);
-  if (NS_WARN_IF(iter == mContentParentMap.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return false;
-  }
-
-  auto remoteFrameIter = iter->second.mRemoteFrames.find(aChildTabId);
-  if (NS_WARN_IF(remoteFrameIter == iter->second.mRemoteFrames.end())) {
-    ASSERT_UNLESS_FUZZING();
-    return false;
-  }
-
-  *aOpenerTabId = remoteFrameIter->second.mOpenerTabId;
-
-  return true;
-}
-
-} // namespace dom
-} // namespace mozilla
deleted file mode 100644
--- a/dom/ipc/ContentProcessManager.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et ft=cpp : */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_ContentProcessManager_h
-#define mozilla_dom_ContentProcessManager_h
-
-#include <map>
-#include <set>
-#include "mozilla/StaticPtr.h"
-#include "mozilla/dom/TabContext.h"
-#include "mozilla/dom/ipc/IdType.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace dom {
-class ContentParent;
-
-struct RemoteFrameInfo
-{
-  TabId mOpenerTabId;
-  TabContext mContext;
-};
-
-struct ContentProcessInfo
-{
-  ContentParent* mCp;
-  ContentParentId mParentCpId;
-  std::set<ContentParentId> mChildrenCpId;
-  std::map<TabId, RemoteFrameInfo> mRemoteFrames;
-};
-
-class ContentProcessManager MOZ_FINAL
-{
-public:
-  static ContentProcessManager* GetSingleton();
-  ~ContentProcessManager() {MOZ_COUNT_DTOR(ContentProcessManager);};
-
-  /**
-   * Add a new content process into the map.
-   * If aParentCpId is not 0, it's a nested content process.
-   */
-  void AddContentProcess(ContentParent* aChildCp,
-                         const ContentParentId& aParentCpId = ContentParentId(0));
-  /**
-   * Remove the content process by id.
-   */
-  void RemoveContentProcess(const ContentParentId& aChildCpId);
-  /**
-   * Add a grandchild content process into the map.
-   * aParentCpId must be already added in the map by AddContentProcess().
-   */
-  bool AddGrandchildProcess(const ContentParentId& aParentCpId,
-                            const ContentParentId& aChildCpId);
-  /**
-   * Get the parent process's id by child process's id.
-   * Used to check if a child really belongs to the parent.
-   */
-  bool GetParentProcessId(const ContentParentId& aChildCpId,
-                          /*out*/ ContentParentId* aParentCpId);
-  /**
-   * Return the ContentParent pointer by id.
-   */
-  ContentParent* GetContentProcessById(const ContentParentId& aChildCpId);
-
-  /**
-   * Return a list of all child process's id.
-   */
-  nsTArray<ContentParentId>
-  GetAllChildProcessById(const ContentParentId& aParentCpId);
-
-  /**
-   * Allocate a tab id for the given content process's id.
-   * Used when a content process wants to create a new tab. aOpenerTabId and
-   * aContext are saved in RemoteFrameInfo, which is a part of ContentProcessInfo.
-   * We can use the tab id and process id to locate the TabContext for future use.
-   */
-  TabId AllocateTabId(const TabId& aOpenerTabId,
-                      const IPCTabContext& aContext,
-                      const ContentParentId& aChildCpId);
-
-  /**
-   * Remove the RemoteFrameInfo by the given process and tab id.
-   */
-  void DeallocateTabId(const ContentParentId& aChildCpId,
-                       const TabId& aChildTabId);
-
-  /**
-   * Get all app ids which are inside the given content process.
-   * XXX Currently not used. Plan to be used for bug 1020186.
-   */
-  nsTArray<uint64_t>
-  GetAppIdsByContentProcess(const ContentParentId& aChildCpId);
-
-  /**
-   * Get all TabContext which are inside the given content process.
-   * Used for AppProcessChecker to cehck app status.
-   */
-  nsTArray<TabContext>
-  GetTabContextByContentProcess(const ContentParentId& aChildCpId);
-
-  /**
-   * Query a tab's opener id by the given process and tab id.
-   * XXX Currently not used. Plan to be used for bug 1020179.
-   */
-  bool GetRemoteFrameOpenerTabId(const ContentParentId& aChildCpId,
-                                 const TabId& aChildTabId,
-                                 /*out*/ TabId* aOpenerTabId);
-
-private:
-  static StaticAutoPtr<ContentProcessManager> sSingleton;
-  TabId mUniqueId;
-  std::map<ContentParentId, ContentProcessInfo> mContentParentMap;
-
-  ContentProcessManager() {MOZ_COUNT_CTOR(ContentProcessManager);};
-};
-
-} // namespace dom
-} // namespace mozilla
-#endif
\ No newline at end of file
deleted file mode 100644
--- a/dom/ipc/IdType.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set sw=4 ts=8 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/. */
-
-#ifndef mozilla_dom_IdType_h
-#define mozilla_dom_IdType_h
-
-#include "ipc/IPCMessageUtils.h"
-
-namespace IPC {
-template<typename T> struct ParamTraits;
-}
-
-namespace mozilla {
-namespace dom {
-class ContentParent;
-class TabParent;
-
-
-template<typename T>
-class IdType
-{
-
-  friend struct IPC::ParamTraits<IdType<T>>;
-
-public:
-  IdType() : mId(0) {}
-  explicit IdType(uint64_t aId) : mId(aId) {}
-
-  operator uint64_t() const { return mId; }
-
-  IdType& operator=(uint64_t aId)
-  {
-    mId = aId;
-    return *this;
-  }
-
-  bool operator<(const IdType& rhs)
-  {
-    return mId < rhs.mId;
-  }
-private:
-  uint64_t mId;
-};
-
-typedef IdType<TabParent> TabId;
-typedef IdType<ContentParent> ContentParentId;
-
-} // namespace dom
-} // namespace mozilla
-
-namespace IPC {
-
-template<typename T>
-struct ParamTraits<mozilla::dom::IdType<T>>
-{
-  typedef mozilla::dom::IdType<T> paramType;
-
-  static void Write(Message* aMsg, const paramType& aParam)
-  {
-    WriteParam(aMsg, aParam.mId);
-  }
-
-  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
-  {
-    return ReadParam(aMsg, aIter, &aResult->mId);
-  }
-};
-
-}
-
-#endif
\ No newline at end of file
deleted file mode 100644
--- a/dom/ipc/PBrowserOrId.ipdlh
+++ /dev/null
@@ -1,21 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et tw=80 ft=c: */
-/* 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 protocol PBrowser;
-
-using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
-
-namespace mozilla {
-namespace dom {
-
-union PBrowserOrId
-{
-  nullable PBrowser;
-  TabId;
-};
-
-} // namespace dom
-} // namespace mozilla
\ No newline at end of file
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -62,18 +62,16 @@ using struct mozilla::void_t from "ipc/I
 using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
 using mozilla::dom::AudioChannel from "mozilla/dom/AudioChannelBinding.h";
 using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::dom::quota::PersistenceType from "mozilla/dom/quota/PersistenceType.h";
 using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
 using gfxIntSize from "nsSize.h";
-using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
-using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     ResourceMapping;
 };
 
@@ -382,18 +380,18 @@ both:
     // browser element.
     //
     // This allows the parent to prevent a malicious child from escalating its
     // privileges by requesting a PBrowser corresponding to a highly-privileged
     // app; the child can only request privileges for an app which the child has
     // access to (in the form of a TabChild).
     //
     // Keep the last 3 attributes in sync with GetProcessAttributes!
-    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
-                   ContentParentId cpId, bool isForApp, bool isForBrowser);
+    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
+                   uint64_t id, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     PFileDescriptorSet(FileDescriptor fd);
 
 child:
     /**
      * Enable system-level sandboxing features, if available.  Can
@@ -517,26 +515,25 @@ parent:
      * |id| is a unique ID among all subprocesses.  When |isForApp &&
      * isForBrowser|, we're loading <browser> for an app.  When
      * |isForBrowser|, we're loading <browser>.  When |!isForApp &&
      * !isForBrowser|, we're probably loading <xul:browser remote>.
      *
      * Keep the return values in sync with PBrowser()!
      */
     sync GetProcessAttributes()
-        returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
+        returns (uint64_t id, bool isForApp, bool isForBrowser);
     sync GetXPCOMProcessAttributes()
         returns (bool isOffline, nsString[] dictionaries,
                  ClipboardCapabilities clipboardCaps);
 
     sync CreateChildProcess(IPCTabContext context,
-                            ProcessPriority priority,
-                            TabId openerTabId)
-        returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId);
-    intr BridgeToChildProcess(ContentParentId cpId);
+                            ProcessPriority priority)
+        returns (uint64_t id, bool isForApp, bool isForBrowser);
+    intr BridgeToChildProcess(uint64_t id);
 
     async PJavaScript();
 
     sync PRemoteSpellcheckEngine();
     PDeviceStorageRequest(DeviceStorageParams params);
 
     PFileSystemRequest(FileSystemParams params);
 
@@ -741,23 +738,15 @@ parent:
     // Use only for testing!
     sync GetFileReferences(PersistenceType persistenceType,
                            nsCString origin,
                            nsString databaseName,
                            int64_t fileId)
       returns (int32_t refCnt, int32_t dBRefCnt, int32_t sliceRefCnt,
                bool result);
 
-    /**
-     * Tell the chrome process there is an creation of PBrowser.
-     * return a system-wise unique Id.
-     */
-    sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
-        returns (TabId tabId);
-    async DeallocateTabId(TabId tabId);
-
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -9,18 +9,16 @@ include protocol PBrowser;
 include protocol PContent;
 include protocol PJavaScript;
 
 include DOMTypes;
 include JavaScriptTypes;
 include PTabContext;
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
-using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
-using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace dom {
 
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
  * the root process to create a new process and then bridge them.  The first
@@ -38,18 +36,18 @@ prio(normal upto high) intr protocol PCo
 
 parent:
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (nsString[] retval);
 both:
     // Both the parent and the child can construct the PBrowser.
     // See the comment in PContent::PBrowser().
-    async PBrowser(TabId tabId, IPCTabContext context, uint32_t chromeFlags,
-                   ContentParentId cpId, bool isForApp, bool isForBrowser);
+    async PBrowser(IPCTabContext context, uint32_t chromeFlags,
+                   uint64_t id, bool isForApp, bool isForBrowser);
 
     async PBlob(BlobConstructorParams params);
 
     async PJavaScript();
 
     AsyncMessage(nsString aMessage, ClonedMessageData aData,
                  CpowEntry[] aCpows, Principal aPrincipal);
 };
--- a/dom/ipc/PTabContext.ipdlh
+++ b/dom/ipc/PTabContext.ipdlh
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBrowser;
-include PBrowserOrId;
+
 
 using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
 
 namespace mozilla {
 namespace dom {
 
 // An IPCTabContext which corresponds to a PBrowser opened by a child when it
 // receives window.open().
@@ -22,17 +22,17 @@ namespace dom {
 // If isBrowserElement is true, the frame's browserFrameOwnerAppId will be equal
 // to the opener's app-id.
 //
 // It's an error to set isBrowserElement == false if opener is a browser
 // element.  Such a PopupIPCTabContext should be rejected by code which receives
 // it.
 struct PopupIPCTabContext
 {
-  PBrowserOrId opener;
+  PBrowser opener;
   bool isBrowserElement;
 };
 
 // An IPCTabContext which corresponds to an app frame.
 struct AppFrameIPCTabContext
 {
   // The ID of the app this frame corresponds to.  May be NO_APP_ID.
   uint32_t ownAppId;
--- a/dom/ipc/ProcessPriorityManager.cpp
+++ b/dom/ipc/ProcessPriorityManager.cpp
@@ -467,25 +467,24 @@ ProcessPriorityManagerImpl::Observe(
   return NS_OK;
 }
 
 already_AddRefed<ParticularProcessPriorityManager>
 ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
   ContentParent* aContentParent)
 {
   nsRefPtr<ParticularProcessPriorityManager> pppm;
-  uint64_t cpId = aContentParent->ChildID();
-  mParticularManagers.Get(cpId, &pppm);
+  mParticularManagers.Get(aContentParent->ChildID(), &pppm);
   if (!pppm) {
     pppm = new ParticularProcessPriorityManager(aContentParent);
     pppm->Init();
-    mParticularManagers.Put(cpId, pppm);
+    mParticularManagers.Put(aContentParent->ChildID(), pppm);
 
     FireTestOnlyObserverNotification("process-created",
-      nsPrintfCString("%lld", cpId));
+      nsPrintfCString("%lld", aContentParent->ChildID()));
   }
 
   return pppm.forget();
 }
 
 void
 ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent,
                                                ProcessPriority aPriority,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -728,34 +728,33 @@ private:
         mInfo->FireCallback();
         return NS_OK;
     }
 };
 
 StaticRefPtr<TabChild> sPreallocatedTab;
 
 /*static*/
-std::map<TabId, nsRefPtr<TabChild>>&
+std::map<uint64_t, nsRefPtr<TabChild> >&
 TabChild::NestedTabChildMap()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  static std::map<TabId, nsRefPtr<TabChild>> sNestedTabChildMap;
+  static std::map<uint64_t, nsRefPtr<TabChild> > sNestedTabChildMap;
   return sNestedTabChildMap;
 }
 
 /*static*/ void
 TabChild::PreloadSlowThings()
 {
     MOZ_ASSERT(!sPreallocatedTab);
 
     // Pass nullptr to aManager since at this point the TabChild is
     // not connected to any manager. Any attempt to use the TabChild
     // in IPC will crash.
     nsRefPtr<TabChild> tab(new TabChild(nullptr,
-                                        TabId(0),
                                         TabContext(), /* chromeFlags */ 0));
     if (!NS_SUCCEEDED(tab->Init()) ||
         !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
         return;
     }
     // Just load and compile these scripts, but don't run them.
     tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
     // Load, compile, and run these scripts.
@@ -776,44 +775,41 @@ TabChild::PreloadSlowThings()
     }
 
     sPreallocatedTab = tab;
     ClearOnShutdown(&sPreallocatedTab);
 }
 
 /*static*/ already_AddRefed<TabChild>
 TabChild::Create(nsIContentChild* aManager,
-                 const TabId& aTabId,
                  const TabContext &aContext,
                  uint32_t aChromeFlags)
 {
     if (sPreallocatedTab &&
         sPreallocatedTab->mChromeFlags == aChromeFlags &&
         aContext.IsBrowserOrApp()) {
 
         nsRefPtr<TabChild> child = sPreallocatedTab.get();
         sPreallocatedTab = nullptr;
 
         MOZ_ASSERT(!child->mTriedBrowserInit);
 
         child->mManager = aManager;
-        child->SetTabId(aTabId);
         child->SetTabContext(aContext);
         child->NotifyTabContextUpdated();
         return child.forget();
     }
 
-    nsRefPtr<TabChild> iframe = new TabChild(aManager, aTabId,
+    nsRefPtr<TabChild> iframe = new TabChild(aManager,
                                              aContext, aChromeFlags);
     return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
 }
 
 
 TabChild::TabChild(nsIContentChild* aManager,
-                   const TabId& aTabId,
                    const TabContext& aContext,
                    uint32_t aChromeFlags)
   : TabContext(aContext)
   , mRemoteFrame(nullptr)
   , mManager(aManager)
   , mChromeFlags(aChromeFlags)
   , mLayersId(0)
   , mOuterRect(0, 0, 0, 0)
@@ -827,31 +823,25 @@ TabChild::TabChild(nsIContentChild* aMan
   , mUpdateHitRegion(false)
   , mPendingTouchPreventedResponse(false)
   , mPendingTouchPreventedBlockId(0)
   , mTouchEndCancelled(false)
   , mEndTouchIsClick(false)
   , mIgnoreKeyPressEvent(false)
   , mActiveElementManager(new ActiveElementManager())
   , mHasValidInnerSize(false)
+  , mUniqueId(0)
   , mDestroyed(false)
-  , mUniqueId(aTabId)
 {
   if (!sActiveDurationMsSet) {
     Preferences::AddIntVarCache(&sActiveDurationMs,
                                 "ui.touch_activation.duration_ms",
                                 sActiveDurationMs);
     sActiveDurationMsSet = true;
   }
-
-  // preloaded TabChild should not be added to child map
-  if (mUniqueId) {
-    MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
-    NestedTabChildMap()[mUniqueId] = this;
-  }
 }
 
 NS_IMETHODIMP
 TabChild::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
   if (eventType.EqualsLiteral("DOMMetaAdded")) {
@@ -1439,46 +1429,36 @@ TabChild::BrowserFrameProvideWindow(nsID
                                     nsIURI* aURI,
                                     const nsAString& aName,
                                     const nsACString& aFeatures,
                                     bool* aWindowIsNew,
                                     nsIDOMWindow** aReturn)
 {
   *aReturn = nullptr;
 
-  ContentChild* cc = ContentChild::GetSingleton();
-  const TabId openerTabId = GetTabId();
+  nsRefPtr<TabChild> newChild =
+      new TabChild(ContentChild::GetSingleton(),
+                   /* TabContext */ *this, /* chromeFlags */ 0);
+  if (!NS_SUCCEEDED(newChild->Init())) {
+      return NS_ERROR_ABORT;
+  }
 
   // We must use PopupIPCTabContext here; ContentParent will not accept the
   // result of this->AsIPCTabContext() (which will be a
   // BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
   // reasons.
   PopupIPCTabContext context;
-  context.opener() = openerTabId;
+  context.openerChild() = this;
   context.isBrowserElement() = IsBrowserElement();
 
-  IPCTabContext ipcContext(context, mScrolling);
-
-  TabId tabId;
-  cc->SendAllocateTabId(openerTabId,
-                        ipcContext,
-                        cc->GetID(),
-                        &tabId);
-
-  nsRefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
-                                             /* TabContext */ *this, /* chromeFlags */ 0);
-  if (NS_FAILED(newChild->Init())) {
-    return NS_ERROR_ABORT;
-  }
-
-  context.opener() = this;
+  ContentChild* cc = static_cast<ContentChild*>(Manager());
   unused << Manager()->SendPBrowserConstructor(
       // We release this ref in DeallocPBrowserChild
       nsRefPtr<TabChild>(newChild).forget().take(),
-      tabId, IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
+      IPCTabContext(context, mScrolling), /* chromeFlags */ 0,
       cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
 
   nsAutoCString spec;
   if (aURI) {
     aURI->GetSpec(spec);
   }
 
   NS_ConvertUTF8toUTF16 url(spec);
@@ -1578,18 +1558,18 @@ TabChild::ActorDestroy(ActorDestroyReaso
     static_cast<nsFrameMessageManager*>
       (mTabChildGlobal->mMessageManager.get())->Disconnect();
     mTabChildGlobal->mMessageManager = nullptr;
   }
 
   CompositorChild* compositorChild = static_cast<CompositorChild*>(CompositorChild::Get());
   compositorChild->CancelNotifyAfterRemotePaint(this);
 
-  if (GetTabId() != 0) {
-    NestedTabChildMap().erase(GetTabId());
+  if (Id() != 0) {
+    NestedTabChildMap().erase(Id());
   }
 }
 
 TabChild::~TabChild()
 {
     DestroyWindow();
 
     nsCOMPtr<nsIWebBrowser> webBrowser = do_QueryInterface(WebNavigation());
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -29,17 +29,16 @@
 #include "nsITooltipListener.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "nsIWebBrowserChrome3.h"
-#include "mozilla/dom/ipc/IdType.h"
 
 class nsICachedFileDescriptorListener;
 class nsIDOMWindowUtils;
 
 namespace mozilla {
 namespace layout {
 class RenderFrameChild;
 }
@@ -250,35 +249,48 @@ class TabChild MOZ_FINAL : public TabChi
                            public nsITooltipListener
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::layout::RenderFrameChild RenderFrameChild;
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
     typedef mozilla::layers::ActiveElementManager ActiveElementManager;
 
 public:
-    static std::map<TabId, nsRefPtr<TabChild>>& NestedTabChildMap();
+    static std::map<uint64_t, nsRefPtr<TabChild> >& NestedTabChildMap();
 
 public:
     /** 
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild>
-    Create(nsIContentChild* aManager, const TabId& aTabId, const TabContext& aContext, uint32_t aChromeFlags);
+    Create(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
 
     bool IsRootContentDocument();
 
-    const TabId GetTabId() const {
-      MOZ_ASSERT(mUniqueId != 0);
-      return mUniqueId;
+    const uint64_t Id() const {
+        return mUniqueId;
+    }
+
+    static uint64_t
+    GetTabChildId(TabChild* aTabChild)
+    {
+        MOZ_ASSERT(NS_IsMainThread());
+        if (aTabChild->Id() != 0) {
+            return aTabChild->Id();
+        }
+        static uint64_t sId = 0;
+        sId++;
+        aTabChild->mUniqueId = sId;
+        NestedTabChildMap()[sId] = aTabChild;
+        return sId;
     }
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIEMBEDDINGSITEWINDOW
     NS_DECL_NSIWEBBROWSERCHROMEFOCUS
     NS_DECL_NSIINTERFACEREQUESTOR
@@ -502,20 +514,17 @@ private:
     /**
      * Create a new TabChild object.
      *
      * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
      * frame in the hierarchy which contains us.
      *
      * |aIsBrowserElement| indicates whether we're a browser (but not an app).
      */
-    TabChild(nsIContentChild* aManager,
-             const TabId& aTabId,
-             const TabContext& aContext,
-             uint32_t aChromeFlags);
+    TabChild(nsIContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
 
     nsresult Init();
 
     class DelayedFireSingleTapEvent;
     class DelayedFireContextMenuEvent;
 
     // Notify others that our TabContext has been updated.  (At the moment, this
     // sets the appropriate app-id and is-browser flags on our docshell.)
@@ -553,24 +562,16 @@ private:
                               bool* aWindowIsNew,
                               nsIDOMWindow** aReturn);
 
     bool HasValidInnerSize();
 
     void SendPendingTouchPreventedResponse(bool aPreventDefault,
                                            const ScrollableLayerGuid& aGuid);
 
-    void SetTabId(const TabId& aTabId)
-    {
-      MOZ_ASSERT(mUniqueId == 0);
-
-      mUniqueId = aTabId;
-      NestedTabChildMap()[mUniqueId] = this;
-    }
-
     class CachedFileDescriptorInfo;
     class CachedFileDescriptorCallbackRunnable;
 
     TextureFactoryIdentifier mTextureFactoryIdentifier;
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     nsCOMPtr<nsIURI> mLastURI;
     RenderFrameChild* mRemoteFrame;
@@ -604,18 +605,18 @@ private:
     void FireSingleTapEvent(LayoutDevicePoint aPoint);
 
     bool mTouchEndCancelled;
     bool mEndTouchIsClick;
 
     bool mIgnoreKeyPressEvent;
     nsRefPtr<ActiveElementManager> mActiveElementManager;
     bool mHasValidInnerSize;
+    uint64_t mUniqueId;
     bool mDestroyed;
-    TabId mUniqueId;
 
     DISALLOW_EVIL_CONSTRUCTORS(TabChild);
 };
 
 }
 }
 
 #endif // mozilla_dom_TabChild_h
--- a/dom/ipc/TabContext.cpp
+++ b/dom/ipc/TabContext.cpp
@@ -251,34 +251,29 @@ MaybeInvalidTabContext::MaybeInvalidTabC
   uint32_t containingAppId = NO_APP_ID;
 
   const IPCTabAppBrowserContext& appBrowser = aParams.appBrowserContext();
   switch(appBrowser.type()) {
     case IPCTabAppBrowserContext::TPopupIPCTabContext: {
       const PopupIPCTabContext &ipcContext = appBrowser.get_PopupIPCTabContext();
 
       TabContext *context;
-      if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
-        context = static_cast<TabParent*>(ipcContext.opener().get_PBrowserParent());
+      if (ipcContext.openerParent()) {
+        context = static_cast<TabParent*>(ipcContext.openerParent());
         if (context->IsBrowserElement() && !ipcContext.isBrowserElement()) {
           // If the TabParent corresponds to a browser element, then it can only
           // open other browser elements, for security reasons.  We should have
           // checked this before calling the TabContext constructor, so this is
           // a fatal error.
           mInvalidReason = "Child is-browser process tried to "
                            "open a non-browser tab.";
           return;
         }
-      } else if (ipcContext.opener().type() == PBrowserOrId::TPBrowserChild) {
-        context = static_cast<TabChild*>(ipcContext.opener().get_PBrowserChild());
-      } else if (ipcContext.opener().type() == PBrowserOrId::TTabId) {
-        // We should never get here because this PopupIPCTabContext is only
-        // used for allocating a new tab id, not for allocating a PBrowser.
-        mInvalidReason = "Child process tried to open an tab without the opener information.";
-        return;
+      } else if (ipcContext.openerChild()) {
+        context = static_cast<TabChild*>(ipcContext.openerChild());
       } else {
         // This should be unreachable because PopupIPCTabContext::opener is not a
         // nullable field.
         mInvalidReason = "PopupIPCTabContext::opener was null (?!).";
         return;
       }
 
       // Browser elements can't nest other browser elements.  So if
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -213,20 +213,17 @@ TabParent* sEventCapturer;
 TabParent *TabParent::mIMETabParent = nullptr;
 
 NS_IMPL_ISUPPORTS(TabParent,
                   nsITabParent,
                   nsIAuthPromptProvider,
                   nsISecureBrowserUI,
                   nsISupportsWeakReference)
 
-TabParent::TabParent(nsIContentParent* aManager,
-                     const TabId& aTabId,
-                     const TabContext& aContext,
-                     uint32_t aChromeFlags)
+TabParent::TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags)
   : TabContext(aContext)
   , mFrameElement(nullptr)
   , mIMESelectionAnchor(0)
   , mIMESelectionFocus(0)
   , mIMEComposing(false)
   , mIMECompositionEnding(false)
   , mIMECompositionStart(0)
   , mIMESeqno(0)
@@ -240,17 +237,16 @@ TabParent::TabParent(nsIContentParent* a
   , mShown(false)
   , mUpdatedDimensions(false)
   , mManager(aManager)
   , mMarkedDestroying(false)
   , mIsDestroyed(false)
   , mAppPackageFileDescriptorSent(false)
   , mSendOfflineStatus(true)
   , mChromeFlags(aChromeFlags)
-  , mTabId(aTabId)
 {
   MOZ_ASSERT(aManager);
 }
 
 TabParent::~TabParent()
 {
 }
 
@@ -317,23 +313,17 @@ TabParent::Destroy()
   mMarkedDestroying = true;
 }
 
 bool
 TabParent::Recv__delete__()
 {
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     Manager()->AsContentParent()->NotifyTabDestroyed(this, mMarkedDestroying);
-    ContentParent::DeallocateTabId(mTabId,
-                                   Manager()->AsContentParent()->ChildID());
   }
-  else {
-    ContentParent::DeallocateTabId(mTabId, ContentParentId(0));
-  }
-
   return true;
 }
 
 void
 TabParent::ActorDestroy(ActorDestroyReason why)
 {
   if (sEventCapturer == this) {
     sEventCapturer = nullptr;
@@ -1655,26 +1645,16 @@ TabParent::GetFrom(nsIContent* aContent)
   nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent);
   if (!loaderOwner) {
     return nullptr;
   }
   nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
   return GetFrom(frameLoader);
 }
 
-/*static*/ TabId
-TabParent::GetTabIdFrom(nsIDocShell *docShell)
-{
-  nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
-  if (tabChild) {
-    return static_cast<TabChild*>(tabChild.get())->GetTabId();
-  }
-  return TabId(0);
-}
-
 RenderFrameParent*
 TabParent::GetRenderFrame()
 {
   if (ManagedPRenderFrameParent().IsEmpty()) {
     return nullptr;
   }
   return static_cast<RenderFrameParent*>(ManagedPRenderFrameParent()[0]);
 }
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -6,17 +6,16 @@
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
-#include "mozilla/dom/ipc/IdType.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsISecureBrowserUI.h"
 #include "nsITabParent.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsWeakReference.h"
 #include "Units.h"
@@ -24,17 +23,16 @@
 
 class nsFrameLoader;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 class nsIWidget;
 class nsILoadContext;
 class CpowHolder;
-class nsIDocShell;
 
 namespace mozilla {
 
 namespace layers {
 struct FrameMetrics;
 struct TextureFactoryIdentifier;
 }
 
@@ -64,20 +62,17 @@ class TabParent : public PBrowserParent
     typedef mozilla::layout::ScrollingBehavior ScrollingBehavior;
 
     virtual ~TabParent();
 
 public:
     // nsITabParent
     NS_DECL_NSITABPARENT
 
-    TabParent(nsIContentParent* aManager,
-              const TabId& aTabId,
-              const TabContext& aContext,
-              uint32_t aChromeFlags);
+    TabParent(nsIContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags);
     Element* GetOwnerElement() const { return mFrameElement; }
     void SetOwnerElement(Element* aElement);
 
     /**
      * Get the mozapptype attribute from this TabParent's owner DOM element.
      */
     void GetAppType(nsAString& aOut);
 
@@ -324,33 +319,27 @@ public:
 
     static TabParent *GetIMETabParent() { return mIMETabParent; }
     bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
     bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
     bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
 
     static TabParent* GetFrom(nsFrameLoader* aFrameLoader);
     static TabParent* GetFrom(nsIContent* aContent);
-    static TabId GetTabIdFrom(nsIDocShell* docshell);
 
     nsIContentParent* Manager() { return mManager; }
 
     /**
      * Let managees query if Destroy() is already called so they don't send out
      * messages when the PBrowser actor is being destroyed.
      */
     bool IsDestroyed() const { return mIsDestroyed; }
 
     already_AddRefed<nsIWidget> GetWidget() const;
 
-    const TabId GetTabId() const
-    {
-      return mTabId;
-    }
-
 protected:
     bool ReceiveMessage(const nsString& aMessage,
                         bool aSync,
                         const StructuredCloneData* aCloneData,
                         CpowHolder* aCpows,
                         nsIPrincipal* aPrincipal,
                         InfallibleTArray<nsString>* aJSONRetVal = nullptr);
 
@@ -447,16 +436,14 @@ private:
 
     // Whether we need to send the offline status to the TabChild
     // This is true, until the first call of LoadURL
     bool mSendOfflineStatus;
 
     uint32_t mChromeFlags;
 
     nsCOMPtr<nsILoadContext> mLoadContext;
-
-    TabId mTabId;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -6,27 +6,25 @@
 
 EXPORTS += [
     'nsICachedFileDescriptorListener.h',
 ]
 
 EXPORTS.mozilla.dom.ipc += [
     'BlobChild.h',
     'BlobParent.h',
-    'IdType.h',
     'nsIRemoteBlob.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'ContentBridgeChild.h',
     'ContentBridgeParent.h',
     'ContentChild.h',
     'ContentParent.h',
     'ContentProcess.h',
-    'ContentProcessManager.h',
     'CPOWManagerGetter.h',
     'CrashReporterChild.h',
     'CrashReporterParent.h',
     'FilePickerParent.h',
     'nsIContentChild.h',
     'nsIContentParent.h',
     'PermissionMessageUtils.h',
     'StructuredCloneUtils.h',
@@ -44,17 +42,16 @@ EXPORTS.mozilla += [
 
 UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
-    'ContentProcessManager.cpp',
     'CrashReporterParent.cpp',
     'FilePickerParent.cpp',
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
     'ScreenManagerParent.cpp',
@@ -75,17 +72,16 @@ SOURCES += [
     'CrashReporterChild.cpp',
 ]
 
 IPDL_SOURCES += [
     'DOMTypes.ipdlh',
     'PBlob.ipdl',
     'PBlobStream.ipdl',
     'PBrowser.ipdl',
-    'PBrowserOrId.ipdlh',
     'PColorPicker.ipdl',
     'PContent.ipdl',
     'PContentBridge.ipdl',
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PCycleCollectWithLogs.ipdl',
     'PDocumentRenderer.ipdl',
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -45,37 +45,36 @@ nsIContentChild::AllocPJavaScriptChild()
 bool
 nsIContentChild::DeallocPJavaScriptChild(PJavaScriptChild* aChild)
 {
   static_cast<JavaScriptChild*>(aChild)->decref();
   return true;
 }
 
 PBrowserChild*
-nsIContentChild::AllocPBrowserChild(const TabId& aTabId,
-                                    const IPCTabContext& aContext,
+nsIContentChild::AllocPBrowserChild(const IPCTabContext& aContext,
                                     const uint32_t& aChromeFlags,
-                                    const ContentParentId& aCpID,
+                                    const uint64_t& aID,
                                     const bool& aIsForApp,
                                     const bool& aIsForBrowser)
 {
   // We'll happily accept any kind of IPCTabContext here; we don't need to
   // check that it's of a certain type for security purposes, because we
   // believe whatever the parent process tells us.
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
                              "the parent process. (%s)  Crashing...",
                              tc.GetInvalidReason()).get());
     MOZ_CRASH("Invalid TabContext received from the parent process.");
   }
 
   nsRefPtr<TabChild> child =
-    TabChild::Create(this, aTabId, tc.GetTabContext(), aChromeFlags);
+    TabChild::Create(this, tc.GetTabContext(), aChromeFlags);
 
   // The ref here is released in DeallocPBrowserChild.
   return child.forget().take();
 }
 
 bool
 nsIContentChild::DeallocPBrowserChild(PBrowserChild* aIframe)
 {
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -2,18 +2,16 @@
 /* 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_nsIContentChild_h
 #define mozilla_dom_nsIContentChild_h
 
-#include "mozilla/dom/ipc/IdType.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 } }
 
@@ -49,30 +47,28 @@ public:
   BlobChild* GetOrCreateActorForBlob(File* aBlob);
 
   virtual PBlobChild* SendPBlobConstructor(
     PBlobChild* aActor,
     const BlobConstructorParams& aParams) = 0;
 
   virtual bool
   SendPBrowserConstructor(PBrowserChild* aActor,
-                          const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
-                          const ContentParentId& aCpID,
+                          const uint64_t& aID,
                           const bool& aIsForApp,
                           const bool& aIsForBrowser) = 0;
 protected:
   virtual jsipc::PJavaScriptChild* AllocPJavaScriptChild();
   virtual bool DeallocPJavaScriptChild(jsipc::PJavaScriptChild*);
 
-  virtual PBrowserChild* AllocPBrowserChild(const TabId& aTabId,
-                                            const IPCTabContext& aContext,
+  virtual PBrowserChild* AllocPBrowserChild(const IPCTabContext& aContext,
                                             const uint32_t& aChromeFlags,
-                                            const ContentParentId& aCpId,
+                                            const uint64_t& aID,
                                             const bool& aIsForApp,
                                             const bool& aIsForBrowser);
   virtual bool DeallocPBrowserChild(PBrowserChild*);
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
 
   virtual bool DeallocPBlobChild(PBlobChild* aActor);
 
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -19,23 +19,16 @@
 
 #include "JavaScriptParent.h"
 #include "nsFrameMessageManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla::jsipc;
 
-// XXX need another bug to move this to a common header.
-#ifdef DISABLE_ASSERTS_FOR_FUZZING
-#define ASSERT_UNLESS_FUZZING(...) do { } while (0)
-#else
-#define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
-#endif
-
 namespace mozilla {
 namespace dom {
 
 nsIContentParent::nsIContentParent()
 {
   mMessageManager = nsFrameMessageManager::NewProcessMessageManager(this);
 }
 
@@ -76,70 +69,65 @@ nsIContentParent::CanOpenBrowser(const I
 {
   const IPCTabAppBrowserContext& appBrowser = aContext.appBrowserContext();
 
   // We don't trust the IPCTabContext we receive from the child, so we'll bail
   // if we receive an IPCTabContext that's not a PopupIPCTabContext.
   // (PopupIPCTabContext lets the child process prove that it has access to
   // the app it's trying to open.)
   if (appBrowser.type() != IPCTabAppBrowserContext::TPopupIPCTabContext) {
-    ASSERT_UNLESS_FUZZING("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
+    NS_ERROR("Unexpected IPCTabContext type.  Aborting AllocPBrowserParent.");
     return false;
   }
 
   const PopupIPCTabContext& popupContext = appBrowser.get_PopupIPCTabContext();
-  if (popupContext.opener().type() != PBrowserOrId::TPBrowserParent) {
-    ASSERT_UNLESS_FUZZING("Unexpected PopupIPCTabContext type.  Aborting AllocPBrowserParent.");
-    return false;
-  }
-
-  auto opener = static_cast<TabParent*>(popupContext.opener().get_PBrowserParent());
+  TabParent* opener = static_cast<TabParent*>(popupContext.openerParent());
   if (!opener) {
-    ASSERT_UNLESS_FUZZING("Got null opener from child; aborting AllocPBrowserParent.");
+    NS_ERROR("Got null opener from child; aborting AllocPBrowserParent.");
     return false;
   }
 
   // Popup windows of isBrowser frames must be isBrowser if the parent
   // isBrowser.  Allocating a !isBrowser frame with same app ID would allow
   // the content to access data it's not supposed to.
   if (!popupContext.isBrowserElement() && opener->IsBrowserElement()) {
-    ASSERT_UNLESS_FUZZING("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
+    NS_ERROR("Child trying to escalate privileges!  Aborting AllocPBrowserParent.");
     return false;
   }
 
   MaybeInvalidTabContext tc(aContext);
   if (!tc.IsValid()) {
     NS_ERROR(nsPrintfCString("Child passed us an invalid TabContext.  (%s)  "
                              "Aborting AllocPBrowserParent.",
                              tc.GetInvalidReason()).get());
     return false;
   }
 
   return true;
 }
 
 PBrowserParent*
-nsIContentParent::AllocPBrowserParent(const TabId& aTabId,
-                                      const IPCTabContext& aContext,
+nsIContentParent::AllocPBrowserParent(const IPCTabContext& aContext,
                                       const uint32_t& aChromeFlags,
-                                      const ContentParentId& aCpId,
+                                      const uint64_t& aId,
                                       const bool& aIsForApp,
                                       const bool& aIsForBrowser)
 {
-  unused << aCpId;
+  unused << aChromeFlags;
+  unused << aId;
   unused << aIsForApp;
   unused << aIsForBrowser;
 
   if (!CanOpenBrowser(aContext)) {
     return nullptr;
   }
 
   MaybeInvalidTabContext tc(aContext);
   MOZ_ASSERT(tc.IsValid());
-  TabParent* parent = new TabParent(this, aTabId, tc.GetTabContext(), aChromeFlags);
+  TabParent* parent = new TabParent(this, tc.GetTabContext(), aChromeFlags);
 
   // We release this ref in DeallocPBrowserParent()
   NS_ADDREF(parent);
   return parent;
 }
 
 bool
 nsIContentParent::DeallocPBrowserParent(PBrowserParent* aFrame)
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -2,18 +2,16 @@
 /* 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_nsIContentParent_h
 #define mozilla_dom_nsIContentParent_h
 
-#include "mozilla/dom/ipc/IdType.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 } }
 
@@ -46,47 +44,45 @@ class nsIContentParent : public nsISuppo
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICONTENTPARENT_IID)
 
   nsIContentParent();
 
   BlobParent* GetOrCreateActorForBlob(File* aBlob);
 
-  virtual ContentParentId ChildID() = 0;
+  virtual uint64_t ChildID() = 0;
   virtual bool IsForApp() = 0;
   virtual bool IsForBrowser() = 0;
 
   virtual PBlobParent* SendPBlobConstructor(
     PBlobParent* aActor,
     const BlobConstructorParams& aParams) NS_WARN_UNUSED_RESULT = 0;
 
   virtual PBrowserParent* SendPBrowserConstructor(
     PBrowserParent* actor,
-    const TabId& aTabId,
     const IPCTabContext& context,
     const uint32_t& chromeFlags,
-    const ContentParentId& aCpId,
+    const uint64_t& aId,
     const bool& aIsForApp,
     const bool& aIsForBrowser) NS_WARN_UNUSED_RESULT = 0;
 
   virtual bool IsContentParent() { return false; }
   ContentParent* AsContentParent();
 
 protected: // methods
   bool CanOpenBrowser(const IPCTabContext& aContext);
 
 protected: // IPDL methods
   virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScriptParent();
   virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*);
 
-  virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
-                                              const IPCTabContext& aContext,
+  virtual PBrowserParent* AllocPBrowserParent(const IPCTabContext& aContext,
                                               const uint32_t& aChromeFlags,
-                                              const ContentParentId& aCpId,
+                                              const uint64_t& aId,
                                               const bool& aIsForApp,
                                               const bool& aIsForBrowser);
   virtual bool DeallocPBrowserParent(PBrowserParent* frame);
 
   virtual PBlobParent* AllocPBlobParent(const BlobConstructorParams& aParams);
 
   virtual bool DeallocPBlobParent(PBlobParent* aActor);
 
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -271,17 +271,21 @@ nsresult MediaCodecDataDecoder::InitDeco
 {
   JNIEnv* env = GetJNIForThread();
   mDecoder = CreateDecoder(env, mMimeType);
   if (!mDecoder) {
     mCallback->Error();
     return NS_ERROR_FAILURE;
   }
 
-  mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0);
+  if (!mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0)) {
+    mCallback->Error();
+    return NS_ERROR_FAILURE;
+  }
+
   mDecoder->Start();
 
   ResetInputBuffers();
   ResetOutputBuffers();
 
   NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread),
                     NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop));
 
--- a/dom/mobileconnection/MobileConnection.cpp
+++ b/dom/mobileconnection/MobileConnection.cpp
@@ -1036,31 +1036,29 @@ MobileConnection::NotifyDataError(const 
 
   nsRefPtr<DataErrorEvent> event =
     DataErrorEvent::Constructor(this, NS_LITERAL_STRING("dataerror"), init);
 
   return DispatchTrustedEvent(event);
 }
 
 NS_IMETHODIMP
-MobileConnection::NotifyCFStateChanged(bool aSuccess,
-                                       unsigned short aAction,
+MobileConnection::NotifyCFStateChanged(unsigned short aAction,
                                        unsigned short aReason,
                                        const nsAString& aNumber,
                                        unsigned short aSeconds,
                                        unsigned short aServiceClass)
 {
   if (!CheckPermission("mobileconnection")) {
     return NS_OK;
   }
 
   CFStateChangeEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
-  init.mSuccess = aSuccess;
   init.mAction = aAction;
   init.mReason = aReason;
   init.mNumber = aNumber;
   init.mTimeSeconds = aSeconds;
   init.mServiceClass = aServiceClass;
 
   nsRefPtr<CFStateChangeEvent> event =
     CFStateChangeEvent::Constructor(this, NS_LITERAL_STRING("cfstatechange"), init);
--- a/dom/mobileconnection/gonk/MobileConnectionService.js
+++ b/dom/mobileconnection/gonk/MobileConnectionService.js
@@ -660,18 +660,18 @@ MobileConnectionProvider.prototype = {
 
     this.radioState = aRadioState;
     this.deliverListenerEvent("notifyRadioStateChanged");
   },
 
   notifyCFStateChanged: function(aAction, aReason, aNumber, aTimeSeconds,
                                  aServiceClass) {
     this.deliverListenerEvent("notifyCFStateChanged",
-                              [true, aAction, aReason, aNumber, aTimeSeconds,
-                                aServiceClass]);
+                              [aAction, aReason, aNumber, aTimeSeconds,
+                               aServiceClass]);
   },
 
   getSupportedNetworkTypes: function(aTypes) {
     aTypes.value = this.supportedNetworkTypes.slice();
     return aTypes.value.length;
   },
 
   getNetworks: function(aCallback) {
--- a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
+++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
@@ -7,17 +7,17 @@
 interface nsICellInfoListCallback;
 interface nsIMobileCallForwardingOptions;
 interface nsIMobileConnection;
 interface nsIMobileConnectionInfo;
 interface nsIMobileNetworkInfo;
 interface nsINeighboringCellIdsCallback;
 interface nsIVariant;
 
-[scriptable, uuid(823d935e-8262-47ed-8429-8203096b2ff4)]
+[scriptable, uuid(c00abd30-5b2e-11e4-8ed6-0800200c9a66)]
 interface nsIMobileConnectionListener : nsISupports
 {
   /**
    * Notify when voice info is changed.
    */
   void notifyVoiceChanged();
 
   /**
@@ -42,31 +42,28 @@ interface nsIMobileConnectionListener : 
    * @param message
    *        Error message from RIL.
    */
   void notifyDataError(in DOMString message);
 
   /**
    * Notify when call forwarding state is changed.
    *
-   * @param success
-   *        Indicates whether the set call forwarding request is success.
    * @param action
    *        One of the nsIMobileConnection.CALL_FORWARD_ACTION_* values.
    * @param reason
    *        One of the nsIMobileConnection.CALL_FORWARD_REASON_* values.
    * @param number
    *        Phone number of forwarding address.
    * @param timeSeconds
    *        The time in seconds should wait before call is forwarded.
    * @param serviceClass
    *        One of the nsIMobileConnection.ICC_SERVICE_CLASS_* values.
    */
-  void notifyCFStateChanged(in boolean success,
-                            in unsigned short action,
+  void notifyCFStateChanged(in unsigned short action,
                             in unsigned short reason,
                             in DOMString number,
                             in unsigned short timeSeconds,
                             in unsigned short serviceClass);
 
   /**
    * Notify when emergency callback mode is changed.
    *
--- a/dom/mobileconnection/ipc/MobileConnectionChild.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp
@@ -434,26 +434,25 @@ MobileConnectionChild::RecvNotifyDataErr
   for (int32_t i = 0; i < mListeners.Count(); i++) {
     mListeners[i]->NotifyDataError(aMessage);
   }
 
   return true;
 }
 
 bool
-MobileConnectionChild::RecvNotifyCFStateChanged(const bool& aSuccess,
-                                                const uint16_t& aAction,
+MobileConnectionChild::RecvNotifyCFStateChanged(const uint16_t& aAction,
                                                 const uint16_t& aReason,
                                                 const nsString& aNumber,
                                                 const uint16_t& aTimeSeconds,
                                                 const uint16_t& aServiceClass)
 {
   for (int32_t i = 0; i < mListeners.Count(); i++) {
-    mListeners[i]->NotifyCFStateChanged(aSuccess, aAction, aReason, aNumber,
-                                        aTimeSeconds, aServiceClass);
+    mListeners[i]->NotifyCFStateChanged(aAction, aReason, aNumber, aTimeSeconds,
+                                        aServiceClass);
   }
 
   return true;
 }
 
 bool
 MobileConnectionChild::RecvNotifyEmergencyCbModeChanged(const bool& aActive,
                                                         const uint32_t& aTimeoutMs)
--- a/dom/mobileconnection/ipc/MobileConnectionChild.h
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.h
@@ -72,19 +72,19 @@ protected:
   virtual bool
   RecvNotifyUssdReceived(const nsString& aMessage,
                          const bool& aSessionEnd) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyDataError(const nsString& aMessage) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifyCFStateChanged(const bool& aSuccess, const uint16_t& aAction,
-                           const uint16_t& aReason, const nsString& aNumber,
-                           const uint16_t& aTimeSeconds, const uint16_t& aServiceClass) MOZ_OVERRIDE;
+  RecvNotifyCFStateChanged(const uint16_t& aAction, const uint16_t& aReason,
+                           const nsString& aNumber, const uint16_t& aTimeSeconds,
+                           const uint16_t& aServiceClass) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyEmergencyCbModeChanged(const bool& aActive,
                                    const uint32_t& aTimeoutMs) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyOtaStatusChanged(const nsString& aStatus) MOZ_OVERRIDE;
 
--- a/dom/mobileconnection/ipc/MobileConnectionParent.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp
@@ -207,28 +207,26 @@ NS_IMETHODIMP
 MobileConnectionParent::NotifyDataError(const nsAString& aMessage)
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   return SendNotifyDataError(nsAutoString(aMessage)) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
-MobileConnectionParent::NotifyCFStateChanged(bool aSuccess,
-                                             uint16_t aAction,
+MobileConnectionParent::NotifyCFStateChanged(uint16_t aAction,
                                              uint16_t aReason,
                                              const nsAString &aNumber,
                                              uint16_t aTimeSeconds,
                                              uint16_t aServiceClass)
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
-  return SendNotifyCFStateChanged(aSuccess, aAction, aReason,
-                                  nsAutoString(aNumber), aTimeSeconds,
-                                  aServiceClass) ? NS_OK : NS_ERROR_FAILURE;
+  return SendNotifyCFStateChanged(aAction, aReason, nsAutoString(aNumber),
+                                  aTimeSeconds, aServiceClass) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyEmergencyCbModeChanged(bool aActive,
                                                      uint32_t aTimeoutMs)
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
--- a/dom/mobileconnection/ipc/PMobileConnection.ipdl
+++ b/dom/mobileconnection/ipc/PMobileConnection.ipdl
@@ -17,19 +17,18 @@ sync protocol PMobileConnection
   manager PContent;
   manages PMobileConnectionRequest;
 
 child:
   NotifyVoiceInfoChanged(nsMobileConnectionInfo aInfo);
   NotifyDataInfoChanged(nsMobileConnectionInfo aInfo);
   NotifyUssdReceived(nsString aMessage, bool aSessionEnd);
   NotifyDataError(nsString aMessage);
-  NotifyCFStateChanged(bool aSuccess, uint16_t aAction, uint16_t aReason,
-                       nsString aNumber, uint16_t aTimeSeconds,
-                       uint16_t aServiceClass);
+  NotifyCFStateChanged(uint16_t aAction, uint16_t aReason, nsString aNumber,
+                       uint16_t aTimeSeconds, uint16_t aServiceClass);
   NotifyEmergencyCbModeChanged(bool aActive, uint32_t aTimeoutMs);
   NotifyOtaStatusChanged(nsString aStatus);
   NotifyIccChanged(nsString aIccId);
   NotifyRadioStateChanged(int32_t aRadioState);
   NotifyClirModeChanged(uint32_t aMode);
   NotifyLastNetworkChanged(nsString aNetwork);
   NotifyLastHomeNetworkChanged(nsString aNetwork);
   NotifyNetworkSelectionModeChanged(int32_t aMode);
--- a/dom/mobileconnection/tests/marionette/test_mobile_call_forwarding.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_call_forwarding.js
@@ -24,17 +24,16 @@ const TEST_DATA = [
 
 function testSetCallForwardingOption(aOptions) {
   log("Test setting call forwarding to " + JSON.stringify(aOptions));
 
   let promises = [];
 
   // Check cfstatechange event.
   promises.push(waitForManagerEvent("cfstatechange").then(function(aEvent) {
-    is(aEvent.success, true, "check success");
     is(aEvent.action, aOptions.action, "check action");
     is(aEvent.reason, aOptions.reason, "check reason");
     is(aEvent.number, aOptions.number, "check number");
     is(aEvent.timeSeconds, aOptions.timeSeconds, "check timeSeconds");
     is(aEvent.serviceClass, aOptions.serviceClass, "check serviceClass");
   }));
   // Check DOMRequest's result.
   promises.push(setCallForwardingOption(aOptions).then(null, (aError) => {
--- a/dom/mobileconnection/tests/marionette/test_mobile_mmi_call_forwarding.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_mmi_call_forwarding.js
@@ -55,17 +55,16 @@ function testSetCallForwarding(aData) {
   let MMI_CODE = "**" + CF_REASON_TO_MMI[aData.reason] + "*" + aData.number +
                  "*" + SERVICE_CLASS_TO_MMI[aData.serviceClass] +
                  "*" + aData.timeSeconds + "#";
   log("Test " + MMI_CODE);
 
   let promises = [];
   // Check cfstatechange event.
   promises.push(waitForManagerEvent("cfstatechange").then(function(aEvent) {
-    is(aEvent.success, true, "check success");
     is(aEvent.action, MozMobileConnection.CALL_FORWARD_ACTION_REGISTRATION,
        "check action");
     is(aEvent.reason, aData.reason, "check reason");
     is(aEvent.number, aData.number, "check number");
     is(aEvent.timeSeconds, aData.timeSeconds, "check timeSeconds");
     is(aEvent.serviceClass, aData.serviceClass, "check serviceClass");
   }));
   // Check DOMRequest's result.
--- a/dom/network/tests/unit/test_multisend.js
+++ b/dom/network/tests/unit/test_multisend.js
@@ -24,17 +24,17 @@ const ServerSocket = CC("@mozilla.org/ne
 var server = null, sock = null;
 
 /**
  * Spin up a listening socket and associate at most one live, accepted socket
  * with ourselves.
  */
 function TestServer() {
   this.listener = ServerSocket(-1, true, -1);
-  do_print('server: listening on', this.listener.port);
+  do_print('server: listening on ' + this.listener.port);
   this.listener.asyncListen(this);
 
   this.binaryInput = null;
   this.input = null;
   this.binaryOutput = null;
   this.output = null;
 
   this.onaccept = null;
@@ -144,9 +144,9 @@ function run_test() {
     }
   };
   server.onclose = function() {};
 
   sock.onopen = function() {
     sock.send(ok.buffer, 0, 2);
     sock.send(ok.buffer, 2, 3);
   };
-}
\ No newline at end of file
+}
--- a/dom/network/tests/unit/test_tcpsocket.js
+++ b/dom/network/tests/unit/test_tcpsocket.js
@@ -86,17 +86,17 @@ function is_content() {
 }
 
 /**
  * Spin up a listening socket and associate at most one live, accepted socket
  * with ourselves.
  */
 function TestServer() {
   this.listener = ServerSocket(-1, true, -1);
-  do_print('server: listening on', this.listener.port);
+  do_print('server: listening on ' + this.listener.port);
   this.listener.asyncListen(this);
 
   this.binaryInput = null;
   this.input = null;
   this.binaryOutput = null;
   this.output = null;
 
   this.onconnect = null;
--- a/dom/telephony/test/marionette/test_mmi_call_forwarding.js
+++ b/dom/telephony/test/marionette/test_mmi_call_forwarding.js
@@ -100,17 +100,16 @@ function testSetCallForwarding(aData) {
   let MMI_CODE = "**" + CF_REASON_TO_MMI[aData.reason] + "*" + aData.number +
                  "*" + SERVICE_CLASS_TO_MMI[aData.serviceClass] +
                  "*" + aData.timeSeconds + "#";
   log("Test " + MMI_CODE);
 
   let promises = [];
   // Check cfstatechange event.
   promises.push(waitForManagerEvent("cfstatechange").then(function(aEvent) {
-    is(aEvent.success, true, "check success");
     is(aEvent.action, MozMobileConnection.CALL_FORWARD_ACTION_REGISTRATION,
        "check action");
     is(aEvent.reason, aData.reason, "check reason");
     is(aEvent.number, aData.number, "check number");
     is(aEvent.timeSeconds, aData.timeSeconds, "check timeSeconds");
     is(aEvent.serviceClass, aData.serviceClass, "check serviceClass");
   }));
   // Check DOMRequest's result.
--- a/dom/webidl/CFStateChangeEvent.webidl
+++ b/dom/webidl/CFStateChangeEvent.webidl
@@ -4,21 +4,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
 [Pref="dom.mobileconnection.enabled",
  Constructor(DOMString type, optional CFStateChangeEventInit eventInitDict)]
 interface CFStateChangeEvent : Event
 {
   /**
-   * Indicates about errors while setting up the Call forwarding rule.
-   */
-  readonly attribute boolean success;
-
-  /**
    * Indicates what to do with the rule.
    *
    * One of the CALL_FORWARD_ACTION_* constants. It will be either disable (0),
    * enable (1), query status (2), registration (3), or erasure (4).
    *
    * @see 3GPP MozMobileConnection.CALL_FORWARD_ACTION_* values.
    * @see 3GPP TS 27.007 7.11 "mode".
    */
@@ -51,15 +46,14 @@ interface CFStateChangeEvent : Event
    * Service for which the call forward is set up. It should be one of the
    * MozMobileConnection.ICC_SERVICE_CLASS_* values.
    */
   readonly attribute unsigned short serviceClass;
 };
 
 dictionary CFStateChangeEventInit : EventInit
 {
-  boolean success = false;
   unsigned short action = 0;
   unsigned short reason = 0;
   DOMString number = "";
   unsigned short timeSeconds = 0;
   unsigned short serviceClass = 0;
 };
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -1210,16 +1210,22 @@ var WifiManager = (function() {
     var done = 0;
     for (var n = 0; n < networkConfigurationFields.length; ++n) {
       let fieldName = networkConfigurationFields[n].name;
       let fieldType = networkConfigurationFields[n].type;
       wifiCommand.getNetworkVariable(netId, fieldName, function(value) {
         if (value !== null) {
           if (fieldType === "integer") {
             config[fieldName] = parseInt(value, 10);
+          } else if ( fieldName == "ssid" && value[0] != '"' ) {
+            // SET_NETWORK will set a quoted ssid to wpa_supplicant.
+            // But if ssid contains non-ascii char, it will be converted into utf-8.
+            // For example: "Test的wifi" --> 54657374e79a8477696669
+            // When GET_NETWORK receive a un-quoted utf-8 ssid, it must be decoded and quoted.
+            config[fieldName] = quote(decodeURIComponent(value.replace(/[0-9a-f]{2}/g, '%$&')));
           } else {
             // value is string type by default.
             config[fieldName] = value;
           }
         }
         if (++done == networkConfigurationFields.length)
           callback(config);
       });
new file mode 100644
--- /dev/null
+++ b/dom/workers/WorkerDebuggerManager.cpp
@@ -0,0 +1,236 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* 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 "WorkerDebuggerManager.h"
+
+#include "nsISimpleEnumerator.h"
+
+#include "WorkerPrivate.h"
+
+USING_WORKERS_NAMESPACE
+
+class RegisterDebuggerRunnable MOZ_FINAL : public nsRunnable
+{
+  nsRefPtr<WorkerDebuggerManager> mManager;
+  nsRefPtr<WorkerDebugger> mDebugger;
+  bool mHasListeners;
+
+public:
+  RegisterDebuggerRunnable(WorkerDebuggerManager* aManager,
+                           WorkerDebugger* aDebugger,
+                           bool aHasListeners)
+  : mManager(aManager), mDebugger(aDebugger), mHasListeners(aHasListeners)
+  { }
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+private:
+  ~RegisterDebuggerRunnable()
+  { }
+
+  NS_IMETHOD
+  Run() MOZ_OVERRIDE
+  {
+    mManager->RegisterDebuggerOnMainThread(mDebugger, mHasListeners);
+
+    return NS_OK;
+  }
+};
+
+NS_IMPL_ISUPPORTS(RegisterDebuggerRunnable, nsIRunnable);
+
+BEGIN_WORKERS_NAMESPACE
+
+class WorkerDebuggerEnumerator MOZ_FINAL : public nsISimpleEnumerator
+{
+  nsTArray<nsCOMPtr<nsISupports>> mDebuggers;
+  uint32_t mIndex;
+
+public:
+  WorkerDebuggerEnumerator(const nsTArray<WorkerDebugger*>& aDebuggers)
+  : mIndex(0)
+  {
+    mDebuggers.AppendElements(aDebuggers);
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISIMPLEENUMERATOR
+
+private:
+  ~WorkerDebuggerEnumerator() {}
+};
+
+NS_IMPL_ISUPPORTS(WorkerDebuggerEnumerator, nsISimpleEnumerator);
+
+NS_IMETHODIMP
+WorkerDebuggerEnumerator::HasMoreElements(bool* aResult)
+{
+  *aResult = mIndex < mDebuggers.Length();
+  return NS_OK;
+};
+
+NS_IMETHODIMP
+WorkerDebuggerEnumerator::GetNext(nsISupports** aResult)
+{
+  if (mIndex == mDebuggers.Length()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsISupports> element = mDebuggers.ElementAt(mIndex++);
+  element.forget(aResult);
+  return NS_OK;
+};
+
+WorkerDebuggerManager::WorkerDebuggerManager()
+: mMutex("WorkerDebuggerManager::mMutex")
+{
+  AssertIsOnMainThread();
+}
+
+WorkerDebuggerManager::~WorkerDebuggerManager()
+{
+  AssertIsOnMainThread();
+}
+
+NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIWorkerDebuggerManager);
+
+NS_IMETHODIMP
+WorkerDebuggerManager::GetWorkerDebuggerEnumerator(
+                                                  nsISimpleEnumerator** aResult)
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mMutex);
+
+  nsRefPtr<WorkerDebuggerEnumerator> enumerator =
+    new WorkerDebuggerEnumerator(mDebuggers);
+  enumerator.forget(aResult);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WorkerDebuggerManager::AddListener(nsIWorkerDebuggerManagerListener* aListener)
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mMutex);
+
+  if (mListeners.Contains(aListener)) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  mListeners.AppendElement(aListener);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WorkerDebuggerManager::RemoveListener(
+                                    nsIWorkerDebuggerManagerListener* aListener)
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mMutex);
+
+  if (!mListeners.Contains(aListener)) {
+    return NS_OK;
+  }
+
+  mListeners.RemoveElement(aListener);
+  return NS_OK;
+}
+
+void
+WorkerDebuggerManager::RegisterDebugger(WorkerDebugger* aDebugger)
+{
+  // May be called on any thread!
+
+  bool hasListeners = false;
+
+  {
+    MutexAutoLock lock(mMutex);
+
+    hasListeners = !mListeners.IsEmpty();
+  }
+
+  if (NS_IsMainThread()) {
+    RegisterDebuggerOnMainThread(aDebugger, hasListeners);
+  } else {
+    nsCOMPtr<nsIRunnable> runnable =
+      new RegisterDebuggerRunnable(this, aDebugger, hasListeners);
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+      NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
+
+    if (hasListeners) {
+      aDebugger->WaitIsEnabled(true);
+    }
+  }
+}
+
+void
+WorkerDebuggerManager::UnregisterDebugger(WorkerDebugger* aDebugger)
+{
+  // May be called on any thread!
+
+  if (NS_IsMainThread()) {
+    UnregisterDebuggerOnMainThread(aDebugger);
+  } else {
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewRunnableMethodWithArg<nsRefPtr<WorkerDebugger>>(this,
+        &WorkerDebuggerManager::UnregisterDebuggerOnMainThread, aDebugger);
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+      NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
+
+    aDebugger->WaitIsEnabled(false);
+  }
+}
+
+void
+WorkerDebuggerManager::RegisterDebuggerOnMainThread(WorkerDebugger* aDebugger,
+                                                    bool aHasListeners)
+{
+  AssertIsOnMainThread();
+
+  MOZ_ASSERT(!mDebuggers.Contains(aDebugger));
+  mDebuggers.AppendElement(aDebugger);
+
+  nsTArray<nsCOMPtr<nsIWorkerDebuggerManagerListener>> listeners;
+  {
+    MutexAutoLock lock(mMutex);
+
+    listeners.AppendElements(mListeners);
+  }
+
+  if (aHasListeners) {
+    for (size_t index = 0; index < listeners.Length(); ++index) {
+      listeners[index]->OnRegister(aDebugger);
+    }
+  }
+
+  aDebugger->Enable();
+}
+
+void
+WorkerDebuggerManager::UnregisterDebuggerOnMainThread(WorkerDebugger* aDebugger)
+{
+  AssertIsOnMainThread();
+
+  MOZ_ASSERT(mDebuggers.Contains(aDebugger));
+  mDebuggers.RemoveElement(aDebugger);
+
+  nsTArray<nsCOMPtr<nsIWorkerDebuggerManagerListener>> listeners;
+  {
+    MutexAutoLock lock(mMutex);
+
+    listeners.AppendElements(mListeners);
+  }
+
+  for (size_t index = 0; index < listeners.Length(); ++index) {
+    listeners[index]->OnUnregister(aDebugger);
+  }
+
+  aDebugger->Disable();
+}
+
+END_WORKERS_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/workers/WorkerDebuggerManager.h
@@ -0,0 +1,95 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* 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_workers_workerdebuggermanager_h
+#define mozilla_dom_workers_workerdebuggermanager_h
+
+#include "Workers.h"
+
+#include "nsIWorkerDebuggerManager.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsTArray.h"
+
+#define WORKERDEBUGGERMANAGER_CID \
+  { 0x62ec8731, 0x55ad, 0x4246, \
+    { 0xb2, 0xea, 0xf2, 0x6c, 0x1f, 0xe1, 0x9d, 0x2d } }
+#define WORKERDEBUGGERMANAGER_CONTRACTID \
+  "@mozilla.org/dom/workers/workerdebuggermanager;1"
+
+class RegisterDebuggerRunnable;
+
+BEGIN_WORKERS_NAMESPACE
+
+class WorkerDebugger;
+
+class WorkerDebuggerManager MOZ_FINAL : public nsIWorkerDebuggerManager
+{
+  friend class ::RegisterDebuggerRunnable;
+
+  mozilla::Mutex mMutex;
+
+  // Protected by mMutex.
+  nsTArray<nsCOMPtr<nsIWorkerDebuggerManagerListener>> mListeners;
+
+  // Only touched on the main thread.
+  nsTArray<WorkerDebugger*> mDebuggers;
+
+public:
+  static WorkerDebuggerManager*
+  GetOrCreateService()
+  {
+    nsCOMPtr<nsIWorkerDebuggerManager> wdm =
+      do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID);
+    return static_cast<WorkerDebuggerManager*>(wdm.get());
+  }
+
+  WorkerDebuggerManager();
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIWORKERDEBUGGERMANAGER
+
+  void RegisterDebugger(WorkerDebugger* aDebugger);
+
+  void UnregisterDebugger(WorkerDebugger* aDebugger);
+
+private:
+  virtual ~WorkerDebuggerManager();
+
+  void RegisterDebuggerOnMainThread(WorkerDebugger* aDebugger,
+                                    bool aHasListeners);
+
+  void UnregisterDebuggerOnMainThread(WorkerDebugger* aDebugger);
+};
+
+inline nsresult
+RegisterWorkerDebugger(WorkerDebugger* aDebugger)
+{
+  nsRefPtr<WorkerDebuggerManager> manager =
+    WorkerDebuggerManager::GetOrCreateService();
+  if (!manager) {
+    return NS_ERROR_FAILURE;
+  }
+
+  manager->RegisterDebugger(aDebugger);
+  return NS_OK;
+}
+
+inline nsresult
+UnregisterWorkerDebugger(WorkerDebugger* aDebugger)
+{
+  nsRefPtr<WorkerDebuggerManager> manager =
+    WorkerDebuggerManager::GetOrCreateService();
+  if (!manager) {
+    return NS_ERROR_FAILURE;
+  }
+
+  manager->UnregisterDebugger(aDebugger);
+  return NS_OK;
+}
+
+END_WORKERS_NAMESPACE
+
+#endif // mozilla_dom_workers_workerdebuggermanager_h
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -22,16 +22,17 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsPerformance.h"
 #include "nsPIDOMWindow.h"
 #include "nsITextToSubURI.h"
 #include "nsIThreadInternal.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
+#include "nsIWorkerDebugger.h"
 #include "nsIXPConnect.h"
 
 #include <algorithm>
 #include "jsfriendapi.h"
 #include "js/MemoryMetrics.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ContentEvents.h"
@@ -75,16 +76,17 @@
 
 #include "MessagePort.h"
 #include "Navigator.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "ServiceWorkerManager.h"
 #include "SharedWorker.h"
+#include "WorkerDebuggerManager.h"
 #include "WorkerFeature.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
 // JS_MaybeGC will run once every second during normal execution.
 #define PERIODIC_GC_TIMER_DELAY_SEC 1
 
 // A shrinking GC will run five seconds after the last event is processed.
@@ -651,16 +653,18 @@ private:
       new MainThreadReleaseRunnable(doomed, hostObjectURIs);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       NS_WARNING("Failed to dispatch, going to leak!");
     }
 
     RuntimeService* runtime = RuntimeService::GetService();
     NS_ASSERTION(runtime, "This should never be null!");
 
+    mFinishedWorker->DisableDebugger();
+
     runtime->UnregisterWorker(aCx, mFinishedWorker);
 
     mFinishedWorker->ClearSelfRef();
     return true;
   }
 };
 
 class TopLevelWorkerFinishedRunnable MOZ_FINAL : public nsRunnable
@@ -685,16 +689,18 @@ private:
     AssertIsOnMainThread();
 
     RuntimeService* runtime = RuntimeService::GetService();
     MOZ_ASSERT(runtime);
 
     AutoSafeJSContext cx;
     JSAutoRequest ar(cx);
 
+    mFinishedWorker->DisableDebugger();
+
     runtime->UnregisterWorker(cx, mFinishedWorker);
 
     nsTArray<nsCOMPtr<nsISupports> > doomed;
     mFinishedWorker->ForgetMainThreadObjects(doomed);
 
     nsTArray<nsCString> hostObjectURIs;
     mFinishedWorker->StealHostObjectURIs(hostObjectURIs);
 
@@ -2138,16 +2144,52 @@ WorkerPrivateParent<Derived>::DispatchPr
 
     mCondVar.Notify();
   }
 
   return NS_OK;
 }
 
 template <class Derived>
+void
+WorkerPrivateParent<Derived>::EnableDebugger()
+{
+  AssertIsOnParentThread();
+
+  WorkerPrivate* self = ParentAsWorkerPrivate();
+
+  MOZ_ASSERT(!self->mDebugger);
+  self->mDebugger = new WorkerDebugger(self);
+
+  if (NS_FAILED(RegisterWorkerDebugger(self->mDebugger))) {
+    NS_WARNING("Failed to register worker debugger!");
+    self->mDebugger = nullptr;
+  }
+}
+
+template <class Derived>
+void
+WorkerPrivateParent<Derived>::DisableDebugger()
+{
+  AssertIsOnParentThread();
+
+  WorkerPrivate* self = ParentAsWorkerPrivate();
+
+  if (!self->mDebugger) {
+    return;
+  }
+
+  if (NS_FAILED(UnregisterWorkerDebugger(self->mDebugger))) {
+    NS_WARNING("Failed to unregister worker debugger!");
+  }
+
+  self->mDebugger = nullptr;
+}
+
+template <class Derived>
 nsresult
 WorkerPrivateParent<Derived>::DispatchControlRunnable(
                                   WorkerControlRunnable* aWorkerControlRunnable)
 {
   // May be called on any thread!
 
   MOZ_ASSERT(aWorkerControlRunnable);
 
@@ -3443,16 +3485,104 @@ WorkerPrivateParent<Derived>::AssertInne
   AssertIsOnMainThread();
 
   nsPIDOMWindow* outer = mLoadInfo.mWindow->GetOuterWindow();
   NS_ASSERTION(outer && outer->GetCurrentInnerWindow() == mLoadInfo.mWindow,
                "Inner window no longer correct!");
 }
 
 #endif
+
+WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
+: mMutex("WorkerDebugger::mMutex"),
+  mCondVar(mMutex, "WorkerDebugger::mCondVar"),
+  mWorkerPrivate(aWorkerPrivate),
+  mIsEnabled(false)
+{
+  mWorkerPrivate->AssertIsOnParentThread();
+}
+
+WorkerDebugger::~WorkerDebugger()
+{
+  MOZ_ASSERT(!mWorkerPrivate);
+}
+
+NS_IMPL_ISUPPORTS(WorkerDebugger, nsIWorkerDebugger)
+
+NS_IMETHODIMP
+WorkerDebugger::GetIsClosed(bool* aResult)
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mMutex);
+
+  *aResult = !mWorkerPrivate;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WorkerDebugger::GetUrl(nsAString& aResult)
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mMutex);
+
+  if (!mWorkerPrivate) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  aResult = mWorkerPrivate->ScriptURL();
+  return NS_OK;
+}
+
+void
+WorkerDebugger::WaitIsEnabled(bool aIsEnabled)
+{
+  MutexAutoLock lock(mMutex);
+
+  while (mIsEnabled != aIsEnabled) {
+    mCondVar.Wait();
+  }
+}
+
+void
+WorkerDebugger::NotifyIsEnabled(bool aIsEnabled)
+{
+  mMutex.AssertCurrentThreadOwns();
+
+  MOZ_ASSERT(mIsEnabled != aIsEnabled);
+  mIsEnabled = aIsEnabled;
+  mCondVar.Notify();
+}
+
+void
+WorkerDebugger::Enable()
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mMutex);
+
+  MOZ_ASSERT(mWorkerPrivate);
+
+  NotifyIsEnabled(true);
+}
+
+void
+WorkerDebugger::Disable()
+{
+  AssertIsOnMainThread();
+
+  MutexAutoLock lock(mMutex);
+
+  MOZ_ASSERT(mWorkerPrivate);
+  mWorkerPrivate = nullptr;
+
+  NotifyIsEnabled(false);
+}
+
 WorkerPrivate::WorkerPrivate(JSContext* aCx,
                              WorkerPrivate* aParent,
                              const nsAString& aScriptURL,
                              bool aIsChromeWorker, WorkerType aWorkerType,
                              const nsACString& aSharedWorkerName,
                              LoadInfo& aLoadInfo)
 : WorkerPrivateParent<WorkerPrivate>(aCx, aParent, aScriptURL,
                                      aIsChromeWorker, aWorkerType,
@@ -3616,16 +3746,18 @@ WorkerPrivate::Constructor(JSContext* aC
     new WorkerPrivate(aCx, parent, aScriptURL, aIsChromeWorker,
                       aWorkerType, aSharedWorkerName, *aLoadInfo);
 
   if (!runtimeService->RegisterWorker(aCx, worker)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
+  worker->EnableDebugger();
+
   nsRefPtr<CompileScriptRunnable> compiler = new CompileScriptRunnable(worker);
   if (!compiler->Dispatch(aCx)) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   worker->mSelfRef = worker;
 
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_workerprivate_h__
 #define mozilla_dom_workers_workerprivate_h__
 
 #include "Workers.h"
 
 #include "nsIContentSecurityPolicy.h"
+#include "nsIWorkerDebugger.h"
 #include "nsPIDOMWindow.h"
 
 #include "mozilla/CondVar.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
@@ -56,16 +57,17 @@ BEGIN_WORKERS_NAMESPACE
 
 class AutoSyncLoopHolder;
 class MessagePort;
 class SharedWorker;
 class WorkerControlRunnable;
 class WorkerGlobalScope;
 class WorkerPrivate;
 class WorkerRunnable;
+class WorkerDebugger;
 
 enum WorkerType
 {
   WorkerTypeDedicated,
   WorkerTypeShared,
   WorkerTypeService
 };
 
@@ -290,16 +292,22 @@ public:
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,
                                                          DOMEventTargetHelper)
 
   void
+  EnableDebugger();
+
+  void
+  DisableDebugger();
+
+  void
   ClearSelfRef()
   {
     AssertIsOnParentThread();
     MOZ_ASSERT(mSelfRef);
     mSelfRef = nullptr;
   }
 
   nsresult
@@ -716,16 +724,44 @@ public:
   { }
 
   void
   AssertInnerWindowIsCorrect() const
   { }
 #endif
 };
 
+class WorkerDebugger : public nsIWorkerDebugger {
+  mozilla::Mutex mMutex;
+  mozilla::CondVar mCondVar;
+
+  // Protected by mMutex
+  WorkerPrivate* mWorkerPrivate;
+  bool mIsEnabled;
+
+public:
+  WorkerDebugger(WorkerPrivate* aWorkerPrivate);
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIWORKERDEBUGGER
+
+  void AssertIsOnParentThread();
+
+  void WaitIsEnabled(bool aIsEnabled);
+
+  void Enable();
+
+  void Disable();
+
+private:
+  virtual ~WorkerDebugger();
+
+  void NotifyIsEnabled(bool aIsEnabled);
+};
+
 class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
 {
   friend class WorkerPrivateParent<WorkerPrivate>;
   typedef WorkerPrivateParent<WorkerPrivate> ParentType;
   friend class AutoSyncLoopHolder;
 
   struct TimeoutInfo;
 
@@ -734,16 +770,18 @@ class WorkerPrivate : public WorkerPriva
 
   enum GCTimerMode
   {
     PeriodicTimer = 0,
     IdleTimer,
     NoTimer
   };
 
+  nsRefPtr<WorkerDebugger> mDebugger;
+
   Queue<WorkerControlRunnable*, 4> mControlQueue;
 
   // Touched on multiple threads, protected with mMutex.
   JSContext* mJSContext;
   nsRefPtr<WorkerCrossThreadDispatcher> mCrossThreadDispatcher;
   nsTArray<nsCOMPtr<nsIRunnable>> mUndispatchedRunnablesForSyncLoop;
   nsCOMPtr<nsIThread> mThread;
 
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -11,16 +11,17 @@ EXPORTS.mozilla.dom += [
     'ServiceWorkerRegistration.h',
     'WorkerPrivate.h',
     'WorkerRunnable.h',
     'WorkerScope.h',
 ]
 
 EXPORTS.mozilla.dom.workers += [
     'ServiceWorkerManager.h',
+    'WorkerDebuggerManager.h',
     'Workers.h',
 ]
 
 # Stuff needed for the bindings, not really public though.
 EXPORTS.mozilla.dom.workers.bindings += [
     'DataStore.h',
     'DataStoreCursor.h',
     'FileReaderSync.h',
@@ -31,16 +32,23 @@ EXPORTS.mozilla.dom.workers.bindings += 
     'ServiceWorker.h',
     'SharedWorker.h',
     'URL.h',
     'WorkerFeature.h',
     'XMLHttpRequest.h',
     'XMLHttpRequestUpload.h',
 ]
 
+XPIDL_MODULE = 'dom_workers'
+
+XPIDL_SOURCES += [
+    'nsIWorkerDebugger.idl',
+    'nsIWorkerDebuggerManager.idl',
+]
+
 UNIFIED_SOURCES += [
     'ChromeWorkerScope.cpp',
     'DataStore.cpp',
     'DataStoreCursor.cpp',
     'FileReaderSync.cpp',
     'Location.cpp',
     'MessagePort.cpp',
     'Navigator.cpp',
@@ -51,16 +59,17 @@ UNIFIED_SOURCES += [
     'ScriptLoader.cpp',
     'ServiceWorker.cpp',
     'ServiceWorkerContainer.cpp',
     'ServiceWorkerEvents.cpp',
     'ServiceWorkerManager.cpp',
     'ServiceWorkerRegistration.cpp',
     'SharedWorker.cpp',
     'URL.cpp',
+    'WorkerDebuggerManager.cpp',
     'WorkerPrivate.cpp',
     'WorkerRunnable.cpp',
     'WorkerScope.cpp',
     'XMLHttpRequest.cpp',
     'XMLHttpRequestUpload.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
new file mode 100644
--- /dev/null
+++ b/dom/workers/nsIWorkerDebugger.idl
@@ -0,0 +1,9 @@
+#include "nsISupports.idl"
+
+[scriptable, builtinclass, uuid(0833b363-bffe-4cdb-ad50-1c4563e0C8ff)]
+interface nsIWorkerDebugger : nsISupports
+{
+  readonly attribute bool isClosed;
+
+  readonly attribute DOMString url;
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/nsIWorkerDebuggerManager.idl
@@ -0,0 +1,22 @@
+#include "nsISupports.idl"
+
+interface nsISimpleEnumerator;
+interface nsIWorkerDebugger;
+
+[scriptable, uuid(d2aa74ee-6b98-4d5d-8173-4e23422daf1e)]
+interface nsIWorkerDebuggerManagerListener : nsISupports
+{
+  void onRegister(in nsIWorkerDebugger debugger);
+
+  void onUnregister(in nsIWorkerDebugger debugger);
+};
+
+[scriptable, builtinclass, uuid(056d7918-dc86-452a-b4e6-86da3405f015)]
+interface nsIWorkerDebuggerManager : nsISupports
+{
+  nsISimpleEnumerator getWorkerDebuggerEnumerator();
+
+  void addListener(in nsIWorkerDebuggerManagerListener listener);
+
+  void removeListener(in nsIWorkerDebuggerManagerListener listener);
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerManager_childWorker.js
@@ -0,0 +1,3 @@
+"use strict";
+
+onmessage = function () {};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/WorkerDebuggerManager_parentWorker.js
@@ -0,0 +1,3 @@
+"use strict";
+
+var worker = new Worker("WorkerDebuggerManager_childWorker.js");
--- a/dom/workers/test/chrome.ini
+++ b/dom/workers/test/chrome.ini
@@ -1,30 +1,35 @@
 [DEFAULT]
 support-files =
+  WorkerDebuggerManager_childWorker.js
+  WorkerDebuggerManager_parentWorker.js
   WorkerTest.jsm
   WorkerTest_subworker.js
   WorkerTest_worker.js
   chromeWorker_subworker.js
   chromeWorker_worker.js
   dom_worker_helper.js
+  file_url.jsm
+  file_worker.js
   fileBlobSubWorker_worker.js
   fileBlob_worker.js
   filePosting_worker.js
   fileReadSlice_worker.js
   fileReaderSyncErrors_worker.js
   fileReaderSync_worker.js
   fileSlice_worker.js
   fileSubWorker_worker.js
   file_worker.js
   jsm_url_worker.js
   workersDisabled_worker.js
   file_url.jsm
   bug1062920_worker.js
 
+[test_WorkerDebuggerManager.xul]
 [test_bug883784.jsm]
 [test_bug883784.xul]
 [test_chromeWorker.xul]
 [test_chromeWorkerJSM.xul]
 [test_extension.xul]
 [test_extensionBootstrap.xul]
 [test_file.xul]
 [test_fileBlobPosting.xul]
--- a/dom/workers/test/dom_worker_helper.js
+++ b/dom/workers/test/dom_worker_helper.js
@@ -1,21 +1,102 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/AddonManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].
+            getService(Ci.nsIWorkerDebuggerManager);
+
 var gRemainingTests = 0;
 
 function waitForWorkerFinish() {
   if (gRemainingTests == 0) {
     SimpleTest.waitForExplicitFinish();
   }
   ++gRemainingTests;
 }
 
 function finish() {
   --gRemainingTests;
   if (gRemainingTests == 0) {
     SimpleTest.finish();
   }
 }
 
+function assertThrows(fun, message) {
+  let throws = false;
+  try {
+    fun();
+  } catch (e) {
+    throws = true;
+  }
+  ok(throws, message);
+}
+
+function* generateDebuggers() {
+  let e = wdm.getWorkerDebuggerEnumerator();
+  while (e.hasMoreElements()) {
+    let dbg = e.getNext().QueryInterface(Ci.nsIWorkerDebugger);
+    yield dbg;
+  }
+}
+
+function findDebugger(predicate) {
+  for (let dbg of generateDebuggers()) {
+    if (predicate(dbg)) {
+      return dbg;
+    }
+  }
+  return null;
+}
+
+function waitForRegister(predicate = () => true) {
+  return new Promise(function (resolve) {
+    wdm.addListener({
+      onRegister: function (dbg) {
+        if (!predicate(dbg)) {
+          return;
+        }
+        wdm.removeListener(this);
+        resolve(dbg);
+      }
+    });
+  });
+}
+
+function waitForUnregister(predicate = () => true) {
+  return new Promise(function (resolve) {
+    wdm.addListener({
+      onUnregister: function (dbg) {
+        if (!predicate(dbg)) {
+          return;
+        }
+        wdm.removeListener(this);
+        resolve(dbg);
+      }
+    });
+  });
+}
+
+function waitForMultiple(promises) {
+  return new Promise(function (resolve) {
+    let results = [];
+    for (let i = 0; i < promises.length; ++i) {
+      let promise = promises[i];
+      let index = i;
+      promise.then(function (result) {
+        is(results.length, index, "events should occur in the specified order");
+        results.push(result);
+        if (results.length === promises.length) {
+          resolve(results);
+        }
+      });
+    }
+  });
+};
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_WorkerDebuggerManager.xul
@@ -0,0 +1,92 @@
+<?xml version="1.0"?>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<window title="Test for WorkerDebuggerManager"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        onload="test();">
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+  <script type="application/javascript" src="dom_worker_helper.js"/>
+
+  <script type="application/javascript">
+  <![CDATA[
+
+    const PARENT_WORKER_URL = "WorkerDebuggerManager_parentWorker.js";
+    const CHILD_WORKER_URL = "WorkerDebuggerManager_childWorker.js";
+
+    function test() {
+      Task.spawn(function* () {
+        SimpleTest.waitForExplicitFinish();
+
+        ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
+           "debugger for parent worker should not be enumerated before it is " +
+           "registered");
+        ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
+           "debugger for child worker should not be enumerated before it is " +
+           "registered");
+
+        let promise = waitForMultiple([
+          waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
+          waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
+        ]);
+        let worker = new Worker(PARENT_WORKER_URL);
+        let dbgs = yield promise;
+        is(dbgs[0].isClosed, false,
+           "debugger for parent worker should not be closed after it is " +
+           "registered");
+        is(dbgs[1].isClosed, false,
+           "debugger for child worker should not be closed after it is " +
+            "registered");
+
+        ok(findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
+           "debugger for parent worker should be enumerated after it is " +
+           "registered");
+        ok(findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
+           "debugger for child worker should be enumerated after it is " +
+           "registered");
+
+        promise = waitForMultiple([
+          waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
+          waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
+        ]);
+        worker.terminate();
+        dbgs = yield promise;
+        is(dbgs[0].isClosed, true,
+           "debugger for parent worker should be closed after it is " +
+           "unregistered");
+        is(dbgs[1].isClosed, true,
+           "debugger for child worker should be closed after it is " +
+           "unregistered");
+        assertThrows(() => dbgs[0].url,
+                     "accessing debugger for parent worker should throw " +
+                     "after it is closed");
+        assertThrows(() => dbgs[0].url,
+                     "accessing debugger for child worker should throw after " +
+                     "it is closed");
+
+        ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
+           "debugger for parent worker should not be enumerated after it is " +
+           "unregistered");
+        ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
+           "debugger for child worker should not be enumerated after it is " +
+           "unregistered");
+
+        SimpleTest.finish();
+      });
+    }
+
+  ]]>
+  </script>
+
+  <body xmlns="http://www.w3.org/1999/xhtml">
+    <p id="display"></p>
+    <div id="content" style="display:none;"></div>
+    <pre id="test"></pre>
+  </body>
+  <label id="test-result"/>
+</window>
--- a/dom/workers/test/test_extension.xul
+++ b/dom/workers/test/test_extension.xul
@@ -11,23 +11,16 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
   <script type="application/javascript" src="dom_worker_helper.js"/>
 
   <script type="application/javascript">
   <![CDATA[
 
-    const Cc = Components.classes;
-    const Ci = Components.interfaces;
-    const Cu = Components.utils;
-
-    Cu.import("resource://gre/modules/Services.jsm");
-    Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
     function test() {
       const message = "woohoo";
 
       var workertest =
         Cc["@mozilla.org/test/workertest;1"].createInstance(Ci.nsIWorkerTest);
 
       workertest.callback = {
         onmessage: function(data) {
--- a/dom/workers/test/test_extensionBootstrap.xul
+++ b/dom/workers/test/test_extensionBootstrap.xul
@@ -11,24 +11,16 @@
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
   <script type="application/javascript" src="dom_worker_helper.js"/>
 
   <script type="application/javascript">
   <![CDATA[
 
-    const Cc = Components.classes;
-    const Ci = Components.interfaces;
-    const Cu = Components.utils;
-
-    Cu.import("resource://gre/modules/AddonManager.jsm");
-    Cu.import("resource://gre/modules/Services.jsm");
-    Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
     function test() {
       const message = "woohoo";
 
       var observer = {
         observe: function(subject, topic, data) {
           is(topic, "message", "Correct type of event");
           is(data, message, "Correct message");
 
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -1,23 +1,23 @@
 /* -*- Mode: C++; tab-width: 8; 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 "APZCTreeManager.h"
 #include "AsyncPanZoomController.h"
 #include "Compositor.h"                 // for Compositor
-#include "CompositorParent.h"           // for CompositorParent, etc
 #include "InputBlockState.h"            // for InputBlockState
 #include "InputData.h"                  // for InputData, etc
 #include "Layers.h"                     // for Layer, etc
 #include "mozilla/dom/Touch.h"          // for Touch
 #include "mozilla/gfx/Point.h"          // for Point
 #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
+#include "mozilla/layers/CompositorParent.h" // for CompositorParent, etc
 #include "mozilla/layers/LayerMetricsWrapper.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/mozalloc.h"           // for operator new
 #include "mozilla/TouchEvents.h"
 #include "mozilla/Preferences.h"        // for Preferences
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsThreadUtils.h"              // for NS_IsMainThread
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -6,17 +6,16 @@
 
 #include <math.h>                       // for fabsf, fabs, atan2
 #include <stdint.h>                     // for uint32_t, uint64_t
 #include <sys/types.h>                  // for int32_t
 #include <algorithm>                    // for max, min
 #include "AsyncPanZoomController.h"     // for AsyncPanZoomController, etc
 #include "Axis.h"                       // for AxisX, AxisY, Axis, etc
 #include "Compositor.h"                 // for Compositor
-#include "CompositorParent.h"           // for CompositorParent
 #include "FrameMetrics.h"               // for FrameMetrics, etc
 #include "GestureEventListener.h"       // for GestureEventListener
 #include "InputData.h"                  // for MultiTouchInput, etc
 #include "InputBlockState.h"            // for InputBlockState, TouchBlockState
 #include "InputQueue.h"                 // for InputQueue
 #include "OverscrollHandoffState.h"     // for OverscrollHandoffState
 #include "TaskThrottler.h"              // for TaskThrottler
 #include "Units.h"                      // for CSSRect, CSSPoint, etc
@@ -41,16 +40,17 @@
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/Point.h"          // for Point, RoundedToInt, etc
 #include "mozilla/gfx/Rect.h"           // for RoundedIn
 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
 #include "mozilla/layers/APZCTreeManager.h"  // for ScrollableLayerGuid
 #include "mozilla/layers/AsyncCompositionManager.h"  // for ViewTransform
 #include "mozilla/layers/AxisPhysicsModel.h" // for AxisPhysicsModel
 #include "mozilla/layers/AxisPhysicsMSDModel.h" // for AxisPhysicsMSDModel
+#include "mozilla/layers/CompositorParent.h" // for CompositorParent
 #include "mozilla/layers/LayerTransactionParent.h" // for LayerTransactionParent
 #include "mozilla/layers/PCompositorParent.h" // for PCompositorParent
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/unused.h"             // for unused
 #include "mozilla/FloatingPoint.h"      // for FuzzyEquals*
 #include "nsAlgorithm.h"                // for clamped
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -1,25 +1,25 @@
 /* -*- Mode: C++; tab-width: 20; 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 "CanvasClient.h"
 
 #include "ClientCanvasLayer.h"          // for ClientCanvasLayer
-#include "CompositorChild.h"            // for CompositorChild
 #include "GLContext.h"                  // for GLContext
 #include "GLScreenBuffer.h"             // for GLScreenBuffer
 #include "ScopedGLHelpers.h"
 #include "gfx2DGlue.h"                  // for ImageFormatToSurfaceFormat
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "GLReadTexImageHelper.h"
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/CompositorChild.h" // for CompositorChild
 #include "mozilla/layers/GrallocTextureClient.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/layers/TextureClientOGL.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for printf_stderr, NS_ASSERTION
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
 #ifdef MOZ_WIDGET_GONK
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -1,23 +1,23 @@
 /* -*- 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 "ClientLayerManager.h"
-#include "CompositorChild.h"            // for CompositorChild
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "gfxPrefs.h"                   // for gfxPrefs::LayersTile...
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Hal.h"
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/dom/TabChild.h"       // for TabChild
 #include "mozilla/hal_sandbox/PHal.h"   // for ScreenConfiguration
 #include "mozilla/layers/CompositableClient.h"
+#include "mozilla/layers/CompositorChild.h" // for CompositorChild
 #include "mozilla/layers/ContentClient.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/PLayerChild.h"  // for PLayerChild
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
 #include "ClientReadbackLayer.h"        // for ClientReadbackLayer
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -1,30 +1,30 @@
 /* -*- Mode: C++; tab-width: 20; 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 "mozilla/layers/ContentClient.h"
 #include "BasicLayers.h"                // for BasicLayerManager
-#include "CompositorChild.h"            // for CompositorChild
 #include "gfxColor.h"                   // for gfxRGBA
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
 #include "gfxTeeSurface.h"              // for gfxTeeSurface
 #include "gfxUtils.h"                   // for gfxUtils
 #include "ipc/ShadowLayers.h"           // for ShadowLayerForwarder
 #include "mozilla/ArrayUtils.h"         // for ArrayLength
 #include "mozilla/gfx/2D.h"             // for DrawTarget, Factory
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Types.h"
+#include "mozilla/layers/CompositorChild.h" // for CompositorChild
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersMessages.h"  // for ThebesBufferData
 #include "mozilla/layers/LayersTypes.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "prenv.h"                      // for PR_GetEnv
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -4,26 +4,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/TiledContentClient.h"
 #include <math.h>                       // for ceil, ceilf, floor
 #include <algorithm>
 #include "ClientTiledPaintedLayer.h"     // for ClientTiledPaintedLayer
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "ClientLayerManager.h"         // for ClientLayerManager
-#include "CompositorChild.h"            // for CompositorChild
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/MathAlgorithms.h"     // for Abs
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/gfx/Tools.h"          // for BytesPerPixel
 #include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/CompositorChild.h" // for CompositorChild
 #include "mozilla/layers/LayerMetricsWrapper.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "TextureClientPool.h"
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "gfxReusableSharedImageSurfaceWrapper.h"
 #include "nsExpirationTracker.h"        // for nsExpirationTracker
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -2,29 +2,29 @@
 /* vim: set sw=2 ts=2 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 "mozilla/layers/AsyncCompositionManager.h"
 #include <stdint.h>                     // for uint32_t
 #include "apz/src/AsyncPanZoomController.h"
-#include "CompositorParent.h"           // for CompositorParent, etc
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "LayerManagerComposite.h"      // for LayerManagerComposite, etc
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "gfxPoint.h"                   // for gfxPoint, gfxSize
 #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
 #include "mozilla/WidgetUtils.h"        // for ComputeTransformForRotation
 #include "mozilla/dom/AnimationPlayer.h" // for AnimationPlayer
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/Point.h"          // for RoundedToInt, PointTyped
 #include "mozilla/gfx/Rect.h"           // for RoundedToInt, RectTyped
 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
 #include "mozilla/layers/Compositor.h"  // for Compositor
+#include "mozilla/layers/CompositorParent.h" // for CompositorParent, etc
 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
 #include "nsCSSPropList.h"
 #include "nsCoord.h"                    // for NSAppUnitsToFloatPixels, etc
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
 #include "nsDeviceContext.h"            // for nsDeviceContext
 #include "nsDisplayList.h"              // for nsDisplayTransform, etc
 #include "nsMathUtils.h"                // for NS_round
 #include "nsPoint.h"                    // for nsPoint
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=2 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 "CompositorChild.h"
+#include "mozilla/layers/CompositorChild.h"
 #include <stddef.h>                     // for size_t
 #include "ClientLayerManager.h"         // for ClientLayerManager
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/process_util.h"          // for OpenProcessHandle
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=2 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 "CompositorParent.h"
+#include "mozilla/layers/CompositorParent.h"
 #include <stdio.h>                      // for fprintf, stdout
 #include <stdint.h>                     // for uint64_t
 #include <map>                          // for _Rb_tree_iterator, etc
 #include <utility>                      // for pair
 #include "LayerTransactionParent.h"     // for LayerTransactionParent
 #include "RenderTrace.h"                // for RenderTraceLayers
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/process.h"               // for ProcessHandle
@@ -18,31 +18,31 @@
 #include "base/thread.h"                // for Thread
 #include "base/tracked.h"               // for FROM_HERE
 #include "gfxContext.h"                 // for gfxContext
 #include "gfxPlatform.h"                // for gfxPlatform
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"             // for gfxPlatform
 #endif
 #include "gfxPrefs.h"                   // for gfxPrefs
-#include "ipc/ShadowLayersManager.h"    // for ShadowLayersManager
 #include "mozilla/AutoRestore.h"        // for AutoRestore
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/gfx/2D.h"          // for DrawTarget
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/layers/APZCTreeManager.h"  // for APZCTreeManager
 #include "mozilla/layers/AsyncCompositionManager.h"
 #include "mozilla/layers/BasicCompositor.h"  // for BasicCompositor
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
+#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #ifdef MOZ_WIDGET_GTK
 #include "basic/X11BasicCompositor.h" // for X11BasicCompositor
 #endif
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE, etc
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsIWidget.h"                  // for nsIWidget
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -12,29 +12,29 @@
 // its responsiveness objectives:
 //    1) Compose a frame within 15ms of receiving a ScheduleCompositeCall
 //    2) Unless a frame was composited within the throttle threshold in
 //       which the deadline will be 15ms + throttle threshold
 //#define COMPOSITOR_PERFORMANCE_WARNING
 
 #include <stdint.h>                     // for uint64_t
 #include "Layers.h"                     // for Layer
-#include "ShadowLayersManager.h"        // for ShadowLayersManager
 #include "base/basictypes.h"            // for DISALLOW_EVIL_CONSTRUCTORS
 #include "base/platform_thread.h"       // for PlatformThreadId
 #include "base/thread.h"                // for Thread
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/Monitor.h"            // for Monitor
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/GeckoContentController.h"
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "mozilla/layers/PCompositorParent.h"
+#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
 #include "mozilla/layers/APZTestData.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"
 #include "nsSize.h"                     // for nsIntSize
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 #include "mozilla/VsyncDispatcher.h"
 
 class CancelableTask;
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; 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 "ImageBridgeChild.h"
 #include <vector>                       // for vector
-#include "CompositorParent.h"           // for CompositorParent
 #include "ImageBridgeParent.h"          // for ImageBridgeParent
 #include "ImageContainer.h"             // for ImageContainer
 #include "Layers.h"                     // for Layer, etc
 #include "ShadowLayers.h"               // for ShadowLayerForwarder
 #include "base/message_loop.h"          // for MessageLoop
 #include "base/platform_thread.h"       // for PlatformThread
 #include "base/process.h"               // for ProcessHandle
 #include "base/process_util.h"          // for OpenProcessHandle
@@ -19,16 +18,17 @@
 #include "base/tracked.h"               // for FROM_HERE
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Monitor.h"            // for Monitor, MonitorAutoLock
 #include "mozilla/ReentrantMonitor.h"   // for ReentrantMonitor, etc
 #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
+#include "mozilla/layers/CompositorParent.h" // for CompositorParent
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/ImageClient.h"  // for ImageClient
 #include "mozilla/layers/LayersMessages.h"  // for CompositableOperation
 #include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for ImageContainer::AddRef, etc
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -4,21 +4,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef gfx_layers_ipc_ImageBridgeParent_h_
 #define gfx_layers_ipc_ImageBridgeParent_h_
 
 #include <stddef.h>                     // for size_t
 #include <stdint.h>                     // for uint32_t, uint64_t
 #include "CompositableTransactionParent.h"
-#include "CompositorParent.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/ipc/SharedMemory.h"   // for SharedMemory, etc
+#include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/PImageBridgeParent.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"
 #include "nsTArrayForwardDeclare.h"     // for InfallibleTArray
 
 class MessageLoop;
 
 namespace base {
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -8,32 +8,32 @@
 #include "LayerTransactionParent.h"
 #include <vector>                       // for vector
 #include "apz/src/AsyncPanZoomController.h"
 #include "CompositableHost.h"           // for CompositableParent, Get, etc
 #include "ImageLayers.h"                // for ImageLayer
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #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
 #include "mozilla/layers/PaintedLayerComposite.h"
+#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "mozilla/unused.h"
 #include "nsCoord.h"                    // for NSAppUnitsToFloatPixels
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsDeviceContext.h"            // for AppUnitsPerCSSPixel
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsLayoutUtils.h"              // for nsLayoutUtils
 #include "nsMathUtils.h"                // for NS_round
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -21,19 +21,16 @@ EXPORTS += [
     'CopyableCanvasLayer.h',
     'D3D9SurfaceImage.h',
     'FrameMetrics.h',
     'GLImages.h',
     'GrallocImages.h',
     'ImageContainer.h',
     'ImageLayers.h',
     'ImageTypes.h',
-    'ipc/CompositorChild.h',
-    'ipc/CompositorParent.h',
-    'ipc/ShadowLayersManager.h',
     'ipc/ThreadSafeRefcountingWithMainThreadDestruction.h',
     'Layers.h',
     'LayerScope.h',
     'LayersLogging.h',
     'LayerSorter.h',
     'LayersTypes.h',
     'LayerTreeInvalidation.h',
     'opengl/Composer2D.h',
--- a/gfx/tests/crashtests/crashtests.list
+++ b/gfx/tests/crashtests/crashtests.list
@@ -36,17 +36,17 @@ load 385719-1.html
 load 389326-1.html
 skip load 390476.html # bug 585185
 load 393746-1.xhtml
 load 393749-1.html
 load 393822-1.html
 load 394384-1.html
 load 394246-1.html
 load 394246-2.html
-skip-if(Android&&(AndroidVersion<15||AndroidVersion>=17)) load 394751.xhtml # bug 922976
+skip-if(Android||B2G) load 394751.xhtml # bug 922976
 load 395335-1.xhtml
 load 395458-1.html
 load 396321-1.svg
 load 398042-1.xhtml
 load 398042-2.xhtml
 load 402307-1.html
 load 403464-1.html
 load 404112-1.html
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -69,16 +69,17 @@ MSG_DEF(JSMSG_INVALID_MAP_ITERABLE,    0
 MSG_DEF(JSMSG_NESTING_GENERATOR,       0, JSEXN_TYPEERR, "already executing generator")
 MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,     3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
 MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
 MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS,       0, JSEXN_TYPEERR, "invalid arguments")
 MSG_DEF(JSMSG_BAD_SURROGATE_CHAR,      1, JSEXN_TYPEERR, "bad surrogate character {0}")
 MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE,     1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
 MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR,     1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
 MSG_DEF(JSMSG_WRONG_CONSTRUCTOR,       1, JSEXN_TYPEERR, "wrong constructor called for {0}")
+MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW,     1, JSEXN_NONE, "calling a builtin {0} constructor without new is deprecated and will be forbidden in ES6")
 MSG_DEF(JSMSG_PROTO_SETTING_SLOW,      0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
 MSG_DEF(JSMSG_BAD_GENERATOR_YIELD,     1, JSEXN_TYPEERR, "yield from closing generator {0}")
 MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE,      0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
 MSG_DEF(JSMSG_UNEXPECTED_TYPE,         2, JSEXN_TYPEERR, "{0} is {1}")
 MSG_DEF(JSMSG_MISSING_FUN_ARG,         2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
 MSG_DEF(JSMSG_NOT_NONNULL_OBJECT,      0, JSEXN_TYPEERR, "value is not a non-null object")
 MSG_DEF(JSMSG_INVALID_DESCRIPTOR,      0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
 MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE,   1, JSEXN_TYPEERR, "{0} is not extensible")
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -456,18 +456,22 @@ ArrayBufferObject::fun_transfer(JSContex
 #endif  // defined(NIGHTLY_BUILD)
 
 /*
  * new ArrayBuffer(byteLength)
  */
 bool
 ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (!WarnIfNotConstructing(cx, args, "ArrayBuffer"))
+        return false;
+
     int32_t nbytes = 0;
-    CallArgs args = CallArgsFromVp(argc, vp);
     if (argc > 0 && !ToInt32(cx, args[0], &nbytes))
         return false;
 
     if (nbytes < 0) {
         /*
          * We're just not going to support arrays that are bigger than what will fit
          * as an integer value; if someone actually ever complains (validly), then we
          * can fix.
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -675,11 +675,20 @@ inline bool
 DefineNativeProperty(ExclusiveContext *cx, HandleNativeObject obj,
                      PropertyName *name, HandleValue value,
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     RootedId id(cx, NameToId(name));
     return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
+inline bool
+WarnIfNotConstructing(JSContext *cx, const CallArgs &args, const char *builtinName)
+{
+    if (args.isConstructing())
+        return true;
+    return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
+                                        JSMSG_BUILTIN_CTOR_NO_NEW, builtinName);
+}
+
 } // namespace js
 
 #endif /* vm_NativeObject_inl_h */
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -398,16 +398,20 @@ class TypedArrayObjectTemplate : public 
      * new [Type]Array(otherTypedArray)
      * new [Type]Array(JSArray)
      * new [Type]Array(ArrayBuffer, [optional] byteOffset, [optional] length)
      */
     static bool
     class_constructor(JSContext *cx, unsigned argc, Value *vp)
     {
         CallArgs args = CallArgsFromVp(argc, vp);
+
+        if (!WarnIfNotConstructing(cx, args, "typed array"))
+            return false;
+
         JSObject *obj = create(cx, args);
         if (!obj)
             return false;
         args.rval().setObject(*obj);
         return true;
     }
 
     static JSObject *
--- a/layout/base/SelectionCarets.cpp
+++ b/layout/base/SelectionCarets.cpp
@@ -379,52 +379,49 @@ SelectionCarets::UpdateSelectionCarets()
   }
 
   nsRefPtr<dom::Selection> selection = GetSelection();
   if (!selection) {
     SetVisibility(false);
     return;
   }
 
-  if (selection->IsCollapsed()) {
+  if (selection->GetRangeCount() <= 0) {
     SetVisibility(false);
     return;
   }
 
-  int32_t rangeCount = selection->GetRangeCount();
-  nsRefPtr<nsRange> firstRange = selection->GetRangeAt(0);
-  nsRefPtr<nsRange> lastRange = selection->GetRangeAt(rangeCount - 1);
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
+  if (range->Collapsed()) {
+    SetVisibility(false);
+    return;
+  }
 
-  nsLayoutUtils::FirstAndLastRectCollector collectorStart;
-  nsRange::CollectClientRects(&collectorStart, firstRange,
-                              firstRange->GetStartParent(), firstRange->StartOffset(),
-                              firstRange->GetEndParent(), firstRange->EndOffset(), true, true);
-
-  nsLayoutUtils::FirstAndLastRectCollector collectorEnd;
-  nsRange::CollectClientRects(&collectorEnd, lastRange,
-                              lastRange->GetStartParent(), lastRange->StartOffset(),
-                              lastRange->GetEndParent(), lastRange->EndOffset(), true, true);
+  nsLayoutUtils::FirstAndLastRectCollector collector;
+  nsRange::CollectClientRects(&collector, range,
+                              range->GetStartParent(), range->StartOffset(),
+                              range->GetEndParent(), range->EndOffset(), true, true);
 
   nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
   nsIFrame* rootFrame = mPresShell->GetRootFrame();
 
   if (!canvasFrame || !rootFrame) {
     SetVisibility(false);
     return;
   }
 
   // Check start and end frame is rtl or ltr text
   nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
   int32_t startOffset;
   nsIFrame* startFrame = FindFirstNodeWithFrame(mPresShell->GetDocument(),
-                                                firstRange, fs, false, startOffset);
+                                                range, fs, false, startOffset);
 
   int32_t endOffset;
   nsIFrame* endFrame = FindFirstNodeWithFrame(mPresShell->GetDocument(),
-                                              lastRange, fs, true, endOffset);
+                                              range, fs, true, endOffset);
 
   if (!startFrame || !endFrame) {
     SetVisibility(false);
     return;
   }
 
   // If frame isn't editable and we don't support non-editable fields, bail
   // out.
@@ -440,46 +437,46 @@ SelectionCarets::UpdateSelectionCarets()
     return;
   }
 
   bool startFrameIsRTL = IsRightToLeft(startFrame);
   bool endFrameIsRTL = IsRightToLeft(endFrame);
 
   // If start frame is LTR, then place start caret in first rect's leftmost
   // otherwise put it to first rect's rightmost.
-  ReduceRectToVerticalEdge(collectorStart.mFirstRect, startFrameIsRTL);
+  ReduceRectToVerticalEdge(collector.mFirstRect, startFrameIsRTL);
 
   // Contrary to start frame, if end frame is LTR, put end caret to last
   // rect's rightmost position, otherwise, put it to last rect's leftmost.
-  ReduceRectToVerticalEdge(collectorEnd.mLastRect, !endFrameIsRTL);
+  ReduceRectToVerticalEdge(collector.mLastRect, !endFrameIsRTL);
 
   nsAutoTArray<nsIFrame*, 16> hitFramesInFirstRect;
   nsLayoutUtils::GetFramesForArea(rootFrame,
-    collectorStart.mFirstRect,
+    collector.mFirstRect,
     hitFramesInFirstRect,
     nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
       nsLayoutUtils::IGNORE_CROSS_DOC |
       nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
 
   nsAutoTArray<nsIFrame*, 16> hitFramesInLastRect;
   nsLayoutUtils::GetFramesForArea(rootFrame,
-    collectorEnd.mLastRect,
+    collector.mLastRect,
     hitFramesInLastRect,
     nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
       nsLayoutUtils::IGNORE_CROSS_DOC |
       nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
 
   SetStartFrameVisibility(hitFramesInFirstRect.Contains(startFrame));
   SetEndFrameVisibility(hitFramesInLastRect.Contains(endFrame));
 
-  nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collectorStart.mFirstRect);
-  nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collectorEnd.mLastRect);
+  nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mFirstRect);
+  nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mLastRect);
 
-  SetStartFramePos(collectorStart.mFirstRect.BottomLeft());
-  SetEndFramePos(collectorEnd.mLastRect.BottomRight());
+  SetStartFramePos(collector.mFirstRect.BottomLeft());
+  SetEndFramePos(collector.mLastRect.BottomRight());
   SetVisibility(true);
 
   // If range select only one character, append tilt class name to it.
   bool isTilt = false;
   if (startFrame && endFrame) {
     // In this case <textarea>abc</textarea> and we select 'c' character,
     // EndContent would be HTMLDivElement and mResultContent which get by
     // calling startFrame->PeekOffset() with selecting next cluster would be
@@ -687,23 +684,21 @@ SelectionCarets::DragSelection(const nsP
 
   nsFrame::ContentOffsets offsets =
     newFrame->GetContentOffsetsFromPoint(newPoint);
   if (!offsets.content) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   nsRefPtr<dom::Selection> selection = GetSelection();
-  int32_t rangeCount = selection->GetRangeCount();
-  if (rangeCount <= 0) {
+  if (selection->GetRangeCount() <= 0) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
-  nsRefPtr<nsRange> range = mDragMode == START_FRAME ?
-    selection->GetRangeAt(0) : selection->GetRangeAt(rangeCount - 1);
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
   if (!CompareRangeWithContentOffset(range, fs, offsets, mDragMode)) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   nsIFrame* anchorFrame;
   selection->GetPrimaryFrameForAnchorNode(&anchorFrame);
   if (!anchorFrame) {
     return nsEventStatus_eConsumeNoDefault;
@@ -737,32 +732,30 @@ SelectionCarets::GetCaretYCenterPosition
 {
   nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
 
   if (!canvasFrame) {
     return 0;
   }
 
   nsRefPtr<dom::Selection> selection = GetSelection();
-  int32_t rangeCount = selection->GetRangeCount();
-  if (rangeCount <= 0) {
+  if (selection->GetRangeCount() <= 0) {
     return 0;
   }
 
+  nsRefPtr<nsRange> range = selection->GetRangeAt(0);
   nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
 
   MOZ_ASSERT(mDragMode != NONE);
   nsCOMPtr<nsIContent> node;
   uint32_t nodeOffset;
   if (mDragMode == START_FRAME) {
-    nsRefPtr<nsRange> range = selection->GetRangeAt(0);
     node = do_QueryInterface(range->GetStartParent());
     nodeOffset = range->StartOffset();
   } else {
-    nsRefPtr<nsRange> range = selection->GetRangeAt(rangeCount - 1);
     node = do_QueryInterface(range->GetEndParent());
     nodeOffset = range->EndOffset();
   }
 
   int32_t offset;
   CaretAssociationHint hint =
     mDragMode == START_FRAME ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
   nsIFrame* theFrame =
@@ -887,16 +880,22 @@ SelectionCarets::GetFrameSelection()
   }
 }
 
 nsresult
 SelectionCarets::NotifySelectionChanged(nsIDOMDocument* aDoc,
                                        nsISelection* aSel,
                                        int16_t aReason)
 {
+  bool isCollapsed;
+  aSel->GetIsCollapsed(&isCollapsed);
+  if (isCollapsed) {
+    SetVisibility(false);
+    return NS_OK;
+  }
   if (!aReason || (aReason & (nsISelectionListener::DRAG_REASON |
                                nsISelectionListener::KEYPRESS_REASON |
                                nsISelectionListener::MOUSEDOWN_REASON))) {
     SetVisibility(false);
   } else {
     UpdateSelectionCarets();
   }
   return NS_OK;
--- a/layout/base/tests/marionette/manifest.ini
+++ b/layout/base/tests/marionette/manifest.ini
@@ -8,9 +8,8 @@ browser = true
 ; true if the test is compatible with b2g, otherwise false
 b2g = true
 
 ; true if the test should be skipped
 skip = false
 
 [test_touchcaret.py]
 [test_selectioncarets.py]
-[test_selectioncarets_multiplerange.py]
deleted file mode 100644
--- a/layout/base/tests/marionette/test_selectioncarets_multiplerange.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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 by import By
-from marionette import Actions
-from marionette_test import MarionetteTestCase
-from selection import SelectionManager
-
-
-class SelectionCaretsMultipleRangeTest(MarionetteTestCase):
-    _long_press_time = 1        # 1 second
-
-    def setUp(self):
-        # Code to execute before a tests are run.
-        MarionetteTestCase.setUp(self)
-        self.actions = Actions(self.marionette)
-
-    def openTestHtml(self, enabled=True):
-        # Open html for testing and enable selectioncaret and
-        # non-editable support
-        self.marionette.execute_script(
-            'SpecialPowers.setBoolPref("selectioncaret.enabled", %s);' %
-            ('true' if enabled else 'false'))
-        self.marionette.execute_script(
-            'SpecialPowers.setBoolPref("selectioncaret.noneditable", %s);' %
-            ('true' if enabled else 'false'))
-
-        test_html = self.marionette.absolute_url('test_selectioncarets_multiplerange.html')
-        self.marionette.navigate(test_html)
-
-        self._body = self.marionette.find_element(By.ID, 'bd')
-        self._sel3 = self.marionette.find_element(By.ID, 'sel3')
-        self._sel4 = self.marionette.find_element(By.ID, 'sel4')
-        self._sel6 = self.marionette.find_element(By.ID, 'sel6')
-        self._nonsel1 = self.marionette.find_element(By.ID, 'nonsel1')
-
-    def _long_press_without_contextmenu(self, el, x, y):
-        return self.actions.press(el, x, y).move_by_offset(0, 0).\
-            wait(self._long_press_time).release()
-
-    def _long_press_to_select_word(self, el, wordOrdinal):
-        sel = SelectionManager(el)
-        original_content = sel.content
-        words = original_content.split()
-        self.assertTrue(wordOrdinal < len(words),
-            'Expect at least %d words in the content.' % wordOrdinal)
-
-        # Calc offset
-        offset = 0
-        for i in range(wordOrdinal):
-            offset += (len(words[i]) + 1)
-
-        # Move caret inside the word.
-        el.tap()
-        sel.move_caret_to_front()
-        sel.move_caret_by_offset(offset)
-        x, y = sel.caret_location()
-
-        # Long press the caret position. Selection carets should appear, and the
-        # word will be selected. On Windows, those spaces after the word
-        # will also be selected.
-        self._long_press_without_contextmenu(el, x, y).perform()
-
-    def _to_unix_line_ending(self, s):
-        """Changes all Windows/Mac line endings in s to UNIX line endings."""
-
-        return s.replace('\r\n', '\n').replace('\r', '\n')
-
-    def test_long_press_to_select_non_selectable_word(self):
-        '''Testing long press on non selectable field.
-        We should not select anything when long press on non selectable fields.'''
-
-        self.openTestHtml(enabled=True)
-        halfY = self._nonsel1.size['height'] / 2
-        self._long_press_without_contextmenu(self._nonsel1, 0, halfY).perform()
-        sel = SelectionManager(self._nonsel1)
-        range_count = sel.range_count()
-        self.assertEqual(range_count, 0)
-
-    def test_drag_caret_over_non_selectable_field(self):
-        '''Testing drag caret over non selectable field.
-        So that the selected content should exclude non selectable field and
-        end selection caret should appear in last range's position.'''
-        self.openTestHtml(enabled=True)
-
-        # Select target element and get target caret location
-        self._long_press_to_select_word(self._sel4, 3)
-        sel = SelectionManager(self._body)
-        (_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()
-
-        self._long_press_to_select_word(self._sel6, 0)
-        (_, _), (end_caret2_x, end_caret2_y) = sel.selection_carets_location()
-
-        # Select start element
-        self._long_press_to_select_word(self._sel3, 3)
-
-        # Drag end caret to target location
-        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
-        self.actions.flick(self._body, caret2_x, caret2_y, end_caret_x, end_caret_y).perform()
-        self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()),
-            'this 3\nuser can select this')
-
-        (caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
-        self.actions.flick(self._body, caret2_x, caret2_y, end_caret2_x, end_caret2_y).perform()
-        self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()),
-            'this 3\nuser can select this 4\nuser can select this 5\nuser')
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -85,16 +85,17 @@
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/dom/network/TCPSocketChild.h"
 #include "mozilla/dom/network/TCPSocketParent.h"
 #include "mozilla/dom/network/TCPServerSocketChild.h"
 #include "mozilla/dom/network/UDPSocketChild.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
+#include "mozilla/dom/workers/WorkerDebuggerManager.h"
 #include "mozilla/OSFileConstants.h"
 #include "mozilla/Services.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/FakeSpeechRecognitionService.h"
 #include "mozilla/dom/nsSynthVoiceRegistry.h"
 #endif
 
@@ -243,16 +244,17 @@ static void Shutdown();
 #include "GMPService.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using mozilla::dom::alarm::AlarmHalService;
 using mozilla::dom::power::PowerManagerService;
 using mozilla::dom::quota::QuotaManager;
 using mozilla::dom::workers::ServiceWorkerManager;
+using mozilla::dom::workers::WorkerDebuggerManager;
 using mozilla::dom::TCPSocketChild;
 using mozilla::dom::TCPSocketParent;
 using mozilla::dom::TCPServerSocketChild;
 using mozilla::dom::UDPSocketChild;
 using mozilla::dom::time::TimeService;
 using mozilla::net::StreamingProtocolControllerService;
 using mozilla::gmp::GeckoMediaPluginService;
 
@@ -282,16 +284,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(Exception
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService,
                                          DOMRequestService::FactoryCreate)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManager,
                                          QuotaManager::FactoryCreate)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ServiceWorkerManager,
                                          ServiceWorkerManager::FactoryCreate)
+NS_GENERIC_FACTORY_CONSTRUCTOR(WorkerDebuggerManager)
+
 #ifdef MOZ_WIDGET_GONK
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemWorkerManager,
                                          SystemWorkerManager::FactoryCreate)
 #endif
 #ifdef MOZ_B2G_BT
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(BluetoothService,
                                          BluetoothService::FactoryCreate)
 #endif
@@ -710,16 +714,17 @@ NS_DEFINE_NAMED_CID(NS_XMLHTTPREQUEST_CI
 NS_DEFINE_NAMED_CID(NS_DOMPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_DOMSESSIONSTORAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_DOMLOCALSTORAGEMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_DOMJSON_CID);
 NS_DEFINE_NAMED_CID(NS_TEXTEDITOR_CID);
 NS_DEFINE_NAMED_CID(DOMREQUEST_SERVICE_CID);
 NS_DEFINE_NAMED_CID(QUOTA_MANAGER_CID);
 NS_DEFINE_NAMED_CID(SERVICEWORKERMANAGER_CID);
+NS_DEFINE_NAMED_CID(WORKERDEBUGGERMANAGER_CID);
 #ifdef MOZ_WIDGET_GONK
 NS_DEFINE_NAMED_CID(SYSTEMWORKERMANAGER_CID);
 #endif
 #ifdef MOZ_B2G_BT
 NS_DEFINE_NAMED_CID(BLUETOOTHSERVICE_CID);
 #endif
 #ifdef MOZ_WIDGET_GONK
 NS_DEFINE_NAMED_CID(NS_AUDIOMANAGER_CID);
@@ -1000,16 +1005,17 @@ static const mozilla::Module::CIDEntry k
   { &kNS_XPCEXCEPTION_CID, false, nullptr, ExceptionConstructor },
   { &kNS_DOMSESSIONSTORAGEMANAGER_CID, false, nullptr, DOMSessionStorageManagerConstructor },
   { &kNS_DOMLOCALSTORAGEMANAGER_CID, false, nullptr, DOMLocalStorageManagerConstructor },
   { &kNS_DOMJSON_CID, false, nullptr, NS_NewJSON },
   { &kNS_TEXTEDITOR_CID, false, nullptr, nsPlaintextEditorConstructor },
   { &kDOMREQUEST_SERVICE_CID, false, nullptr, DOMRequestServiceConstructor },
   { &kQUOTA_MANAGER_CID, false, nullptr, QuotaManagerConstructor },
   { &kSERVICEWORKERMANAGER_CID, false, nullptr, ServiceWorkerManagerConstructor },
+  { &kWORKERDEBUGGERMANAGER_CID, true, nullptr, WorkerDebuggerManagerConstructor },
 #ifdef MOZ_WIDGET_GONK
   { &kSYSTEMWORKERMANAGER_CID, true, nullptr, SystemWorkerManagerConstructor },
 #endif
 #ifdef MOZ_B2G_BT
   { &kBLUETOOTHSERVICE_CID, true, nullptr, BluetoothServiceConstructor },
 #endif
 #ifdef MOZ_WIDGET_GONK
   { &kNS_AUDIOMANAGER_CID, true, nullptr, AudioManagerConstructor },
@@ -1157,16 +1163,17 @@ static const mozilla::Module::ContractID
   // Keeping the old ContractID for backward compatibility
   { "@mozilla.org/dom/storagemanager;1", &kNS_DOMLOCALSTORAGEMANAGER_CID },
   { "@mozilla.org/dom/sessionStorage-manager;1", &kNS_DOMSESSIONSTORAGEMANAGER_CID },
   { "@mozilla.org/dom/json;1", &kNS_DOMJSON_CID },
   { "@mozilla.org/editor/texteditor;1", &kNS_TEXTEDITOR_CID },
   { DOMREQUEST_SERVICE_CONTRACTID, &kDOMREQUEST_SERVICE_CID },
   { QUOTA_MANAGER_CONTRACTID, &kQUOTA_MANAGER_CID },
   { SERVICEWORKERMANAGER_CONTRACTID, &kSERVICEWORKERMANAGER_CID },
+  { WORKERDEBUGGERMANAGER_CONTRACTID, &kWORKERDEBUGGERMANAGER_CID },
 #ifdef MOZ_WIDGET_GONK
   { SYSTEMWORKERMANAGER_CONTRACTID, &kSYSTEMWORKERMANAGER_CID },
 #endif
 #ifdef MOZ_B2G_BT
   { BLUETOOTHSERVICE_CONTRACTID, &kBLUETOOTHSERVICE_CID },
 #endif
 #ifdef MOZ_WIDGET_GONK
   { NS_AUDIOMANAGER_CONTRACTID, &kNS_AUDIOMANAGER_CID },
--- a/mobile/android/components/FilePicker.js
+++ b/mobile/android/components/FilePicker.js
@@ -152,17 +152,18 @@ FilePicker.prototype = {
 
     return new File(f);
   },
 
   get domfiles() {
     let win = this._domWin;
     return this.getEnumerator([this.file], function(file) {
       if (win) {
-        return new win.File(file);
+        let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+        return utils.wrapDOMFile(file);
       }
 
       return new File(file);
     });
   },
 
   get addToRecentDocs() {
     return this._addToRecentDocs;
--- a/netwerk/base/public/nsISpeculativeConnect.idl
+++ b/netwerk/base/public/nsISpeculativeConnect.idl
@@ -30,26 +30,33 @@ interface nsISpeculativeConnect : nsISup
 
 };
 
 /**
  * This is used to override the default values for various values (documented
  * inline) to determine whether or not to actually make a speculative
  * connection.
  */
-[builtinclass, uuid(1040ebe3-6ed1-45a6-8587-995e082518d7)]
+[builtinclass, uuid(f6a0d1e5-369f-4abc-81ae-d370d36e4006)]
 interface nsISpeculativeConnectionOverrider : nsISupports
 {
     /**
      * Used to determine the maximum number of unused speculative connections
      * we will have open for a host at any one time
      */
     [infallible] readonly attribute unsigned long parallelSpeculativeConnectLimit;
 
     /**
+     * Used to loosen the restrictions nsHttpConnectionMgr::RestrictConnections
+     * to allow more speculative connections when we're unsure if a host will
+     * connect via SPDY or not.
+     */
+    [infallible] readonly attribute boolean ignorePossibleSpdyConnections;
+
+    /**
      * Used to determine if we will ignore the existence of any currently idle
      * connections when we decide whether or not to make a speculative
      * connection.
      */
     [infallible] readonly attribute boolean ignoreIdle;
 
     /*
      * Used by the Predictor to gather telemetry data on speculative connection
--- a/netwerk/base/src/Predictor.cpp
+++ b/netwerk/base/src/Predictor.cpp
@@ -369,16 +369,23 @@ Predictor::Observe(nsISupports *subject,
 NS_IMETHODIMP
 Predictor::GetIgnoreIdle(bool *ignoreIdle)
 {
   *ignoreIdle = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+Predictor::GetIgnorePossibleSpdyConnections(bool *ignorePossibleSpdyConnections)
+{
+  *ignorePossibleSpdyConnections = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 Predictor::GetParallelSpeculativeConnectLimit(
     uint32_t *parallelSpeculativeConnectLimit)
 {
   *parallelSpeculativeConnectLimit = 6;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -298,17 +298,17 @@ NeckoChild::AllocPChannelDiverterChild(c
 bool
 NeckoChild::DeallocPChannelDiverterChild(PChannelDiverterChild* child)
 {
   delete static_cast<ChannelDiverterChild*>(child);
   return true;
 }
 
 bool
-NeckoChild::RecvAsyncAuthPromptForNestedFrame(const TabId& aNestedFrameId,
+NeckoChild::RecvAsyncAuthPromptForNestedFrame(const uint64_t& aNestedFrameId,
                                               const nsCString& aUri,
                                               const nsString& aRealm,
                                               const uint64_t& aCallbackId)
 {
   auto iter = dom::TabChild::NestedTabChildMap().find(aNestedFrameId);
   if (iter == dom::TabChild::NestedTabChildMap().end()) {
     MOZ_CRASH();
     return false;
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -66,17 +66,17 @@ protected:
   virtual PRtspChannelChild*
     AllocPRtspChannelChild(const RtspChannelConnectArgs& aArgs)
                            MOZ_OVERRIDE;
   virtual bool DeallocPRtspChannelChild(PRtspChannelChild*) MOZ_OVERRIDE;
   virtual PChannelDiverterChild*
   AllocPChannelDiverterChild(const ChannelDiverterArgs& channel) MOZ_OVERRIDE;
   virtual bool
   DeallocPChannelDiverterChild(PChannelDiverterChild* actor) MOZ_OVERRIDE;
-  virtual bool RecvAsyncAuthPromptForNestedFrame(const TabId& aNestedFrameId,
+  virtual bool RecvAsyncAuthPromptForNestedFrame(const uint64_t& aNestedFrameId,
                                                  const nsCString& aUri,
                                                  const nsString& aRealm,
                                                  const uint64_t& aCallbackId) MOZ_OVERRIDE;
   virtual bool RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline) MOZ_OVERRIDE;
 };
 
 /**
  * Reference to the PNecko Child protocol.
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -183,19 +183,19 @@ NeckoParent::CreateChannelLoadContext(co
         dom::Element* topFrameElement = nullptr;
         if (tabParent) {
           topFrameElement = tabParent->GetOwnerElement();
         }
         aResult = new LoadContext(aSerialized, topFrameElement,
                                   appId, inBrowser);
         break;
       }
-      case PBrowserOrId::TTabId:
+      case PBrowserOrId::Tuint64_t:
       {
-        aResult = new LoadContext(aSerialized, aBrowser.get_TabId(),
+        aResult = new LoadContext(aSerialized, aBrowser.get_uint64_t(),
                                   appId, inBrowser);
         break;
       }
       default:
         MOZ_CRASH();
     }
   }
 
@@ -728,17 +728,17 @@ CallbackMap()
   static std::map<uint64_t, nsCOMPtr<nsIAuthPromptCallback> > sCallbackMap;
   return sCallbackMap;
 }
 } // anonymous namespace
 
 NS_IMPL_ISUPPORTS(NeckoParent::NestedFrameAuthPrompt, nsIAuthPrompt2)
 
 NeckoParent::NestedFrameAuthPrompt::NestedFrameAuthPrompt(PNeckoParent* aParent,
-                                                          TabId aNestedFrameId)
+                                                          uint64_t aNestedFrameId)
   : mNeckoParent(aParent)
   , mNestedFrameId(aNestedFrameId)
 {}
 
 NS_IMETHODIMP
 NeckoParent::NestedFrameAuthPrompt::AsyncPromptAuth(
   nsIChannel* aChannel, nsIAuthPromptCallback* callback,
   nsISupports*, uint32_t,
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -73,17 +73,17 @@ public:
    */
   class NestedFrameAuthPrompt MOZ_FINAL : public nsIAuthPrompt2
   {
     ~NestedFrameAuthPrompt() {}
 
   public:
     NS_DECL_ISUPPORTS
 
-    NestedFrameAuthPrompt(PNeckoParent* aParent, TabId aNestedFrameId);
+    NestedFrameAuthPrompt(PNeckoParent* aParent, uint64_t aNestedFrameId);
 
     NS_IMETHOD PromptAuth(nsIChannel*, uint32_t, nsIAuthInformation*, bool*)
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     NS_IMETHOD AsyncPromptAuth(nsIChannel* aChannel, nsIAuthPromptCallback* callback,
                                nsISupports*, uint32_t,
@@ -93,17 +93,17 @@ public:
                                 nsIAuthPromptCallback*, nsISupports*,
                                 uint32_t, nsIAuthInformation*, nsICancelable**)
     {
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
   protected:
     PNeckoParent* mNeckoParent;
-    TabId mNestedFrameId;
+    uint64_t mNestedFrameId;
   };
 
 protected:
   virtual PHttpChannelParent*
     AllocPHttpChannelParent(const PBrowserOrId&, const SerializedLoadContext&,
                             const HttpChannelCreationArgs& aOpenArgs) MOZ_OVERRIDE;
   virtual bool
     RecvPHttpChannelConstructor(
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -21,24 +21,28 @@ include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 
 include protocol PRtspController;
 include protocol PRtspChannel;
 include URIParams;
 include InputStreamParams;
 include NeckoChannelParams;
-include PBrowserOrId;
+
 
 using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
-using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 
 namespace mozilla {
 namespace net {
 
+union PBrowserOrId {
+  nullable PBrowser;
+  uint64_t;
+};
+
 //-------------------------------------------------------------------
 sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
   manages PFTPChannel;
@@ -89,17 +93,17 @@ parent:
   OnAuthCancelled(uint64_t callbackId, bool userCancel);
 
 child:
   /*
    * Bring up the http auth prompt for a nested remote mozbrowser.
    * NestedFrameId is the id corresponding to the PBrowser.  It is the same id
    * that was passed to the PBrowserOrId param in to the PHttpChannel constructor
    */
-  AsyncAuthPromptForNestedFrame(TabId nestedFrameId, nsCString uri,
+  AsyncAuthPromptForNestedFrame(uint64_t nestedFrameId, nsCString uri,
                                 nsString realm, uint64_t callbackId);
   // Notifies child that a given app is now offline (or online)
   AppOfflineStatus(uint32_t appId, bool offline);
 
 both:
   // Actually we need PTCPSocket() for parent. But ipdl disallows us having different
   // signatures on parent and child. So when constructing the parent side object, we just 
   // leave host/port unused.
--- a/netwerk/protocol/http/AlternateServices.cpp
+++ b/netwerk/protocol/http/AlternateServices.cpp
@@ -410,16 +410,23 @@ AltSvcOverride::GetInterface(const nsIID
 NS_IMETHODIMP
 AltSvcOverride::GetIgnoreIdle(bool *ignoreIdle)
 {
   *ignoreIdle = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AltSvcOverride::GetIgnorePossibleSpdyConnections(bool *ignorePossibleSpdyConnections)
+{
+  *ignorePossibleSpdyConnections = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AltSvcOverride::GetParallelSpeculativeConnectLimit(
   uint32_t *parallelSpeculativeConnectLimit)
 {
   *parallelSpeculativeConnectLimit = 32;
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/netwerk/protocol/http/ConnectionDiagnostics.cpp
+++ b/netwerk/protocol/http/ConnectionDiagnostics.cpp
@@ -68,18 +68,18 @@ nsHttpConnectionMgr::PrintDiagnosticsCB(
   self->mLogData.AppendPrintf("   Active Conns Length = %u\n",
                               ent->mActiveConns.Length());
   self->mLogData.AppendPrintf("   Idle Conns Length = %u\n",
                               ent->mIdleConns.Length());
   self->mLogData.AppendPrintf("   Half Opens Length = %u\n",
                               ent->mHalfOpens.Length());
   self->mLogData.AppendPrintf("   Coalescing Key = %s\n",
                               ent->mCoalescingKey.get());
-  self->mLogData.AppendPrintf("   Spdy using = %d, preferred = %d\n",
-                              ent->mUsingSpdy, ent->mSpdyPreferred);
+  self->mLogData.AppendPrintf("   Spdy using = %d, tested = %d, preferred = %d\n",
+                              ent->mUsingSpdy, ent->mTestedSpdy, ent->mSpdyPreferred);
   self->mLogData.AppendPrintf("   pipelinestate = %d penalty = %d\n",
                               ent->mPipelineState, ent->mPipeliningPenalty);
   for (i = 0; i < nsAHttpTransaction::CLASS_MAX; ++i) {
     self->mLogData.AppendPrintf("   pipeline per class penalty 0x%x %d\n",
                                 i, ent->mPipeliningClassPenalty[i]);
   }
   for (i = 0; i < ent->mActiveConns.Length(); ++i) {
     self->mLogData.AppendPrintf("   :: Active Connection #%u\n", i);
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1050,17 +1050,17 @@ HttpChannelChild::ConnectParent(uint32_t
   AddIPDLReference();
 
   HttpChannelConnectArgs connectArgs(id);
   PBrowserOrId browser;
   if (!tabChild ||
       static_cast<ContentChild*>(gNeckoChild->Manager()) == tabChild->Manager()) {
     browser = tabChild;
   } else {
-    browser = tabChild->GetTabId();
+    browser = TabChild::GetTabChildId(tabChild);
   }
   if (!gNeckoChild->
         SendPHttpChannelConstructor(this, browser,
                                     IPC::SerializedLoadContext(this),
                                     connectArgs)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1505,17 +1505,17 @@ HttpChannelChild::ContinueAsyncOpen()
   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   AddIPDLReference();
 
   PBrowserOrId browser;
   if (!tabChild ||
       static_cast<ContentChild*>(gNeckoChild->Manager()) == tabChild->Manager()) {
     browser = tabChild;
   } else {
-    browser = tabChild->GetTabId();
+    browser = TabChild::GetTabChildId(tabChild);
   }
   gNeckoChild->SendPHttpChannelConstructor(this, browser,
                                            IPC::SerializedLoadContext(this),
                                            openArgs);
 
   if (fdSet) {
     FileDescriptorSetChild* fdSetActor =
       static_cast<FileDescriptorSetChild*>(fdSet);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -62,17 +62,17 @@ HttpChannelParent::HttpChannelParent(con
     do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
 
   MOZ_ASSERT(gHttpHandler);
   mHttpHandler = gHttpHandler;
 
   if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
     mTabParent = static_cast<dom::TabParent*>(iframeEmbedding.get_PBrowserParent());
   } else {
-    mNestedFrameId = iframeEmbedding.get_TabId();
+    mNestedFrameId = iframeEmbedding.get_uint64_t();
   }
 
   mObserver = new OfflineObserver(this);
 }
 
 HttpChannelParent::~HttpChannelParent()
 {
   if (mObserver) {
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -14,31 +14,30 @@
 #include "mozilla/net/NeckoCommon.h"
 #include "mozilla/net/NeckoParent.h"
 #include "OfflineObserver.h"
 #include "nsIObserver.h"
 #include "nsIParentRedirectingChannel.h"
 #include "nsIProgressEventSink.h"
 #include "nsHttpChannel.h"
 #include "nsIAuthPromptProvider.h"
-#include "mozilla/dom/ipc/IdType.h"
 
 class nsICacheEntry;
 class nsIAssociatedContentSecurity;
 
 namespace mozilla {
 
 namespace dom{
 class TabParent;
-class PBrowserOrId;
 }
 
 namespace net {
 
 class HttpChannelParentListener;
+class PBrowserOrId;
 
 class HttpChannelParent : public PHttpChannelParent
                         , public nsIParentRedirectingChannel
                         , public nsIProgressEventSink
                         , public nsIInterfaceRequestor
                         , public ADivertableParentChannel
                         , public nsIAuthPromptProvider
                         , public DisconnectableParent
@@ -50,17 +49,17 @@ public:
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIPARENTCHANNEL
   NS_DECL_NSIPARENTREDIRECTINGCHANNEL
   NS_DECL_NSIPROGRESSEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIAUTHPROMPTPROVIDER
 
-  HttpChannelParent(const dom::PBrowserOrId& iframeEmbedding,
+  HttpChannelParent(const PBrowserOrId& iframeEmbedding,
                     nsILoadContext* aLoadContext,
                     PBOverrideStatus aStatus);
 
   bool Init(const HttpChannelCreationArgs& aOpenArgs);
 
   // ADivertableParentChannel functions.
   void DivertTo(nsIStreamListener *aListener) MOZ_OVERRIDE;
   nsresult SuspendForDiversion() MOZ_OVERRIDE;
@@ -181,15 +180,15 @@ private:
   // received from the child channel.
   bool mDivertingFromChild;
 
   // Set if OnStart|StopRequest was called during a diversion from the child.
   bool mDivertedOnStartRequest;
 
   bool mSuspendedForDiversion;
 
-  dom::TabId mNestedFrameId;
+  uint64_t mNestedFrameId;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/nsHttpConnection.cpp
+++ b/netwerk/protocol/http/nsHttpConnection.cpp
@@ -154,17 +154,16 @@ void
 nsHttpConnection::StartSpdy(uint8_t spdyVersion)
 {
     LOG(("nsHttpConnection::StartSpdy [this=%p]\n", this));
 
     MOZ_ASSERT(!mSpdySession);
 
     mUsingSpdyVersion = spdyVersion;
     mEverUsedSpdy = true;
-    mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport);
 
     if (!mReportedSpdy) {
         mReportedSpdy = true;
         gHttpHandler->ConnMgr()->ReportSpdyConnection(this, true);
     }
 
     // Setting the connection as reused allows some transactions that fail
     // with NS_ERROR_NET_RESET to be restarted and SPDY uses that code
@@ -205,16 +204,17 @@ nsHttpConnection::StartSpdy(uint8_t spdy
               "Proxy and Need Connect", this));
         MOZ_ASSERT(mProxyConnectStream);
 
         mProxyConnectStream = nullptr;
         mCompletedProxyConnect = true;
         mProxyConnectInProgress = false;
     }
 
+    mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport);
     bool spdyProxy = mConnInfo->UsingHttpsProxy() && !mTLSFilter;
     if (spdyProxy) {
         nsRefPtr<nsHttpConnectionInfo> wildCardProxyCi;
         mConnInfo->CreateWildCard(getter_AddRefs(wildCardProxyCi));
         gHttpHandler->ConnMgr()->MoveToWildCardConnEntry(mConnInfo,
                                                          wildCardProxyCi, this);
         mConnInfo = wildCardProxyCi;
     }
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -375,16 +375,17 @@ public:
     NS_IMETHOD_(MozExternalRefCountType) Release(void);
 
 public: // intentional!
     nsRefPtr<NullHttpTransaction> mTrans;
 
     bool mOverridesOK;
     uint32_t mParallelSpeculativeConnectLimit;
     bool mIgnoreIdle;
+    bool mIgnorePossibleSpdyConnections;
     bool mIsFromPredictor;
     bool mAllow1918;
 
     // As above, added manually so we can use nsRefPtr without inheriting from
     // nsISupports
 protected:
     ThreadSafeAutoRefCnt mRefCnt;
     NS_DECL_OWNINGTHREAD
@@ -431,16 +432,18 @@ nsHttpConnectionMgr::SpeculativeConnect(
     args->mTrans =
         nullTransaction ? nullTransaction : new NullHttpTransaction(ci, wrappedCallbacks, caps);
 
     if (overrider) {
         args->mOverridesOK = true;
         overrider->GetParallelSpeculativeConnectLimit(
             &args->mParallelSpeculativeConnectLimit);
         overrider->GetIgnoreIdle(&args->mIgnoreIdle);
+        overrider->GetIgnorePossibleSpdyConnections(
+            &args->mIgnorePossibleSpdyConnections);
         overrider->GetIsFromPredictor(&args->mIsFromPredictor);
         overrider->GetAllow1918(&args->mAllow1918);
     }
 
     nsresult rv =
         PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
     if (NS_SUCCEEDED(rv))
         unused << args.forget();
@@ -647,16 +650,18 @@ nsHttpConnectionMgr::ReportSpdyConnectio
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
     nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(),
                                                    conn, nullptr);
 
     if (!ent)
         return;
 
+    ent->mTestedSpdy = true;
+
     if (!usingSpdy)
         return;
 
     ent->mUsingSpdy = true;
     mNumSpdyActiveConns++;
 
     uint32_t ttl = conn->TimeToLive();
     uint64_t timeOfExpire = NowInSeconds() + ttl;
@@ -667,89 +672,44 @@ nsHttpConnectionMgr::ReportSpdyConnectio
     // GetSpdyPreferredEnt() because we want to avoid the cert compatibility
     // check at this point because the cert is never part of the hash
     // lookup. Filtering on that has to be done at the time of use
     // rather than the time of registration (i.e. now).
     nsConnectionEntry *joinedConnection;
     nsConnectionEntry *preferred =
         mSpdyPreferredHash.Get(ent->mCoalescingKey);
 
-    LOG(("ReportSpdyConnection conn=%p %s %s ent=%p preferred=%p\n",conn,
-         ent->mConnInfo->Host(), ent->mCoalescingKey.get(), ent, preferred));
+    LOG(("ReportSpdyConnection %s %s ent=%p preferred=%p\n",
+         ent->mConnInfo->Host(), ent->mCoalescingKey.get(),
+         ent, preferred));
 
     if (!preferred) {
-        preferred = ent;
         if (!ent->mCoalescingKey.IsEmpty()) {
             mSpdyPreferredHash.Put(ent->mCoalescingKey, ent);
             ent->mSpdyPreferred = true;
         }
     } else if ((preferred != ent) &&
                (joinedConnection = GetSpdyPreferredEnt(ent)) &&
                (joinedConnection != ent)) {
         //
         // A connection entry (e.g. made with a different hostname) with
         // the same IP address is preferred for future transactions over this
         // connection entry. Gracefully close down the connection to help
         // new transactions migrate over.
 
         LOG(("ReportSpdyConnection graceful close of conn=%p ent=%p to "
-                 "migrate to preferred (desharding)\n", conn, ent));
+                 "migrate to preferred\n", conn, ent));
+
         conn->DontReuse();
     } else if (preferred != ent) {
         LOG (("ReportSpdyConnection preferred host may be in false start or "
               "may have insufficient cert. Leave mapping in place but do not "
               "abandon this connection yet."));
     }
 
-    if (preferred == ent) {
-        // this is a new spdy connection to the preferred entry
-        for (int32_t index = ent->mHalfOpens.Length() - 1;
-             (index >= 0) &&  conn->CanDirectlyActivate(); --index) {
-
-            // Abandon all other half-open sockets belonging to the given transaction.
-            // While activating their transactions on the new conn
-
-            nsHalfOpenSocket *half = ent->mHalfOpens[index];
-            nsAHttpTransaction *abstractTrans = half->Transaction();
-            nsRefPtr<nsHttpTransaction> concreteTrans = abstractTrans->QueryHttpTransaction();
-
-            if (!concreteTrans) {
-                continue;
-            }
-
-            LOG(("ReportSpdyConnection conn %p taking transaction %p from a "
-                 "half open that it will cancel\n", conn, concreteTrans.get()));
-
-            // concreteTrans is holding a ref to the transaction in half - so it
-            // is ok to destroy half
-            ent->RemoveHalfOpen(half);
-            half->Abandon();
-
-            DebugOnly<nsresult> rv = DispatchTransaction(ent, concreteTrans, conn);
-            MOZ_ASSERT(NS_SUCCEEDED(rv)); // this cannot fail
-        }
-
-        if (conn->CanDirectlyActivate() && ent->mActiveConns.Length() > 1) {
-            // this is a new connection to an established preferred spdy host.
-            // if there is more than 1 live and established spdy connection (e.g.
-            // some could still be handshaking, shutting down, etc..) then close
-            // this one down after any transactions that are on it are complete.
-            // This probably happened due to the parallel connection algorithm
-            // that is used only before the host is known to speak spdy.
-            for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
-                nsHttpConnection *otherConn = ent->mActiveConns[index];
-                if (otherConn != conn) {
-                    LOG(("ReportSpdyConnection shutting down connection (%p) because new "
-                         "spdy connection (%p) takes precedence\n", otherConn, conn));
-                    otherConn->DontReuse();
-                }
-            }
-        }
-    }
-
     ProcessPendingQ(ent->mConnInfo);
     PostEvent(&nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ);
 }
 
 void
 nsHttpConnectionMgr::ReportSpdyCWNDSetting(nsHttpConnectionInfo *ci,
                                            uint32_t cwndValue)
 {
@@ -1062,17 +1022,19 @@ nsHttpConnectionMgr::PruneDeadConnection
     // red condition, then we can clean it up and restart from
     // yellow
     if (ent->PipelineState()       != PS_RED &&
         self->mCT.Count()          >  125 &&
         ent->mIdleConns.Length()   == 0 &&
         ent->mActiveConns.Length() == 0 &&
         ent->mHalfOpens.Length()   == 0 &&
         ent->mPendingQ.Length()    == 0 &&
-        (!ent->mUsingSpdy || self->mCT.Count() > 300)) {
+        ((!ent->mTestedSpdy && !ent->mUsingSpdy) ||
+         !gHttpHandler->IsSpdyEnabled() ||
+         self->mCT.Count() > 300)) {
         LOG(("    removing empty connection entry\n"));
         return PL_DHASH_REMOVE;
     }
 
     // otherwise use this opportunity to compact our arrays...
     ent->mIdleConns.Compact();
     ent->mActiveConns.Compact();
     ent->mPendingQ.Compact();
@@ -1442,38 +1404,39 @@ nsHttpConnectionMgr::ClosePersistentConn
                                                   void *closure)
 {
     nsHttpConnectionMgr *self = static_cast<nsHttpConnectionMgr *>(closure);
     self->ClosePersistentConnections(ent);
     return PL_DHASH_NEXT;
 }
 
 bool
-nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent)
+nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent,
+                                         bool ignorePossibleSpdyConnections)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
     // If this host is trying to negotiate a SPDY session right now,
     // don't create any new ssl connections until the result of the
     // negotiation is known.
 
     bool doRestrict = ent->mConnInfo->FirstHopSSL() &&
         gHttpHandler->IsSpdyEnabled() &&
-        ent->mUsingSpdy &&
+        ((!ent->mTestedSpdy && !ignorePossibleSpdyConnections) ||
+         ent->mUsingSpdy) &&
         (ent->mHalfOpens.Length() || ent->mActiveConns.Length());
 
     // If there are no restrictions, we are done
     if (!doRestrict)
         return false;
 
     // If the restriction is based on a tcp handshake in progress
     // let that connect and then see if it was SPDY or not
-    if (ent->UnconnectedHalfOpens()) {
+    if (ent->UnconnectedHalfOpens() && !ignorePossibleSpdyConnections)
         return true;
-    }
 
     // There is a concern that a host is using a mix of HTTP/1 and SPDY.
     // In that case we don't want to restrict connections just because
     // there is a single active HTTP/1 session in use.
     if (ent->mUsingSpdy && ent->mActiveConns.Length()) {
         bool confirmedRestrict = false;
         for (uint32_t index = 0; index < ent->mActiveConns.Length(); ++index) {
             nsHttpConnection *conn = ent->mActiveConns[index];
@@ -2984,32 +2947,34 @@ nsHttpConnectionMgr::OnMsgSpeculativeCon
     // the ip pooling rules. If so, connect to the preferred host instead of
     // the one directly passed in here.
     nsConnectionEntry *preferredEntry = GetSpdyPreferredEnt(ent);
     if (preferredEntry)
         ent = preferredEntry;
 
     uint32_t parallelSpeculativeConnectLimit =
         gHttpHandler->ParallelSpeculativeConnectLimit();
+    bool ignorePossibleSpdyConnections = false;
     bool ignoreIdle = false;
     bool isFromPredictor = false;
     bool allow1918 = false;
 
     if (args->mOverridesOK) {
         parallelSpeculativeConnectLimit = args->mParallelSpeculativeConnectLimit;
+        ignorePossibleSpdyConnections = args->mIgnorePossibleSpdyConnections;
         ignoreIdle = args->mIgnoreIdle;
         isFromPredictor = args->mIsFromPredictor;
         allow1918 = args->mAllow1918;
     }
 
     bool keepAlive = args->mTrans->Caps() & NS_HTTP_ALLOW_KEEPALIVE;
     if (mNumHalfOpenConns < parallelSpeculativeConnectLimit &&
         ((ignoreIdle && (ent->mIdleConns.Length() < parallelSpeculativeConnectLimit)) ||
          !ent->mIdleConns.Length()) &&
-        !(keepAlive && RestrictConnections(ent)) &&
+        !(keepAlive && RestrictConnections(ent, ignorePossibleSpdyConnections)) &&
         !AtActiveConnectionLimit(ent, args->mTrans->Caps())) {
         CreateTransport(ent, args->mTrans, args->mTrans->Caps(), true, isFromPredictor, allow1918);
     }
     else {
         LOG(("  Transport not created due to existing connection count\n"));
     }
 }
 
@@ -3363,19 +3328,18 @@ nsHalfOpenSocket::OnOutputStreamReady(ns
 
         if (NS_SUCCEEDED(mSocketTransport->GetPeerAddr(&peeraddr)))
             mEnt->RecordIPFamilyPreference(peeraddr.raw.family);
 
         // The nsHttpConnection object now owns these streams and sockets
         mStreamOut = nullptr;
         mStreamIn = nullptr;
         mSocketTransport = nullptr;
-    } else {
-        MOZ_ASSERT(!mTransaction->IsNullTransaction(),
-                   "null transactions dont have backup timers");
+    }
+    else {
         TimeDuration rtt = TimeStamp::Now() - mBackupSynStarted;
         rv = conn->Init(mEnt->mConnInfo,
                         gHttpHandler->ConnMgr()->mMaxRequestDelay,
                         mBackupTransport, mBackupStreamIn, mBackupStreamOut,
                         mBackupConnectedOK, callbacks,
                         PR_MillisecondsToInterval(
                           static_cast<uint32_t>(rtt.ToMilliseconds())));
 
@@ -3595,16 +3559,17 @@ nsConnectionEntry::nsConnectionEntry(nsH
     , mPipelineState(PS_YELLOW)
     , mYellowGoodEvents(0)
     , mYellowBadEvents(0)
     , mYellowConnection(nullptr)
     , mGreenDepth(kPipelineOpen)
     , mPipeliningPenalty(0)
     , mSpdyCWND(0)
     , mUsingSpdy(false)
+    , mTestedSpdy(false)
     , mSpdyPreferred(false)
     , mPreferIPv4(false)
     , mPreferIPv6(false)
 {
     MOZ_COUNT_CTOR(nsConnectionEntry);
     if (gHttpHandler->GetPipelineAggressive()) {
         mGreenDepth = kPipelineUnlimited;
         mPipelineState = PS_GREEN;
@@ -3992,16 +3957,17 @@ nsHttpConnectionMgr::MoveToWildCardConnE
     }
 
     nsConnectionEntry *wcEnt = GetOrCreateConnectionEntry(wildCardCI, true);
     if (wcEnt == ent) {
         // nothing to do!
         return;
     }
     wcEnt->mUsingSpdy = true;
+    wcEnt->mTestedSpdy = true;
 
     LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard ent %p "
          "idle=%d active=%d half=%d pending=%d\n", ent,
          ent->mIdleConns.Length(), ent->mActiveConns.Length(),
          ent->mHalfOpens.Length(), ent->mPendingQ.Length()));
 
     LOG(("nsHttpConnectionMgr::MakeConnEntryWildCard wc-ent %p "
          "idle=%d active=%d half=%d pending=%d\n", wcEnt,
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -371,16 +371,22 @@ private:
         uint32_t            mSpdyCWND;
         TimeStamp  mSpdyCWNDTimeStamp;
 
         // To have the UsingSpdy flag means some host with the same connection
         // entry has done NPN=spdy/* at some point. It does not mean every
         // connection is currently using spdy.
         bool mUsingSpdy;
 
+        // mTestedSpdy is set after NPN negotiation has occurred and we know
+        // with confidence whether a host speaks spdy or not (which is reflected
+        // in mUsingSpdy). Before mTestedSpdy is set, handshake parallelism is
+        // minimized so that we can multiplex on a single spdy connection.
+        bool mTestedSpdy;
+
         bool mSpdyPreferred;
 
         // Flags to remember our happy-eyeballs decision.
         // Reset only by Ctrl-F5 reload.
         // True when we've first connected an IPv4 server for this host,
         // initially false.
         bool mPreferIPv4 : 1;
         // True when we've first connected an IPv6 server for this host,
@@ -554,17 +560,17 @@ private:
     nsresult DispatchAbstractTransaction(nsConnectionEntry *,
                                          nsAHttpTransaction *,
                                          uint32_t,
                                          nsHttpConnection *,
                                          int32_t);
     nsresult BuildPipeline(nsConnectionEntry *,
                            nsAHttpTransaction *,
                            nsHttpPipeline **);
-    bool     RestrictConnections(nsConnectionEntry *);
+    bool     RestrictConnections(nsConnectionEntry *, bool = false);
     nsresult ProcessNewTransaction(nsHttpTransaction *);
     nsresult EnsureSocketThreadTarget();
     void     ClosePersistentConnections(nsConnectionEntry *ent);
     void     ReportProxyTelemetry(nsConnectionEntry *ent);
     nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *,
                              uint32_t, bool, bool, bool);
     void     AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
     void     DecrementActiveConnCount(nsHttpConnection *);
--- a/netwerk/test/unit/test_net_addr.js
+++ b/netwerk/test/unit/test_net_addr.js
@@ -20,17 +20,17 @@ const ServerSocket = CC("@mozilla.org/ne
  */
 function TestServer() {
   this.reset();
 
   // start server.
   // any port (-1), loopback only (true), default backlog (-1)
   this.listener = ServerSocket(-1, true, -1);
   this.port = this.listener.port;
-  do_print('server: listening on', this.port);
+  do_print('server: listening on ' + this.port);
   this.listener.asyncListen(this);
 }
 
 TestServer.prototype = {
   onSocketAccepted: function(socket, trans) {
     do_print('server: got client connection');
 
     // one connection at a time.
--- a/security/manager/ssl/public/nsICertOverrideService.idl
+++ b/security/manager/ssl/public/nsICertOverrideService.idl
@@ -13,17 +13,17 @@ interface nsIX509Cert;
 #define NS_CERTOVERRIDE_CONTRACTID "@mozilla.org/security/certoverride;1"
 %}
 
 /**
  * This represents the global list of triples
  *   {host:port, cert-fingerprint, allowed-overrides} 
  * that the user wants to accept without further warnings. 
  */
-[scriptable, uuid(31738d2a-77d3-4359-84c9-4be2f38fb8c5)]
+[scriptable, uuid(be019e47-22fc-4355-9f16-9ab047d6742d)]
 interface nsICertOverrideService : nsISupports {
 
   /**
    *  Override Untrusted
    */
   const short ERROR_UNTRUSTED = 1;
 
   /**
@@ -104,23 +104,21 @@ interface nsICertOverrideService : nsISu
    *               If it is -1, then it is internaly treated as 443.
    *               If it is 0 and aHostName is "all:temporary-certificates",
    *               then all temporary certificates should be cleared.
    */
   void clearValidityOverride(in ACString aHostName,
                              in int32_t aPort);
 
   /**
-   *  Obtain the full list of hostname:port for which overrides are known.
+   *  Count and return the number of permanent overrides.
    *
-   *  @param aCount The number of host:port entries returned
-   *  @param aHostsWithPortsArray The array of host:port entries returned
+   *  @param aCount The number of permanent overrides
    */
-  void getAllOverrideHostsWithPorts(out uint32_t aCount, 
-                                    [array, size_is(aCount)] out wstring aHostsWithPortsArray);
+  void getPermanentOverrideCount(out uint32_t aCount);
 
   /**
    *  Is the given cert used in rules?
    *
    *  @param aCert The cert we're looking for
    *  @return how many override entries are currently on file
    *          for the given certificate
    */
--- a/security/manager/ssl/src/nsCertOverrideService.cpp
+++ b/security/manager/ssl/src/nsCertOverrideService.cpp
@@ -1,39 +1,33 @@
 /* -*- 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 "nsCertOverrideService.h"
 
-#include "pkix/pkixtypes.h"
-#include "nsIX509Cert.h"
 #include "NSSCertDBTrustDomain.h"
-#include "nsNSSCertificate.h"
-#include "nsNSSCertHelper.h"
+#include "ScopedNSSTypes.h"
+#include "SharedSSLState.h"
+#include "nsAppDirectoryServiceDefs.h"
 #include "nsCRT.h"
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsStreamUtils.h"
-#include "nsNetUtil.h"
 #include "nsILineInputStream.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsISupportsPrimitives.h"
+#include "nsIX509Cert.h"
+#include "nsNSSCertHelper.h"
+#include "nsNSSCertificate.h"
+#include "nsNSSComponent.h"
+#include "nsNetUtil.h"
 #include "nsPromiseFlatString.h"
-#include "nsThreadUtils.h"
+#include "nsStreamUtils.h"
 #include "nsStringBuffer.h"
-#include "ScopedNSSTypes.h"
-#include "SharedSSLState.h"
-
-#include "nspr.h"
-#include "pk11pub.h"
-#include "certdb.h"
-#include "sechash.h"
+#include "nsThreadUtils.h"
 #include "ssl.h" // For SSL_ClearSessionCache
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 static const char kCertOverrideFileName[] = "cert_override.txt";
 
 void
@@ -101,28 +95,21 @@ nsCertOverrideService::~nsCertOverrideSe
 nsresult
 nsCertOverrideService::Init()
 {
   if (!NS_IsMainThread()) {
     NS_NOTREACHED("nsCertOverrideService initialized off main thread");
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
+  // Note that the names of these variables would seem to indicate that at one
+  // point another hash algorithm was used and is still supported for backwards
+  // compatibility. This is not the case. It has always been SHA256.
   mOidTagForStoringNewHashes = SEC_OID_SHA256;
-
-  SECOidData *od = SECOID_FindOIDByTag(mOidTagForStoringNewHashes);
-  if (!od)
-    return NS_ERROR_FAILURE;
-
-  char *dotted_oid = CERT_GetOidString(&od->oid);
-  if (!dotted_oid)
-    return NS_ERROR_FAILURE;
-
-  mDottedOidForStoringNewHashes = dotted_oid;
-  PR_smprintf_free(dotted_oid);
+  mDottedOidForStoringNewHashes.Assign("OID.2.16.840.1.101.3.4.2.1");
 
   nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
 
   // If we cannot add ourselves as a profile change observer, then we will not
   // attempt to read/write any settings file. Otherwise, we would end up
   // reading/writing the wrong settings file after a profile change.
   if (observerService) {
@@ -393,52 +380,16 @@ GetCertFingerprintByOidTag(nsIX509Cert *
 
   ScopedCERTCertificate nsscert(aCert->GetCert());
   if (!nsscert) {
     return NS_ERROR_FAILURE;
   }
   return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
 }
 
-static nsresult
-GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
-                                    const nsCString &dottedOid, 
-                                    nsCString &fp)
-{
-  SECItem oid;
-  oid.data = nullptr;
-  oid.len = 0;
-  SECStatus srv = SEC_StringToOID(nullptr, &oid, 
-                    dottedOid.get(), dottedOid.Length());
-  if (srv != SECSuccess)
-    return NS_ERROR_FAILURE;
-
-  SECOidTag oid_tag = SECOID_FindOIDTag(&oid);
-  SECITEM_FreeItem(&oid, false);
-
-  if (oid_tag == SEC_OID_UNKNOWN)
-    return NS_ERROR_FAILURE;
-
-  return GetCertFingerprintByOidTag(nsscert, oid_tag, fp);
-}
-
-static nsresult
-GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
-                                    const nsCString &dottedOid,
-                                    nsCString &fp)
-{
-
-  ScopedCERTCertificate nsscert(aCert->GetCert());
-  if (!nsscert) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
-}
-
 NS_IMETHODIMP
 nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
                                                 int32_t aPort,
                                                 nsIX509Cert* aCert,
                                                 uint32_t aOverrideBits,
                                                 bool aTemporary)
 {
   NS_ENSURE_ARG_POINTER(aCert);
@@ -541,24 +492,27 @@ nsCertOverrideService::HasMatchingOverri
   }
 
   *aOverrideBits = settings.mOverrideBits;
   *aIsTemporary = settings.mIsTemporary;
 
   nsAutoCString fpStr;
   nsresult rv;
 
+  // This code was originally written in a way that suggested that other hash
+  // algorithms are supported for backwards compatibility. However, this was
+  // always unnecessary, because only SHA256 has ever been used here.
   if (settings.mFingerprintAlgOID.Equals(mDottedOidForStoringNewHashes)) {
     rv = GetCertFingerprintByOidTag(aCert, mOidTagForStoringNewHashes, fpStr);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  } else {
+    return NS_ERROR_UNEXPECTED;
   }
-  else {
-    rv = GetCertFingerprintByDottedOidString(aCert, settings.mFingerprintAlgOID, fpStr);
-  }
-  if (NS_FAILED(rv))
-    return rv;
 
   *_retval = settings.mFingerprint.Equals(fpStr);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCertOverrideService::GetValidityOverride(const nsACString & aHostName, int32_t aPort,
                                            nsACString & aHashAlg, 
@@ -644,25 +598,48 @@ nsCertOverrideService::ClearValidityOver
   }
   nsAutoCString hostPort;
   GetHostWithPort(aHostName, aPort, hostPort);
   {
     ReentrantMonitorAutoEnter lock(monitor);
     mSettingsTable.RemoveEntry(hostPort.get());
     Write();
   }
-  SSL_ClearSessionCache();
+
+  if (EnsureNSSInitialized(nssEnsure)) {
+    SSL_ClearSessionCache();
+  } else {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
   return NS_OK;
 }
 
+static PLDHashOperator
+CountPermanentEntriesCallback(nsCertOverrideEntry* aEntry, void* aArg)
+{
+  uint32_t* overrideCount = reinterpret_cast<uint32_t*>(aArg);
+  if (aEntry && !aEntry->mSettings.mIsTemporary) {
+    *overrideCount = *overrideCount + 1;
+    return PL_DHASH_NEXT;
+  }
+
+  return PL_DHASH_NEXT;
+}
+
 NS_IMETHODIMP
-nsCertOverrideService::GetAllOverrideHostsWithPorts(uint32_t *aCount, 
-                                                        char16_t ***aHostsWithPortsArray)
+nsCertOverrideService::GetPermanentOverrideCount(uint32_t* aOverrideCount)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  NS_ENSURE_ARG(aOverrideCount);
+  *aOverrideCount = 0;
+
+  ReentrantMonitorAutoEnter lock(monitor);
+  mSettingsTable.EnumerateEntries(CountPermanentEntriesCallback, aOverrideCount);
+
+  return NS_OK;
 }
 
 static bool
 matchesDBKey(nsIX509Cert *cert, const char *match_dbkey)
 {
   char *dbkey = nullptr;
   nsresult rv = cert->GetDbKey(&dbkey);
   if (NS_FAILED(rv) || !dbkey)
@@ -733,25 +710,21 @@ FindMatchingCertCallback(nsCertOverrideE
     if ((settings.mIsTemporary && !cai->aCheckTemporaries)
         ||
         (!settings.mIsTemporary && !cai->aCheckPermanents)) {
       still_ok = false;
     }
 
     if (still_ok && matchesDBKey(cai->cert, settings.mDBKey.get())) {
       nsAutoCString cert_fingerprint;
-      nsresult rv;
+      nsresult rv = NS_ERROR_UNEXPECTED;
       if (settings.mFingerprintAlgOID.Equals(cai->mDottedOidForStoringNewHashes)) {
         rv = GetCertFingerprintByOidTag(cai->cert,
                cai->mOidTagForStoringNewHashes, cert_fingerprint);
       }
-      else {
-        rv = GetCertFingerprintByDottedOidString(cai->cert,
-               settings.mFingerprintAlgOID, cert_fingerprint);
-      }
       if (NS_SUCCEEDED(rv) &&
           settings.mFingerprint.Equals(cert_fingerprint)) {
         cai->counter++;
       }
     }
   }
 
   return PL_DHASH_NEXT;
@@ -803,25 +776,21 @@ EnumerateCertOverridesCallback(nsCertOve
     const nsCertOverride &settings = aEntry->mSettings;
 
     if (!capac->cert) {
       (*capac->enumerator)(settings, capac->userdata);
     }
     else {
       if (matchesDBKey(capac->cert, settings.mDBKey.get())) {
         nsAutoCString cert_fingerprint;
-        nsresult rv;
+        nsresult rv = NS_ERROR_UNEXPECTED;
         if (settings.mFingerprintAlgOID.Equals(capac->mDottedOidForStoringNewHashes)) {
           rv = GetCertFingerprintByOidTag(capac->cert,
                  capac->mOidTagForStoringNewHashes, cert_fingerprint);
         }
-        else {
-          rv = GetCertFingerprintByDottedOidString(capac->cert,
-                 settings.mFingerprintAlgOID, cert_fingerprint);
-        }
         if (NS_SUCCEEDED(rv) &&
             settings.mFingerprint.Equals(cert_fingerprint)) {
           (*capac->enumerator)(settings, capac->userdata);
         }
       }
     }
   }
 
@@ -855,9 +824,8 @@ nsCertOverrideService::GetHostWithPort(c
     aPort = 443;
   }
   if (!hostPort.IsEmpty()) {
     hostPort.Append(':');
     hostPort.AppendInt(aPort);
   }
   _retval.Assign(hostPort);
 }
-
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -1044,16 +1044,33 @@ nsNSSComponent::InitializeNSS()
   // Initialize the site security service
   nsCOMPtr<nsISiteSecurityService> sssService =
     do_GetService(NS_SSSERVICE_CONTRACTID);
   if (!sssService) {
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Cannot initialize site security service\n"));
     return NS_ERROR_FAILURE;
   }
 
+  // This can happen during startup and is a bit expensive, so only instantiate
+  // the certificate override service if telemetry is actually enabled.
+  if (Telemetry::CanRecord()) {
+    nsCOMPtr<nsICertOverrideService> overrideService(
+      do_GetService(NS_CERTOVERRIDE_CONTRACTID));
+    if (!overrideService) {
+      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("Failed to initialize cert override service\n"));
+      return NS_ERROR_FAILURE;
+    }
+    uint32_t overrideCount = 0;
+    rv = overrideService->GetPermanentOverrideCount(&overrideCount);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    Telemetry::Accumulate(Telemetry::SSL_PERMANENT_CERT_ERROR_OVERRIDES,
+                          overrideCount);
+  }
 
   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS Initialization done\n"));
   return NS_OK;
 }
 
 void
 nsNSSComponent::ShutdownNSS()
 {
--- a/security/manager/ssl/src/nsNSSModule.cpp
+++ b/security/manager/ssl/src/nsNSSModule.cpp
@@ -194,24 +194,24 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEn
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCertPicker)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsNTLMAuthModule, InitTest)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHash)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHMAC)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsStreamCipher)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObject)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObjectFactory)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsDataSignatureVerifier)
-NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsCertOverrideService, Init)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsRandomGenerator)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, nsSSLStatus)
 NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, TransportSecurityInfo)
 
 typedef mozilla::psm::NSSErrorsService NSSErrorsService;
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NSSErrorsService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNSSVersion)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsCertOverrideService, Init)
 
 NS_DEFINE_NAMED_CID(NS_NSSCOMPONENT_CID);
 NS_DEFINE_NAMED_CID(NS_SSLSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_STARTTLSSOCKETPROVIDER_CID);
 NS_DEFINE_NAMED_CID(NS_SDR_CID);
 NS_DEFINE_NAMED_CID(NS_PK11TOKENDB_CID);
 NS_DEFINE_NAMED_CID(NS_PKCS11MODULEDB_CID);
 NS_DEFINE_NAMED_CID(NS_PSMCONTENTLISTEN_CID);
--- a/services/sync/modules-testing/utils.js
+++ b/services/sync/modules-testing/utils.js
@@ -231,18 +231,17 @@ this.encryptPayload = function encryptPa
 // * The test itself should be passed as 'test' - ie, test code will generally
 //   pass |this|.
 // * The test function is a regular test function - although note that it must
 //   be a generator - async operations should yield them, and run_next_test
 //   mustn't be called.
 this.add_identity_test = function(test, testFunction) {
   function note(what) {
     let msg = "running test " + testFunction.name + " with " + what + " identity manager";
-    test._log("test_info",
-              {_message: "TEST-INFO | | " + msg + "\n"});
+    test.do_print(msg);
   }
   let ns = {};
   Cu.import("resource://services-sync/service.js", ns);
   // one task for the "old" identity manager.
   test.add_task(function() {
     note("sync");
     let oldIdentity = Status._authManager;
     ensureLegacyIdentityManager();
--- a/testing/marionette/client/marionette/selection.py
+++ b/testing/marionette/client/marionette/selection.py
@@ -68,48 +68,40 @@ class SelectionManager(object):
             cmd = '''var len = arguments[0].value.length;
                   arguments[0].setSelectionRange(len, len);'''
         else:
             cmd = '''var sel = window.getSelection();
                   sel.collapse(arguments[0].lastChild, arguments[0].lastChild.length);'''
 
         self.element.marionette.execute_script(cmd, script_args=[self.element])
 
-    def selection_rect_list(self, idx):
-        '''Return the selection's DOMRectList object for the range at given idx.
+    def selection_rect_list(self):
+        '''Return the selection's DOMRectList object.
 
-        If the element is either <input> or <textarea>, return the DOMRectList of
-        the range at given idx of the selection within the element. Otherwise,
-        return the DOMRectList of the of the range at given idx of current selection.
+        If the element is either <input> or <textarea>, return the selection's
+        DOMRectList within the element. Otherwise, return the DOMRectList of the
+        current selection.
 
         '''
         cmd = self.js_selection_cmd() +\
-            '''return sel.getRangeAt(%d).getClientRects();''' % idx
-        return self.element.marionette.execute_script(cmd, script_args=[self.element])
-
-    def range_count(self):
-        '''Get selection's range count'''
-        cmd = self.js_selection_cmd() +\
-            '''return sel.rangeCount;'''
+            '''return sel.getRangeAt(0).getClientRects();'''
         return self.element.marionette.execute_script(cmd, script_args=[self.element])
 
     def _selection_location_helper(self, location_type):
         '''Return the start and end location of the selection in the element.
 
         Return a tuple containing two pairs of (x, y) coordinates of the start
         and end locations in the element. The coordinates are relative to the
         top left-hand corner of the element. Both ltr and rtl directions are
         considered.
 
         '''
-        range_count = self.range_count();
-        first_rect_list = self.selection_rect_list(0)
-        last_rect_list = self.selection_rect_list(range_count - 1)
-        last_list_length = last_rect_list['length']
-        first_rect, last_rect = first_rect_list['0'], last_rect_list[str(last_list_length - 1)]
+        rect_list = self.selection_rect_list()
+        list_length = rect_list['length']
+        first_rect, last_rect = rect_list['0'], rect_list[str(list_length - 1)]
         origin_x, origin_y = self.element.location['x'], self.element.location['y']
 
         if self.element.get_attribute('dir') == 'rtl':  # such as Arabic
             start_pos, end_pos = 'right', 'left'
         else:
             start_pos, end_pos = 'left', 'right'
 
         # Calculate y offset according to different needs.
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini
@@ -85,16 +85,17 @@ browser = false
 [test_simpletest_pass.js]
 [test_simpletest_sanity.py]
 [test_simpletest_chrome.js]
 [test_simpletest_timeout.js]
 [test_specialpowers.py]
 [test_switch_anonymous_content.py]
 [test_switch_frame.py]
 b2g = false
+skip-if = os == "win" # Bug 1078237
 [test_switch_frame_chrome.py]
 b2g = false
 [test_switch_remote_frame.py]
 b2g = false
 
 [test_pagesource.py]
 b2g = false
 
deleted file mode 100644
--- a/testing/marionette/client/marionette/www/test_selectioncarets_multiplerange.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html>
-<style>
-h4 {
-  -moz-user-select: none;
-}
-</style>
-<body id=bd>
-<h3 id=sel1>user can select this 1</h3>
-<h3 id=sel2>user can select this 2</h3>
-<h3 id=sel3>user can select this 3</h3>
-<h4 id=nonsel1>user cannot select this 1</h4>
-<h4 id=nonsel2>user cannot select this 2</h4>
-<h3 id=sel4>user can select this 4</h3>
-<h3 id=sel5>user can select this 5</h3>
-<h4 id=nonsel3>user cannot select this 3</h4>
-<h3 id=sel6>user can select this 6</h3>
-<h3 id=sel7>user can select this 7</h3>
-</body>
-</html>
--- a/testing/modules/StructuredLog.jsm
+++ b/testing/modules/StructuredLog.jsm
@@ -100,26 +100,31 @@ StructuredLogger.prototype.suiteStart = 
   this._logData("suite_start", data);
 };
 
 StructuredLogger.prototype.suiteEnd = function () {
   this._logData("suite_end");
 };
 
 /**
- * Unstructured logging functions
+ * Unstructured logging functions. The "extra" parameter can always by used to
+ * log suite specific data. If a "stack" field is provided it is logged at the
+ * top level of the data object for the benefit of mozlog's formatters.
  */
 StructuredLogger.prototype.log = function (level, message, extra=null) {
   let data = {
     level: level,
     message: message,
   };
 
   if (extra !== null) {
     data.extra = extra;
+    if ("stack" in extra) {
+      data.stack = extra.stack;
+    }
   }
 
   this._logData("log", data);
 }
 
 StructuredLogger.prototype.debug = function (message, extra=null) {
   this.log("DEBUG", message, extra);
 }
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -8,18 +8,16 @@
  * This file contains common code that is loaded before each test file(s).
  * See http://developer.mozilla.org/en/docs/Writing_xpcshell-based_unit_tests
  * for more information.
  */
 
 var _quit = false;
 var _passed = true;
 var _tests_pending = 0;
-var _passedChecks = 0, _falsePassedChecks = 0;
-var _todoChecks = 0;
 var _cleanupFunctions = [];
 var _pendingTimers = [];
 var _profileInitialized = false;
 
 // Register the testing-common resource protocol early, to have access to its
 // modules.
 _register_modules_protocol_handler();
 
@@ -31,33 +29,29 @@ let AssertCls = Components.utils.import(
 let Assert = new AssertCls(function(err, message, stack) {
   if (err) {
     do_report_result(false, err.message, err.stack);
   } else {
     do_report_result(true, message, stack);
   }
 });
 
-let _log = function (action, params) {
+
+let _add_params = function (params) {
   if (typeof _XPCSHELL_PROCESS != "undefined") {
-    params.process = _XPCSHELL_PROCESS;
+    params.xpcshell_process = _XPCSHELL_PROCESS;
   }
-  params.action = action;
-  params._time = Date.now();
-  dump("\n" + JSON.stringify(params) + "\n");
+};
+
+let _dumpLog = function (raw_msg) {
+  dump("\n" + raw_msg + "\n");
 }
 
-function _dump(str) {
-  let start = /^TEST-/.test(str) ? "\n" : "";
-  if (typeof _XPCSHELL_PROCESS == "undefined") {
-    dump(start + str);
-  } else {
-    dump(start + _XPCSHELL_PROCESS + ": " + str);
-  }
-}
+let _LoggerClass = Components.utils.import("resource://testing-common/StructuredLog.jsm", null).StructuredLogger;
+let _testLogger = new _LoggerClass("xpcshell/head.js", _dumpLog, [_add_params]);
 
 // Disable automatic network detection, so tests work correctly when
 // not connected to a network.
 let (ios = Components.classes["@mozilla.org/network/io-service;1"]
            .getService(Components.interfaces.nsIIOService2)) {
   ios.manageOfflineStatus = false;
   ios.offline = false;
 }
@@ -176,64 +170,34 @@ function _Timer(func, delay) {
     do_timeout(newDelay, this._func);
   }
 };
 
 function _do_main() {
   if (_quit)
     return;
 
-  _log("test_info",
-       {_message: "TEST-INFO | (xpcshell/head.js) | running event loop\n"});
+  _testLogger.info("running event loop");
 
   var thr = Components.classes["@mozilla.org/thread-manager;1"]
                       .getService().currentThread;
 
   while (!_quit)
     thr.processNextEvent(true);
 
   while (thr.hasPendingEvents())
     thr.processNextEvent(true);
 }
 
 function _do_quit() {
-  _log("test_info",
-       {_message: "TEST-INFO | (xpcshell/head.js) | exiting test\n"});
+  _testLogger.info("exiting test");
   _Promise.Debugging.flushUncaughtErrors();
   _quit = true;
 }
 
-function _format_exception_stack(stack) {
-  if (typeof stack == "object" && stack.caller) {
-    let frame = stack;
-    let strStack = "";
-    while (frame != null) {
-      strStack += frame + "\n";
-      frame = frame.caller;
-    }
-    stack = strStack;
-  }
-  // frame is of the form "fname@file:line"
-  let frame_regexp = new RegExp("(.*)@(.*):(\\d*)", "g");
-  return stack.split("\n").reduce(function(stack_msg, frame) {
-    if (frame) {
-      let parts = frame_regexp.exec(frame);
-      if (parts) {
-        let [ _, func, file, line ] = parts;
-        return stack_msg + "JS frame :: " + file + " :: " +
-          (func || "anonymous") + " :: line " + line + "\n";
-      }
-      else { /* Could be a -e (command line string) style location. */
-        return stack_msg + "JS frame :: " + frame + "\n";
-      }
-    }
-    return stack_msg;
-  }, "");
-}
-
 /**
  * Overrides idleService with a mock.  Idle is commonly used for maintenance
  * tasks, thus if a test uses a service that requires the idle service, it will
  * start handling them.
  * This behaviour would cause random failures and slowdown tests execution,
  * for example by running database vacuum or cleanups for each test.
  *
  * @note Idle service is overridden by default.  If a test requires it, it will
@@ -378,18 +342,21 @@ function _execute_test() {
   // Override idle service by default.
   // Call do_get_idle() to restore the factory and get the service.
   _fakeIdleService.activate();
 
   _Promise.Debugging.clearUncaughtErrorObservers();
   _Promise.Debugging.addUncaughtErrorObserver(function observer({message, date, fileName, stack, lineNumber}) {
     let text = " A promise chain failed to handle a rejection: " +
         message + " - rejection date: " + date;
-    _log_message_with_stack("test_unexpected_fail",
-                            text, stack, fileName);
+    _testLogger.error(text,
+                      {
+                        stack: _format_stack(stack),
+                        source_file: fileName
+                      });
   });
 
   // _HEAD_FILES is dynamically defined by <runxpcshelltests.py>.
   _load_files(_HEAD_FILES);
   // _TEST_FILE is dynamically defined by <runxpcshelltests.py>.
   _load_files(_TEST_FILE);
 
   // Tack Assert.jsm methods to the current scope.
@@ -406,31 +373,30 @@ function _execute_test() {
   } catch (e) {
     _passed = false;
     // do_check failures are already logged and set _quit to true and throw
     // NS_ERROR_ABORT. If both of those are true it is likely this exception
     // has already been logged so there is no need to log it again. It's
     // possible that this will mask an NS_ERROR_ABORT that happens after a
     // do_check failure though.
     if (!_quit || e != Components.results.NS_ERROR_ABORT) {
-      let msgObject = {};
+      let extra = {};
       if (e.fileName) {
-        msgObject.source_file = e.fileName;
+        extra.source_file = e.fileName;
         if (e.lineNumber) {
-          msgObject.line_number = e.lineNumber;
+          extra.line_number = e.lineNumber;
         }
       } else {
-        msgObject.source_file = "xpcshell/head.js";
+        extra.source_file = "xpcshell/head.js";
       }
-      msgObject.diagnostic = _exception_message(e);
+      let message = _exception_message(e);
       if (e.stack) {
-        msgObject.diagnostic += " - See following stack:\n";
-        msgObject.stack = _format_exception_stack(e.stack);
+        extra.stack = _format_stack(e.stack);
       }
-      _log("test_unexpected_fail", msgObject);
+      _testLogger.error(message, extra);
     }
   }
 
   // _TAIL_FILES is dynamically defined by <runxpcshelltests.py>.
   _load_files(_TAIL_FILES);
 
   // Execute all of our cleanup functions.
   let reportCleanupError = function(ex) {
@@ -440,18 +406,21 @@ function _execute_test() {
     } else {
       stack = Components.stack.caller;
     }
     if (stack instanceof Components.interfaces.nsIStackFrame) {
       filename = stack.filename;
     } else if (ex.fileName) {
       filename = ex.fileName;
     }
-    _log_message_with_stack("test_unexpected_fail",
-                            ex, stack, filename);
+    _testLogger.error(_exception_message(ex),
+                      {
+                        stack: _format_stack(stack),
+                        source_file: filename
+                      });
   };
 
   let func;
   while ((func = _cleanupFunctions.pop())) {
     let result;
     try {
       result = func();
     } catch (ex) {
@@ -472,81 +441,54 @@ function _execute_test() {
     }
   }
 
   // Restore idle service to avoid leaks.
   _fakeIdleService.deactivate();
 
   if (!_passed)
     return;
-
-  var truePassedChecks = _passedChecks - _falsePassedChecks;
-  if (truePassedChecks > 0) {
-    _log("test_pass",
-         {_message: "TEST-PASS | (xpcshell/head.js) | " + truePassedChecks + " (+ " +
-                    _falsePassedChecks + ") check(s) passed\n",
-          source_file: _TEST_FILE,
-          passed_checks: truePassedChecks});
-    _log("test_info",
-         {_message: "TEST-INFO | (xpcshell/head.js) | " + _todoChecks +
-                    " check(s) todo\n",
-          source_file: _TEST_FILE,
-          todo_checks: _todoChecks});
-  } else {
-    // ToDo: switch to TEST-UNEXPECTED-FAIL when all tests have been updated. (Bug 496443)
-    _log("test_info",
-         {_message: "TEST-INFO | (xpcshell/head.js) | No (+ " + _falsePassedChecks +
-                    ") checks actually run\n",
-         source_file: _TEST_FILE});
-  }
 }
 
 /**
  * Loads files.
  *
  * @param aFiles Array of files to load.
  */
 function _load_files(aFiles) {
-  function loadTailFile(element, index, array) {
+  function load_file(element, index, array) {
     try {
       load(element);
-    } catch (e if e instanceof SyntaxError) {
-      _log("javascript_error",
-           {_message: "TEST-UNEXPECTED-FAIL | (xpcshell/head.js) | Source file " + element + " contains SyntaxError",
-            diagnostic: _exception_message(e),
-            source_file: element,
-            stack: _format_exception_stack(e.stack)});
     } catch (e) {
-      _log("javascript_error",
-           {_message: "TEST-UNEXPECTED-FAIL | (xpcshell/head.js) | Source file " + element + " contains an error",
-            diagnostic: _exception_message(e),
-            source_file: element,
-            stack: e.stack ? _format_exception_stack(e.stack) : null});
+      let extra = {
+        source_file: element
+      }
+      if (e.stack) {
+        extra.stack = _format_stack(e.stack);
+      }
+      _testLogger.error(_exception_message(e), extra);
     }
   }
 
-  aFiles.forEach(loadTailFile);
+  aFiles.forEach(load_file);
 }
 
 function _wrap_with_quotes_if_necessary(val) {
   return typeof val == "string" ? '"' + val + '"' : val;
 }
 
 /************** Functions to be used from the tests **************/
 
 /**
  * Prints a message to the output log.
  */
-function do_print(msg) {
-  var caller_stack = Components.stack.caller;
+function do_print(msg, data) {
   msg = _wrap_with_quotes_if_necessary(msg);
-  _log("test_info",
-       {source_file: caller_stack.filename,
-        diagnostic: msg});
-
+  data = data ? data : null;
+  _testLogger.info(msg, data);
 }
 
 /**
  * Calls the given function at least the specified number of milliseconds later.
  * The callback will not undershoot the given time, but it might overshoot --
  * don't expect precision!
  *
  * @param delay : uint
@@ -570,26 +512,23 @@ function do_execute_soon(callback, aName
         callback();
       } catch (e) {
         // do_check failures are already logged and set _quit to true and throw
         // NS_ERROR_ABORT. If both of those are true it is likely this exception
         // has already been logged so there is no need to log it again. It's
         // possible that this will mask an NS_ERROR_ABORT that happens after a
         // do_check failure though.
         if (!_quit || e != Components.results.NS_ERROR_ABORT) {
-          if (e.stack) {
-            _log("javascript_error",
-                 {source_file: "xpcshell/head.js",
-                  diagnostic: _exception_message(e) + " - See following stack:",
-                  stack: _format_exception_stack(e.stack)});
-          } else {
-            _log("javascript_error",
-                 {source_file: "xpcshell/head.js",
-                  diagnostic: _exception_message(e)});
-          }
+          let stack = e.stack ? _format_stack(e.stack) : null;
+          _testLogger.testStatus(_TEST_NAME,
+                                 funcName,
+                                 'ERROR',
+                                 'OK',
+                                 _exception_message(e),
+                                 stack);
           _do_quit();
         }
       }
       finally {
         do_test_finished(funcName);
       }
     }
   }, Components.interfaces.nsIThread.DISPATCH_NORMAL);
@@ -608,19 +547,26 @@ function do_throw(error, stack) {
   // otherwise get it from our call context
   stack = stack || error.stack || Components.stack.caller;
 
   if (stack instanceof Components.interfaces.nsIStackFrame)
     filename = stack.filename;
   else if (error.fileName)
     filename = error.fileName;
 
-  _log_message_with_stack("test_unexpected_fail",
-                          error, stack, filename);
+  _testLogger.error(_exception_message(error),
+                    {
+                      source_file: filename,
+                      stack: _format_stack(stack)
+                    });
+  _abort_failed_test();
+}
 
+function _abort_failed_test() {
+  // Called to abort the test run after all failures are logged.
   _passed = false;
   _do_quit();
   throw Components.results.NS_ERROR_ABORT;
 }
 
 function _format_stack(stack) {
   let normalized;
   if (stack instanceof Components.interfaces.nsIStackFrame) {
@@ -630,27 +576,16 @@ function _format_stack(stack) {
     }
     normalized = frames.join("\n");
   } else {
     normalized = "" + stack;
   }
   return _Task.Debugging.generateReadableStack(normalized, "    ");
 }
 
-function do_throw_todo(text, stack) {
-  if (!stack)
-    stack = Components.stack.caller;
-
-  _passed = false;
-  _log_message_with_stack("test_unexpected_pass",
-                          text, stack, stack.filename);
-  _do_quit();
-  throw Components.results.NS_ERROR_ABORT;
-}
-
 // Make a nice display string from an object that behaves
 // like Error
 function _exception_message(ex) {
   let message = "";
   if (ex.name) {
     message = ex.name + ": ";
   }
   if (ex.message) {
@@ -664,49 +599,37 @@ function _exception_message(ex) {
   }
   if (message !== "") {
     return message;
   }
   // Force ex to be stringified
   return "" + ex;
 }
 
-function _log_message_with_stack(action, ex, stack, filename, text) {
-  if (stack) {
-    _log(action,
-         {diagnostic: (text ? text : "") +
-                      _exception_message(ex) +
-                      " - See following stack:",
-          source_file: filename,
-          stack: _format_stack(stack)});
-  } else {
-    _log(action,
-         {diagnostic: (text ? text : "") +
-                      _exception_message(ex),
-          source_file: filename});
-  }
-}
-
 function do_report_unexpected_exception(ex, text) {
-  var caller_stack = Components.stack.caller;
+  let filename = Components.stack.caller.filename;
   text = text ? text + " - " : "";
 
   _passed = false;
-  _log_message_with_stack("test_unexpected_fail", ex, ex.stack || "",
-                          caller_stack.filename, text + "Unexpected exception ");
+  _testLogger.error(text + "Unexpected exception " + _exception_message(ex),
+                    {
+                      source_file: filename,
+                      stack: _format_stack(ex.stack)
+                    });
   _do_quit();
   throw Components.results.NS_ERROR_ABORT;
 }
 
 function do_note_exception(ex, text) {
-  var caller_stack = Components.stack.caller;
-  text = text ? text + " - " : "";
-
-  _log_message_with_stack("test_info", ex, ex.stack,
-                          caller_stack.filename, text + "Swallowed exception ");
+  let filename = Components.stack.caller.filename;
+  _testLogger.info(text + "Swallowed exception " + _exception_message(ex),
+                   {
+                     source_file: filename,
+                     stack: _format_stack(ex.stack)
+                   });
 }
 
 function _do_check_neq(left, right, stack, todo) {
   Assert.notEqual(left, right);
 }
 
 function do_check_neq(left, right, stack) {
   if (!stack)
@@ -721,39 +644,56 @@ function todo_check_neq(left, right, sta
 
   _do_check_neq(left, right, stack, true);
 }
 
 function do_report_result(passed, text, stack, todo) {
   while (stack.filename.contains("head.js") && stack.caller) {
     stack = stack.caller;
   }
+
+  let name = _gRunningTest ? _gRunningTest.name : stack.name;
+  let message;
+  if (name) {
+     message = "[" + name + " : " + stack.lineNumber + "] " + text;
+  } else {
+    message = text;
+  }
+
   if (passed) {
     if (todo) {
-      do_throw_todo(text, stack);
+      _testLogger.testStatus(_TEST_NAME,
+                             name,
+                             "PASS",
+                             "FAIL",
+                             message,
+                             _format_stack(stack));
+      _abort_failed_test();
     } else {
-      ++_passedChecks;
-      _log("test_pass",
-           {source_file: stack.filename,
-            test_name: stack.name,
-            line_number: stack.lineNumber,
-            diagnostic: "[" + stack.name + " : " + stack.lineNumber + "] " +
-                        text + "\n"});
+      _testLogger.testStatus(_TEST_NAME,
+                             name,
+                             "PASS",
+                             "PASS",
+                             message);
     }
   } else {
     if (todo) {
-      ++_todoChecks;
-      _log("test_known_fail",
-           {source_file: stack.filename,
-            test_name: stack.name,
-            line_number: stack.lineNumber,
-            diagnostic: "[" + stack.name + " : " + stack.lineNumber + "] " +
-                        text + "\n"});
+      _testLogger.testStatus(_TEST_NAME,
+                             name,
+                             "FAIL",
+                             "FAIL",
+                             message);
     } else {
-      do_throw(text, stack);
+      _testLogger.testStatus(_TEST_NAME,
+                             name,
+                             "FAIL",
+                             "PASS",
+                             message,
+                             _format_stack(stack));
+      _abort_failed_test();
     }
   }
 }
 
 function _do_check_eq(left, right, stack, todo) {
   if (!stack)
     stack = Components.stack.caller;
 
@@ -873,27 +813,25 @@ function do_check_instanceof(value, cons
 function todo_check_instanceof(value, constructor,
                              stack=Components.stack.caller) {
   do_check_instanceof(value, constructor, stack, true);
 }
 
 function do_test_pending(aName) {
   ++_tests_pending;
 
-  _log("test_pending",
-       {_message: "TEST-INFO | (xpcshell/head.js) | test" +
-                  (aName ? " " + aName : "") +
-                  " pending (" + _tests_pending + ")\n"});
+  _testLogger.info("(xpcshell/head.js) | test" +
+                   (aName ? " " + aName : "") +
+                   " pending (" + _tests_pending + ")");
 }
 
 function do_test_finished(aName) {
-  _log("test_finish",
-       {_message: "TEST-INFO | (xpcshell/head.js) | test" +
-                  (aName ? " " + aName : "") +
-                  " finished (" + _tests_pending + ")\n"});
+  _testLogger.info("(xpcshell/head.js) | test" +
+                   (aName ? " " + aName : "") +
+                   " finished (" + _tests_pending + ")");
   if (--_tests_pending == 0)
     _do_quit();
 }
 
 function do_get_file(path, allowNonexistent) {
   try {
     let lf = Components.classes["@mozilla.org/file/directory_service;1"]
       .getService(Components.interfaces.nsIProperties)
@@ -908,22 +846,18 @@ function do_get_file(path, allowNonexist
           lf.append(bits[i]);
       }
     }
 
     if (!allowNonexistent && !lf.exists()) {
       // Not using do_throw(): caller will continue.
       _passed = false;
       var stack = Components.stack.caller;
-      _log("test_unexpected_fail",
-           {source_file: stack.filename,
-            test_name: stack.name,
-            line_number: stack.lineNumber,
-            diagnostic: "[" + stack.name + " : " + stack.lineNumber + "] " +
-                        lf.path + " does not exist\n"});
+      _testLogger.error("[" + stack.name + " : " + stack.lineNumber + "] " +
+                        lf.path + " does not exist");
     }
 
     return lf;
   }
   catch (ex) {
     do_throw(ex.toString(), Components.stack.caller);
   }
 
@@ -935,17 +869,16 @@ function do_get_cwd() {
   return do_get_file("");
 }
 
 function do_load_manifest(path) {
   var lf = do_get_file(path);
   const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
   do_check_true(Components.manager instanceof nsIComponentRegistrar);
   // Previous do_check_true() is not a test check.
-  ++_falsePassedChecks;
   Components.manager.autoRegister(lf);
 }
 
 /**
  * Parse a DOM document.
  *
  * @param aPath File path to the document.
  * @param aType Content type to use in DOMParser.
@@ -1033,19 +966,17 @@ function do_get_minidumpdir() {
 /**
  * Registers a directory with the profile service,
  * and return the directory as an nsILocalFile.
  *
  * @return nsILocalFile of the profile directory.
  */
 function do_get_profile() {
   if (!runningInParent) {
-    _log("test_info",
-         {_message: "TEST-INFO | (xpcshell/head.js) | Ignoring profile creation from child process.\n"});
-
+    _testLogger.info("Ignoring profile creation from child process.");
     return null;
   }
 
   if (!_profileInitialized) {
     // Since we have a profile, we will notify profile shutdown topics at
     // the end of the current test, to ensure correct cleanup on shutdown.
     do_register_cleanup(function() {
       let obsSvc = Components.classes["@mozilla.org/observer-service;1"].
@@ -1166,19 +1097,21 @@ function run_test_in_child(testFile, opt
 {
   var callback = (typeof optionalCallback == 'undefined') ? 
                     do_test_finished : optionalCallback;
 
   do_load_child_test_harness();
 
   var testPath = do_get_file(testFile).path.replace(/\\/g, "/");
   do_test_pending("run in child");
-  sendCommand("_log('child_test_start', {_message: 'CHILD-TEST-STARTED'}); "
-              + "const _TEST_FILE=['" + testPath + "']; _execute_test(); "
-              + "_log('child_test_end', {_message: 'CHILD-TEST-COMPLETED'});",
+  sendCommand("_testLogger.info('CHILD-TEST-STARTED'); "
+              + "const _TEST_FILE=['" + testPath + "']; "
+              + "const _TEST_NAME=" + uneval(_TEST_NAME) + "; "
+              + "_execute_test(); "
+              + "_testLogger.info('CHILD-TEST-COMPLETED');",
               callback);
 }
 
 /**
  * Execute a given function as soon as a particular cross-process message is received.
  * Must be paired with do_send_remote_message or equivalent ProcessMessageManager calls.
  */
 function do_await_remote_message(name, callback)
@@ -1295,17 +1228,17 @@ function run_next_test()
  
   function _run_next_test()
   {
     if (_gTestIndex < _gTests.length) {
       // Flush uncaught errors as early and often as possible.
       _Promise.Debugging.flushUncaughtErrors();
       let _isTask;
       [_isTask, _gRunningTest] = _gTests[_gTestIndex++];
-      print("TEST-INFO | " + _TEST_FILE + " | Starting " + _gRunningTest.name);
+      _testLogger.info(_TEST_NAME + " | Starting " + _gRunningTest.name);
       do_test_pending(_gRunningTest.name);
 
       if (_isTask) {
         _gTaskRunning = true;
         _Task.spawn(_gRunningTest).then(
           () => { _gTaskRunning = false; run_next_test(); },
           (ex) => { _gTaskRunning = false; do_report_unexpected_exception(ex); }
         );
--- a/testing/xpcshell/mach_commands.py
+++ b/testing/xpcshell/mach_commands.py
@@ -1,37 +1,39 @@
 # 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/.
 
 # Integrates the xpcshell test runner with mach.
 
 from __future__ import unicode_literals, print_function
 
-import mozpack.path
-import logging
+import argparse
 import os
 import shutil
 import sys
 import urllib2
 
-from StringIO import StringIO
+from mozlog import structured
 
 from mozbuild.base import (
     MachCommandBase,
     MozbuildObject,
     MachCommandConditions as conditions,
 )
 
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
+_parser = argparse.ArgumentParser()
+structured.commandline.add_logging_group(_parser)
+
 ADB_NOT_FOUND = '''
 The %s command requires the adb binary to be on your path.
 
 If you have a B2G build, this can be found in
 '%s/out/host/<platform>/bin'.
 '''.lstrip()
 
 BUSYBOX_URLS = {
@@ -40,21 +42,16 @@ BUSYBOX_URLS = {
 }
 
 
 if sys.version_info[0] < 3:
     unicode_type = unicode
 else:
     unicode_type = str
 
-# Simple filter to omit the message emitted as a test file begins.
-class TestStartFilter(logging.Filter):
-    def filter(self, record):
-        return not record.params['msg'].endswith("running test ...")
-
 # This should probably be consolidated with similar classes in other test
 # runners.
 class InvalidTestPathError(Exception):
     """Exception raised when the test path is not valid."""
 
 
 class XPCShellRunner(MozbuildObject):
     """Run xpcshell tests."""
@@ -64,16 +61,17 @@ class XPCShellRunner(MozbuildObject):
             '_tests', 'xpcshell', 'xpcshell.ini')])
 
         return self._run_xpcshell_harness(manifest=manifest, **kwargs)
 
     def run_test(self, test_paths, interactive=False,
                  keep_going=False, sequential=False, shuffle=False,
                  debugger=None, debuggerArgs=None, debuggerInteractive=None,
                  rerun_failures=False, test_objects=None, verbose=False,
+                 log=None,
                  # ignore parameters from other platforms' options
                  **kwargs):
         """Runs an individual xpcshell test."""
         from mozbuild.testing import TestResolver
         from manifestparser import TestManifest
 
         # TODO Bug 794506 remove once mach integrates with virtualenv.
         build_path = os.path.join(self.topobjdir, 'build')
@@ -81,17 +79,17 @@ class XPCShellRunner(MozbuildObject):
             sys.path.append(build_path)
 
         if test_paths == ['all']:
             self.run_suite(interactive=interactive,
                            keep_going=keep_going, shuffle=shuffle, sequential=sequential,
                            debugger=debugger, debuggerArgs=debuggerArgs,
                            debuggerInteractive=debuggerInteractive,
                            rerun_failures=rerun_failures,
-                           verbose=verbose)
+                           verbose=verbose, log=log)
             return
         elif test_paths:
             test_paths = [self._wrap_path_argument(p).relpath() for p in test_paths]
 
         if test_objects:
             tests = test_objects
         else:
             resolver = self._spawn(TestResolver)
@@ -113,67 +111,61 @@ class XPCShellRunner(MozbuildObject):
             'shuffle': shuffle,
             'sequential': sequential,
             'debugger': debugger,
             'debuggerArgs': debuggerArgs,
             'debuggerInteractive': debuggerInteractive,
             'rerun_failures': rerun_failures,
             'manifest': manifest,
             'verbose': verbose,
+            'log': log,
         }
 
         return self._run_xpcshell_harness(**args)
 
     def _run_xpcshell_harness(self, manifest,
                               test_path=None, shuffle=False, interactive=False,
                               keep_going=False, sequential=False,
                               debugger=None, debuggerArgs=None, debuggerInteractive=None,
-                              rerun_failures=False, verbose=False):
+                              rerun_failures=False, verbose=False, log=None):
 
         # Obtain a reference to the xpcshell test runner.
         import runxpcshelltests
 
-        dummy_log = StringIO()
-        xpcshell = runxpcshelltests.XPCShellTests(log=dummy_log)
+        xpcshell = runxpcshelltests.XPCShellTests(log=log)
         self.log_manager.enable_unstructured()
 
-        xpcshell_filter = TestStartFilter()
-        self.log_manager.terminal_handler.addFilter(xpcshell_filter)
-
         tests_dir = os.path.join(self.topobjdir, '_tests', 'xpcshell')
         modules_dir = os.path.join(self.topobjdir, '_tests', 'modules')
         # We want output from the test to be written immediately if we are only
         # running a single test.
         single_test = (test_path is not None or
                        (manifest and len(manifest.test_paths())==1))
-        verbose_output = verbose or single_test
         sequential = sequential or single_test
 
         args = {
             'manifest': manifest,
             'xpcshell': self.get_binary_path('xpcshell'),
             'mozInfo': os.path.join(self.topobjdir, 'mozinfo.json'),
             'symbolsPath': os.path.join(self.distdir, 'crashreporter-symbols'),
             'interactive': interactive,
             'keepGoing': keep_going,
             'logfiles': False,
             'sequential': sequential,
             'shuffle': shuffle,
             'testsRootDir': tests_dir,
             'testingModulesDir': modules_dir,
             'profileName': 'firefox',
-            'verbose': test_path is not None,
+            'verbose': verbose or single_test,
             'xunitFilename': os.path.join(self.statedir, 'xpchsell.xunit.xml'),
             'xunitName': 'xpcshell',
             'pluginsPath': os.path.join(self.distdir, 'plugins'),
             'debugger': debugger,
             'debuggerArgs': debuggerArgs,
             'debuggerInteractive': debuggerInteractive,
-            'on_message': (lambda obj, msg: xpcshell.log.info(msg.decode('utf-8', 'replace'))) \
-                            if verbose_output else None,
         }
 
         if test_path is not None:
             args['testPath'] = test_path
 
         # A failure manifest is written by default. If --rerun-failures is
         # specified and a prior failure manifest is found, the prior manifest
         # will be run. A new failure manifest is always written over any
@@ -199,17 +191,16 @@ class XPCShellRunner(MozbuildObject):
 
             if isinstance(k, unicode_type):
                 k = k.encode('utf-8')
 
             filtered_args[k] = v
 
         result = xpcshell.runTests(**filtered_args)
 
-        self.log_manager.terminal_handler.removeFilter(xpcshell_filter)
         self.log_manager.disable_unstructured()
 
         if not result and not xpcshell.sequential:
             print("Tests were run in parallel. Try running with --sequential "
                   "to make sure the failures were not caused by this.")
         return int(not result)
 
 class AndroidXPCShellRunner(MozbuildObject):
@@ -228,17 +219,17 @@ class AndroidXPCShellRunner(MozbuildObje
             else:
                 raise Exception("You must provide a device IP to connect to via the --ip option")
         return dm
 
     """Run Android xpcshell tests."""
     def run_test(self,
                  test_paths, keep_going,
                  devicemanager, ip, port, remote_test_root, no_setup, local_apk,
-                 test_objects=None,
+                 test_objects=None, log=None,
                  # ignore parameters from other platforms' options
                  **kwargs):
         # TODO Bug 794506 remove once mach integrates with virtualenv.
         build_path = os.path.join(self.topobjdir, 'build')
         if build_path not in sys.path:
             sys.path.append(build_path)
 
         import remotexpcshelltests
@@ -283,31 +274,25 @@ class AndroidXPCShellRunner(MozbuildObje
             options.testPath = test_objects[0]['path']
             options.verbose = True
         else:
             if len(test_paths) > 1:
                 print('Warning: only the first test path argument will be used.')
             testdirs = test_paths[0]
             options.testPath = test_paths[0]
             options.verbose = True
-        dummy_log = StringIO()
-        xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, args=testdirs, log=dummy_log)
-        self.log_manager.enable_unstructured()
 
-        xpcshell_filter = TestStartFilter()
-        self.log_manager.terminal_handler.addFilter(xpcshell_filter)
+        xpcshell = remotexpcshelltests.XPCShellRemote(dm, options, testdirs, log)
 
         result = xpcshell.runTests(xpcshell='xpcshell',
                       testClass=remotexpcshelltests.RemoteXPCShellTestThread,
                       testdirs=testdirs,
                       mobileArgs=xpcshell.mobileArgs,
                       **options.__dict__)
 
-        self.log_manager.terminal_handler.removeFilter(xpcshell_filter)
-        self.log_manager.disable_unstructured()
 
         return int(not result)
 
 class B2GXPCShellRunner(MozbuildObject):
     def __init__(self, *args, **kwargs):
         MozbuildObject.__init__(self, *args, **kwargs)
 
         # TODO Bug 794506 remove once mach integrates with virtualenv.
@@ -343,17 +328,17 @@ class B2GXPCShellRunner(MozbuildObject):
                   'initial setup will be slow.')
             return
 
         with open(busybox_path, 'wb') as f:
             f.write(data.read())
         return busybox_path
 
     def run_test(self, test_paths, b2g_home=None, busybox=None, device_name=None,
-                 test_objects=None,
+                 test_objects=None, log=None,
                  # ignore parameters from other platforms' options
                  **kwargs):
         try:
             import which
             which.which('adb')
         except which.WhichError:
             # TODO Find adb automatically if it isn't on the path
             print(ADB_NOT_FOUND % ('mochitest-remote', b2g_home))
@@ -392,17 +377,17 @@ class B2GXPCShellRunner(MozbuildObject):
         options.emulator = 'arm'
         if device_name.startswith('emulator'):
             if 'x86' in device_name:
                 options.emulator = 'x86'
 
         if not options.busybox:
             options.busybox = self._download_busybox(b2g_home, options.emulator)
 
-        return runtestsb2g.run_remote_xpcshell(parser, options, args)
+        return runtestsb2g.run_remote_xpcshell(parser, options, args, log)
 
 def is_platform_supported(cls):
     """Must have a Firefox, Android or B2G build."""
     return conditions.is_android(cls) or \
            conditions.is_b2g(cls) or \
            conditions.is_firefox(cls)
 
 @CommandProvider
@@ -410,17 +395,18 @@ class MachCommands(MachCommandBase):
     def __init__(self, context):
         MachCommandBase.__init__(self, context)
 
         for attr in ('b2g_home', 'device_name'):
             setattr(self, attr, getattr(context, attr, None))
 
     @Command('xpcshell-test', category='testing',
         conditions=[is_platform_supported],
-        description='Run XPCOM Shell tests (API direct unit testing)')
+        description='Run XPCOM Shell tests (API direct unit testing)',
+        parser=_parser)
     @CommandArgument('test_paths', default='all', nargs='*', metavar='TEST',
         help='Test to run. Can be specified as a single JS file, a directory, '
              'or omitted. If omitted, the entire test suite is executed.')
     @CommandArgument('--verbose', '-v', action='store_true',
         help='Provide full output from each test process.')
     @CommandArgument("--debugger", default=None, metavar='DEBUGGER',
                      help = "Run xpcshell under the given debugger.")
     @CommandArgument("--debugger-args", default=None, metavar='ARGS', type=str,
@@ -461,16 +447,21 @@ class MachCommands(MachCommandBase):
         # We should probably have a utility function to ensure the tree is
         # ready to run tests. Until then, we just create the state dir (in
         # case the tree wasn't built with mach).
         self._ensure_state_subdir_exists('.')
 
         driver = self._spawn(BuildDriver)
         driver.install_tests(remove=False)
 
+        structured.commandline.formatter_option_defaults['verbose'] = True
+        params['log'] = structured.commandline.setup_logging("XPCShellTests",
+                                                             params,
+                                                             {"mach": sys.stdout})
+
         if conditions.is_android(self):
             xpcshell = self._spawn(AndroidXPCShellRunner)
         elif conditions.is_b2g(self):
             xpcshell = self._spawn(B2GXPCShellRunner)
             params['b2g_home'] = self.b2g_home
             params['device_name'] = self.device_name
         else:
             xpcshell = self._spawn(XPCShellRunner)
--- a/testing/xpcshell/remotexpcshelltests.py
+++ b/testing/xpcshell/remotexpcshelltests.py
@@ -6,16 +6,18 @@
 
 import posixpath
 import sys, os
 import subprocess
 import runxpcshelltests as xpcshell
 import tempfile
 from automationutils import replaceBackSlashes
 from zipfile import ZipFile
+from mozlog import structured
+from mozlog.structured import commandline
 import shutil
 import mozdevice
 import mozfile
 import mozinfo
 
 here = os.path.dirname(os.path.abspath(__file__))
 
 def remoteJoin(path1, path2):
@@ -58,30 +60,30 @@ class RemoteXPCShellTestThread(xpcshell.
             return None
 
         # making sure tmp dir is set up
         self.setupTempDir()
 
         pluginsDir = remoteJoin(self.remoteTmpDir, "plugins")
         self.device.pushDir(self.pluginsPath, pluginsDir)
         if self.interactive:
-            self.log.info("TEST-INFO | plugins dir is %s" % pluginsDir)
+            self.log.info("plugins dir is %s" % pluginsDir)
         return pluginsDir
 
     def setupProfileDir(self):
         self.device.removeDir(self.profileDir)
         self.device.mkDir(self.profileDir)
         if self.interactive or self.singleFile:
-            self.log.info("TEST-INFO | profile dir is %s" % self.profileDir)
+            self.log.info("profile dir is %s" % self.profileDir)
         return self.profileDir
 
     def logCommand(self, name, completeCmd, testdir):
-        self.log.info("TEST-INFO | %s | full command: %r" % (name, completeCmd))
-        self.log.info("TEST-INFO | %s | current directory: %r" % (name, self.remoteHere))
-        self.log.info("TEST-INFO | %s | environment: %s" % (name, self.env))
+        self.log.info("%s | full command: %r" % (name, completeCmd))
+        self.log.info("%s | current directory: %r" % (name, self.remoteHere))
+        self.log.info("%s | environment: %s" % (name, self.env))
 
     def getHeadAndTailFiles(self, test):
         """Override parent method to find files on remote device."""
         def sanitize_list(s, kind):
             for f in s.strip().split(' '):
                 f = f.strip()
                 if len(f) < 1:
                     continue
@@ -115,20 +117,17 @@ class RemoteXPCShellTestThread(xpcshell.
 
         if self.remoteDebugger:
             # for example, "/data/local/gdbserver" "localhost:12345"
             self.xpcsCmd = [
               self.remoteDebugger,
               self.remoteDebuggerArgs,
               self.xpcsCmd]
 
-    def testTimeout(self, test_file, proc):
-        self.timedout = True
-        if not self.retry:
-            self.log.error("TEST-UNEXPECTED-FAIL | %s | Test timed out" % test_file)
+    def killTimeout(self, proc):
         self.kill(proc)
 
     def launchProcess(self, cmd, stdout, stderr, env, cwd, timeout=None):
         self.timedout = False
         cmd.insert(1, self.remoteHere)
         outputFile = "xpcshelloutput"
         with open(outputFile, 'w+') as f:
             try:
@@ -206,17 +205,17 @@ class RemoteXPCShellTestThread(xpcshell.
             if f is not None:
                 f.close()
 
 
 # A specialization of XPCShellTests that runs tests on an Android device
 # via devicemanager.
 class XPCShellRemote(xpcshell.XPCShellTests, object):
 
-    def __init__(self, devmgr, options, args, log=None):
+    def __init__(self, devmgr, options, args, log):
         xpcshell.XPCShellTests.__init__(self, log)
 
         # Add Android version (SDK level) to mozinfo so that manifest entries
         # can be conditional on android_version.
         androidVersion = devmgr.shellCheckOutput(['getprop', 'ro.build.version.sdk'])
         mozinfo.info['android_version'] = androidVersion
 
         self.localLib = options.localLib
@@ -570,29 +569,33 @@ class PathMapping:
 
 def main():
 
     if sys.version_info < (2,7):
         print >>sys.stderr, "Error: You must use python version 2.7 or newer but less than 3.0"
         sys.exit(1)
 
     parser = RemoteXPCShellOptions()
+    structured.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
     if not options.localAPK:
         for file in os.listdir(os.path.join(options.objdir, "dist")):
             if (file.endswith(".apk") and file.startswith("fennec")):
                 options.localAPK = os.path.join(options.objdir, "dist")
                 options.localAPK = os.path.join(options.localAPK, file)
                 print >>sys.stderr, "using APK: " + options.localAPK
                 break
         else:
             print >>sys.stderr, "Error: please specify an APK"
             sys.exit(1)
 
     options = parser.verifyRemoteOptions(options)
+    log = commandline.setup_logging("Remote XPCShell",
+                                    options,
+                                    {"tbpl": sys.stdout})
 
     if len(args) < 1 and options.manifest is None:
         print >>sys.stderr, """Usage: %s <test dirs>
              or: %s --manifest=test.manifest """ % (sys.argv[0], sys.argv[0])
         sys.exit(1)
 
     if options.dm_trans == "adb":
         if options.deviceIP:
@@ -604,17 +607,17 @@ def main():
             print "Error: you must provide a device IP to connect to via the --device option"
             sys.exit(1)
         dm = mozdevice.DroidSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot)
 
     if options.interactive and not options.testPath:
         print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
         sys.exit(1)
 
-    xpcsh = XPCShellRemote(dm, options, args)
+    xpcsh = XPCShellRemote(dm, options, args, log)
 
     # we don't run concurrent tests on mobile
     options.sequential = True
 
     if not xpcsh.runTests(xpcshell='xpcshell',
                           testClass=RemoteXPCShellTestThread,
                           testdirs=args[0:],
                           mobileArgs=xpcsh.mobileArgs,
--- a/testing/xpcshell/runtestsb2g.py
+++ b/testing/xpcshell/runtestsb2g.py
@@ -6,16 +6,18 @@
 
 import sys
 import os
 sys.path.insert(0, os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0]))))
 
 import traceback
 from remotexpcshelltests import RemoteXPCShellTestThread, XPCShellRemote, RemoteXPCShellOptions
 from mozdevice import devicemanagerADB, DMError
+from mozlog import structured
+from mozlog.structured import commandline
 
 DEVICE_TEST_ROOT = '/data/local/tests'
 
 
 from marionette import Marionette
 
 class B2GXPCShellTestThread(RemoteXPCShellTestThread):
     # Overridden
@@ -148,17 +150,17 @@ class B2GOptions(RemoteXPCShellOptions):
 
         if options.geckoPath and not options.emulator:
             self.error("You must specify --emulator if you specify --gecko-path")
 
         if options.logdir and not options.emulator:
             self.error("You must specify --emulator if you specify --logdir")
         return RemoteXPCShellOptions.verifyRemoteOptions(self, options)
 
-def run_remote_xpcshell(parser, options, args):
+def run_remote_xpcshell(parser, options, args, log):
     options = parser.verifyRemoteOptions(options)
 
     # Create the Marionette instance
     kwargs = {}
     if options.emulator:
         kwargs['emulator'] = options.emulator
         if options.no_window:
             kwargs['noWindow'] = True
@@ -189,17 +191,17 @@ def run_remote_xpcshell(parser, options,
         if options.deviceIP:
             kwargs['host'] = options.deviceIP
             kwargs['port'] = options.devicePort
         kwargs['deviceRoot'] = options.remoteTestRoot
         dm = devicemanagerADB.DeviceManagerADB(**kwargs)
 
     if not options.remoteTestRoot:
         options.remoteTestRoot = dm.deviceRoot
-    xpcsh = B2GXPCShellRemote(dm, options, args)
+    xpcsh = B2GXPCShellRemote(dm, options, args, log)
 
     # we don't run concurrent tests on mobile
     options.sequential = True
 
     try:
         if not xpcsh.runTests(xpcshell='xpcshell', testdirs=args[0:],
                                  testClass=B2GXPCShellTestThread,
                                  mobileArgs=xpcsh.mobileArgs,
@@ -207,22 +209,21 @@ def run_remote_xpcshell(parser, options,
             sys.exit(1)
     except:
         print "Automation Error: Exception caught while running tests"
         traceback.print_exc()
         sys.exit(1)
 
 def main():
     parser = B2GOptions()
+    structured.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
-
-    run_remote_xpcshell(parser, options, args)
+    log = commandline.setup_logging("Remote XPCShell",
+                                    options,
+                                    {"tbpl": sys.stdout})
+    run_remote_xpcshell(parser, options, args, log)
 
 # You usually run this like :
 # python runtestsb2g.py --emulator arm --b2gpath $B2GPATH --manifest $MANIFEST [--xre-path $MOZ_HOST_BIN
 #                                                                               --adbpath $ADB_PATH
 #                                                                               ...]
-#
-# For xUnit output you should also pass in --tests-root-dir ..objdir-gecko/_tests
-#                                          --xunit-file ..objdir_gecko/_tests/results.xml
-#                                          --xunit-suite-name xpcshell-tests
 if __name__ == '__main__':
     main()
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -10,102 +10,90 @@ import math
 import mozdebug
 import mozinfo
 import os
 import os.path
 import random
 import re
 import shutil
 import signal
-import socket
 import sys
 import time
 import traceback
-import xml.dom.minidom
+
 from collections import deque
 from distutils import dir_util
 from multiprocessing import cpu_count
 from optparse import OptionParser
 from subprocess import Popen, PIPE, STDOUT
 from tempfile import mkdtemp, gettempdir
-from threading import Timer, Thread, Event, RLock
+from threading import (
+    Timer,
+    Thread,
+    Event,
+    current_thread,
+)
 
 try:
     import psutil
     HAVE_PSUTIL = True
 except ImportError:
     HAVE_PSUTIL = False
 
-from automation import Automation, getGlobalLog, resetGlobalLog
-from automationutils import *
-
-# Printing buffered output in case of a failure or verbose mode will result
-# in buffered output interleaved with other threads' output.
-# To prevent his, each call to the logger as well as any blocks of output that
-# are intended to be continuous are protected by the same lock.
-LOG_MUTEX = RLock()
+from automation import Automation
+from automationutils import replaceBackSlashes, addCommonOptions
 
 HARNESS_TIMEOUT = 5 * 60
 
 # benchmarking on tbpl revealed that this works best for now
 NUM_THREADS = int(cpu_count() * 4)
 
-FAILURE_ACTIONS = set(['test_unexpected_fail',
-                       'test_unexpected_pass',
-                       'javascript_error'])
-ACTION_STRINGS = {
-    "test_unexpected_fail": "TEST-UNEXPECTED-FAIL",
-    "test_known_fail": "TEST-KNOWN-FAIL",
-    "test_unexpected_pass": "TEST-UNEXPECTED-PASS",
-    "javascript_error": "TEST-UNEXPECTED-FAIL",
-    "test_pass": "TEST-PASS",
-    "test_info": "TEST-INFO"
-}
+EXPECTED_LOG_ACTIONS = set([
+    "test_status",
+    "log",
+])
 
 # --------------------------------------------------------------
 # TODO: this is a hack for mozbase without virtualenv, remove with bug 849900
 #
 here = os.path.dirname(__file__)
 mozbase = os.path.realpath(os.path.join(os.path.dirname(here), 'mozbase'))
 
 if os.path.isdir(mozbase):
     for package in os.listdir(mozbase):
         sys.path.append(os.path.join(mozbase, package))
 
 import manifestparser
 import mozcrash
 import mozinfo
+from mozlog import structured
 
 # --------------------------------------------------------------
 
 # TODO: perhaps this should be in a more generally shared location?
 # This regex matches all of the C0 and C1 control characters
 # (U+0000 through U+001F; U+007F; U+0080 through U+009F),
 # except TAB (U+0009), CR (U+000D), LF (U+000A) and backslash (U+005C).
 # A raw string is deliberately not used.
 _cleanup_encoding_re = re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f\\\\]')
 def _cleanup_encoding_repl(m):
     c = m.group(0)
     return '\\\\' if c == '\\' else '\\x{0:02X}'.format(ord(c))
 def cleanup_encoding(s):
     """S is either a byte or unicode string.  Either way it may
        contain control characters, unpaired surrogates, reserved code
        points, etc.  If it is a byte string, it is assumed to be
-       UTF-8, but it may not be *correct* UTF-8.  Produce a byte
-       string that can safely be dumped into a (generally UTF-8-coded)
-       logfile."""
+       UTF-8, but it may not be *correct* UTF-8.  Return a
+       sanitized unicode object."""
+    if not isinstance(s, basestring):
+        return unicode(s)
     if not isinstance(s, unicode):
         s = s.decode('utf-8', 'replace')
-    if s.endswith('\n'):
-        # A new line is always added by head.js to delimit messages,
-        # however consumers will want to supply their own.
-        s = s[:-1]
     # Replace all C0 and C1 control characters with \xNN escapes.
-    s = _cleanup_encoding_re.sub(_cleanup_encoding_repl, s)
-    return s.encode('utf-8', 'backslashreplace')
+    return _cleanup_encoding_re.sub(_cleanup_encoding_repl, s)
 
 """ Control-C handling """
 gotSIGINT = False
 def markGotSIGINT(signum, stackFrame):
     global gotSIGINT
     gotSIGINT = True
 
 class XPCShellTestThread(Thread):
@@ -132,54 +120,57 @@ class XPCShellTestThread(Thread):
         self.profileName = kwargs.get('profileName')
         self.singleFile = kwargs.get('singleFile')
         self.env = copy.deepcopy(kwargs.get('env'))
         self.symbolsPath = kwargs.get('symbolsPath')
         self.logfiles = kwargs.get('logfiles')
         self.xpcshell = kwargs.get('xpcshell')
         self.xpcsRunArgs = kwargs.get('xpcsRunArgs')
         self.failureManifest = kwargs.get('failureManifest')
-        self.on_message = kwargs.get('on_message')
 
         self.tests_root_dir = tests_root_dir
         self.app_dir_key = app_dir_key
         self.interactive = interactive
         self.verbose = verbose
         self.pStdout = pStdout
         self.pStderr = pStderr
         self.keep_going = keep_going
         self.log = log
 
         # only one of these will be set to 1. adding them to the totals in
         # the harness
         self.passCount = 0
         self.todoCount = 0
         self.failCount = 0
 
+        # Context for output processing
         self.output_lines = []
         self.has_failure_output = False
         self.saw_proc_start = False
         self.saw_proc_end = False
+        self.complete_command = None
+        self.harness_timeout = kwargs.get('harness_timeout')
+        self.timedout = False
 
         # event from main thread to signal work done
         self.event = event
         self.done = False # explicitly set flag so we don't rely on thread.isAlive
 
     def run(self):
         try:
             self.run_test()
         except Exception as e:
             self.exception = e
             self.traceback = traceback.format_exc()
         else:
             self.exception = None
             self.traceback = None
         if self.retry:
-            self.log.info("TEST-INFO | %s | Test failed or timed out, will retry."
-                          % self.test_object['name'])
+            self.log.info("%s failed or timed out, will retry." %
+                          self.test_object['id'])
         self.done = True
         self.event.set()
 
     def kill(self, proc):
         """
           Simple wrapper to kill a process.
           On a remote system, this is overloaded to handle remote process communication.
         """
@@ -255,56 +246,96 @@ class XPCShellTestThread(Thread):
                         test_name=None):
         """
           Simple wrapper to check for crashes.
           On a remote system, this is more complex and we need to overload this function.
         """
         return mozcrash.check_for_crashes(dump_directory, symbols_path, test_name=test_name)
 
     def logCommand(self, name, completeCmd, testdir):
-        self.log.info("TEST-INFO | %s | full command: %r" % (name, completeCmd))
-        self.log.info("TEST-INFO | %s | current directory: %r" % (name, testdir))
+        self.log.info("%s | full command: %r" % (name, completeCmd))
+        self.log.info("%s | current directory: %r" % (name, testdir))
         # Show only those environment variables that are changed from
         # the ambient environment.
         changedEnv = (set("%s=%s" % i for i in self.env.iteritems())
                       - set("%s=%s" % i for i in os.environ.iteritems()))
-        self.log.info("TEST-INFO | %s | environment: %s" % (name, list(changedEnv)))
+        self.log.info("%s | environment: %s" % (name, list(changedEnv)))
+
+    def killTimeout(self, proc):
+        Automation().killAndGetStackNoScreenshot(proc.pid,
+                                                 self.appPath,
+                                                 self.debuggerInfo)
+
+    def postCheck(self, proc):
+        """Checks for a still-running test process, kills it and fails the test if found.
+        We can sometimes get here before the process has terminated, which would
+        cause removeDir() to fail - so check for the process and kill it if needed.
+        """
+        if proc and self.poll(proc) is None:
+            self.kill(proc)
+            message = "%s | Process still running after test!" % self.test_object['id']
+            if self.retry:
+                self.log.info(message)
+                self.log_full_output(self.output_lines)
+                return
+
+            self.log.error(message)
+            self.log_full_output(self.output_lines)
+            self.failCount = 1
 
-    def testTimeout(self, test_file, proc):
-        if not self.retry:
-            self.log.error("TEST-UNEXPECTED-FAIL | %s | Test timed out" % test_file)
+    def testTimeout(self, proc):
+        if self.test_object['expected'] == 'pass':
+            expected = 'PASS'
+        else:
+            expected = 'FAIL'
+
+        if self.retry:
+            self.log.test_end(self.test_object['id'], 'TIMEOUT',
+                              expected='TIMEOUT',
+                              message="Test timed out")
+        else:
+            self.failCount = 1
+            self.log.test_end(self.test_object['id'], 'TIMEOUT',
+                              expected=expected,
+                              message="Test timed out")
+            self.log_full_output(self.output_lines)
+
         self.done = True
-        Automation().killAndGetStackNoScreenshot(proc.pid, self.appPath, self.debuggerInfo)
+        self.timedout = True
+        self.killTimeout(proc)
+        self.log.info("xpcshell return code: %s" % self.getReturnCode(proc))
+        self.postCheck(proc)
+        self.clean_temp_dirs(self.test_object['path'])
 
     def buildCmdTestFile(self, name):
         """
           Build the command line arguments for the test file.
           On a remote system, this may be overloaded to use a remote path structure.
         """
         return ['-e', 'const _TEST_FILE = ["%s"];' %
                   replaceBackSlashes(name)]
 
     def setupTempDir(self):
         tempDir = mkdtemp()
         self.env["XPCSHELL_TEST_TEMP_DIR"] = tempDir
         if self.interactive:
-            self.log.info("TEST-INFO | temp dir is %s" % tempDir)
+            self.log.info("temp dir is %s" % tempDir)
         return tempDir
 
     def setupPluginsDir(self):
         if not os.path.isdir(self.pluginsPath):
             return None
 
         pluginsDir = mkdtemp()
         # shutil.copytree requires dst to not exist. Deleting the tempdir
         # would make a race condition possible in a concurrent environment,
         # so we are using dir_utils.copy_tree which accepts an existing dst
         dir_util.copy_tree(self.pluginsPath, pluginsDir)
         if self.interactive:
-            self.log.info("TEST-INFO | plugins dir is %s" % pluginsDir)
+            self.log.info("plugins dir is %s" % pluginsDir)
         return pluginsDir
 
     def setupProfileDir(self):
         """
           Create a temporary folder for the profile and set appropriate environment variables.
           When running check-interactive and check-one, the directory is well-defined and
           retained for inspection once the tests complete.
 
@@ -317,17 +348,17 @@ class XPCShellTestThread(Thread):
                 self.removeDir(profileDir)
             except:
                 pass
             os.makedirs(profileDir)
         else:
             profileDir = mkdtemp()
         self.env["XPCSHELL_TEST_PROFILE_DIR"] = profileDir
         if self.interactive or self.singleFile:
-            self.log.info("TEST-INFO | profile dir is %s" % profileDir)
+            self.log.info("profile dir is %s" % profileDir)
         return profileDir
 
     def buildCmdHead(self, headfiles, tailfiles, xpcscmd):
         """
           Build the command line arguments for the head and tail files,
           along with the address of the webserver which some tests require.
 
           On a remote system, this is overloaded to resolve quoting issues over a secondary command line.
@@ -406,210 +437,181 @@ class XPCShellTestThread(Thread):
         # setting up every test with its own plugins directory.
         if not self.pluginsPath:
             self.pluginsPath = os.path.join(self.appPath, 'plugins')
 
         self.pluginsDir = self.setupPluginsDir()
         if self.pluginsDir:
             self.xpcsCmd.extend(['-p', self.pluginsDir])
 
-    def cleanupDir(self, directory, name, xunit_result):
+    def cleanupDir(self, directory, name):
         if not os.path.exists(directory):
             return
 
         TRY_LIMIT = 25 # up to TRY_LIMIT attempts (one every second), because
                        # the Windows filesystem is slow to react to the changes
         try_count = 0
         while try_count < TRY_LIMIT:
             try:
                 self.removeDir(directory)
             except OSError:
-                self.log.info("TEST-INFO | Failed to remove directory: %s. Waiting." % directory)
+                self.log.info("Failed to remove directory: %s. Waiting." % directory)
                 # We suspect the filesystem may still be making changes. Wait a
                 # little bit and try again.
                 time.sleep(1)
                 try_count += 1
             else:
                 # removed fine
                 return
 
         # we try cleaning up again later at the end of the run
         self.cleanup_dir_list.append(directory)
 
-    def clean_temp_dirs(self, name, stdout):
+    def clean_temp_dirs(self, name):
         # We don't want to delete the profile when running check-interactive
         # or check-one.
         if self.profileDir and not self.interactive and not self.singleFile:
-            self.cleanupDir(self.profileDir, name, self.xunit_result)
+            self.cleanupDir(self.profileDir, name)
 
-        self.cleanupDir(self.tempDir, name, self.xunit_result)
+        self.cleanupDir(self.tempDir, name)
 
         if self.pluginsDir:
-            self.cleanupDir(self.pluginsDir, name, self.xunit_result)
-
-    def message_from_line(self, line):
-        """ Given a line of raw output, convert to a string message. """
-        if isinstance(line, basestring):
-            # This function has received unstructured output.
-            if line:
-                if 'TEST-UNEXPECTED-' in line:
-                    self.has_failure_output = True
-            return line
-
-        msg = ['%s: ' % line['process'] if 'process' in line else '']
-
-        # Each call to the logger in head.js either specified '_message'
-        # or both 'source_file' and 'diagnostic'. If either of these are
-        # missing, they ended up being undefined as a result of the way
-        # the test was run.
-        if '_message' in line:
-            msg.append(line['_message'])
-            if 'diagnostic' in line:
-                msg.append('\nDiagnostic: %s' % line['diagnostic'])
-        else:
-            msg.append('%s | %s | %s' % (ACTION_STRINGS[line['action']],
-                                         line.get('source_file', 'undefined'),
-                                         line.get('diagnostic', 'undefined')))
-
-        msg.append('\n%s' % line['stack'] if 'stack' in line else '')
-        return ''.join(msg)
+            self.cleanupDir(self.pluginsDir, name)
 
     def parse_output(self, output):
         """Parses process output for structured messages and saves output as it is
         read. Sets self.has_failure_output in case of evidence of a failure"""
         for line_string in output.splitlines():
             self.process_line(line_string)
 
         if self.saw_proc_start and not self.saw_proc_end:
             self.has_failure_output = True
 
-    def report_message(self, line):
-        """ Reports a message to a consumer, both as a strucutured and
-        human-readable log message. """
+    def log_line(self, line):
+        """Log a line of output (either a parser json object or text output from
+        the test process"""
+        if isinstance(line, basestring):
+            line = cleanup_encoding(line)
+            self.log.process_output(self.proc_ident,
+                                    line,
+                                    command=self.complete_command)
+        else:
+            if 'message' in line:
+                line['message'] = cleanup_encoding(line['message'])
+            if 'xpcshell_process' in line:
+                line['thread'] =  ' '.join([current_thread().name, line['xpcshell_process']])
+            else:
+                line['thread'] = current_thread().name
+            self.log.log_raw(line)
 
-        message = cleanup_encoding(self.message_from_line(line))
-        if message.endswith('\n'):
-            # A new line is always added by head.js to delimit messages,
-            # however consumers will want to supply their own.
-            message = message[:-1]
+    def log_full_output(self, output):
+        """Log output any buffered output from the test process"""
+        if not output:
+            return
+        self.log.info(">>>>>>>")
+        for line in output:
+            self.log_line(line)
+        self.log.info("<<<<<<<")
 
-        if self.on_message:
-            self.on_message(line, message)
+    def report_message(self, message):
+        """Stores or logs a json log message in mozlog.structured
+        format."""
+        if self.verbose:
+            self.log_line(message)
         else:
-            self.output_lines.append(message)
+            # Tests eligible to retry will never dump their buffered output.
+            if not self.retry:
+                self.output_lines.append(message)
 
     def process_line(self, line_string):
         """ Parses a single line of output, determining its significance and
         reporting a message.
         """
+        if not line_string.strip():
+            return
+
         try:
             line_object = json.loads(line_string)
             if not isinstance(line_object, dict):
                 self.report_message(line_string)
                 return
         except ValueError:
             self.report_message(line_string)
             return
 
-        if 'action' not in line_object:
-            # In case a test outputs something that happens to be valid
-            # JSON.
+        if ('action' not in line_object or
+            line_object['action'] not in EXPECTED_LOG_ACTIONS):
+            # The test process output JSON.
             self.report_message(line_string)
             return
 
         action = line_object['action']
+
+        self.has_failure_output = (self.has_failure_output or
+                                   'expected' in line_object or
+                                   action == 'log' and line_object['level'] == 'ERROR')
+
         self.report_message(line_object)
 
-        if action in FAILURE_ACTIONS:
-            self.has_failure_output = True
-        elif action == 'child_test_start':
-            self.saw_proc_start = True
-        elif action == 'child_test_end':
+        if action == 'log' and line_object['message'] == 'CHILD-TEST-STARTED':
+             self.saw_proc_start = True
+        elif action == 'log' and line_object['message'] == 'CHILD-TEST-COMPLETED':
             self.saw_proc_end = True
 
-    def log_output(self, output):
-        """Prints given output line-by-line to avoid overflowing buffers."""
-        self.log.info(">>>>>>>")
-        if output:
-            if isinstance(output, basestring):
-                output = output.splitlines()
-            for part in output:
-                # For multi-line output, such as a stack trace
-                for line in part.splitlines():
-                    try:
-                        line = line.decode('utf-8')
-                    except UnicodeDecodeError:
-                        self.log.info("TEST-INFO | %s | Detected non UTF-8 output."\
-                                      " Please modify the test to only print UTF-8." %
-                                      self.test_object['name'])
-                        # add '?' instead of funky bytes
-                        line = line.decode('utf-8', 'replace')
-                    self.log.info(line)
-        self.log.info("<<<<<<<")
-
     def run_test(self):
         """Run an individual xpcshell test."""
         global gotSIGINT
 
-        name = self.test_object['path']
-
-        self.xunit_result = {'name': self.test_object['name'], 'classname': 'xpcshell'}
-
-        # The xUnit package is defined as the path component between the root
-        # dir and the test with path characters replaced with '.' (using Java
-        # class notation).
-        if self.tests_root_dir is not None:
-            self.tests_root_dir = os.path.normpath(self.tests_root_dir)
-            if os.path.normpath(self.test_object['here']).find(self.tests_root_dir) != 0:
-                raise Exception('tests_root_dir is not a parent path of %s' %
-                    self.test_object['here'])
-            relpath = self.test_object['here'][len(self.tests_root_dir):].lstrip('/\\')
-            self.xunit_result['classname'] = relpath.replace('/', '.').replace('\\', '.')
+        name = self.test_object['id']
+        path = self.test_object['path']
 
         # Check for skipped tests
         if 'disabled' in self.test_object:
-            self.log.info('TEST-INFO | skipping %s | %s' %
-                (name, self.test_object['disabled']))
+            message = self.test_object['disabled']
+            if not message:
+                message = 'disabled from xpcshell manifest'
+            self.log.test_start(name)
+            self.log.test_end(name, 'SKIP', message=message)
 
-            self.xunit_result['skipped'] = True
             self.retry = False
-
             self.keep_going = True
             return
 
         # Check for known-fail tests
-        expected = self.test_object['expected'] == 'pass'
+        expect_pass = self.test_object['expected'] == 'pass'
 
         # By default self.appPath will equal the gre dir. If specified in the
         # xpcshell.ini file, set a different app dir for this test.
         if self.app_dir_key and self.app_dir_key in self.test_object:
             rel_app_dir = self.test_object[self.app_dir_key]
             rel_app_dir = os.path.join(self.xrePath, rel_app_dir)
             self.appPath = os.path.abspath(rel_app_dir)
         else:
             self.appPath = None
 
-        test_dir = os.path.dirname(name)
+        test_dir = os.path.dirname(path)
         self.buildXpcsCmd(test_dir)
         head_files, tail_files = self.getHeadAndTailFiles(self.test_object)
         cmdH = self.buildCmdHead(head_files, tail_files, self.xpcsCmd)
 
         # Create a profile and a temp dir that the JS harness can stick
         # a profile and temporary data in
         self.profileDir = self.setupProfileDir()
         self.tempDir = self.setupTempDir()
 
         # The test file will have to be loaded after the head files.
-        cmdT = self.buildCmdTestFile(name)
+        cmdT = self.buildCmdTestFile(path)
 
         args = self.xpcsRunArgs[:]
         if 'debug' in self.test_object:
             args.insert(0, '-d')
 
-        completeCmd = cmdH + cmdT + args
+        # The test name to log
+        cmdI = ['-e', 'const _TEST_NAME = "%s"' % name]
+        self.complete_command = cmdH + cmdT + cmdI + args
 
         if self.test_object.get('dmd') == 'true':
             if sys.platform.startswith('linux'):
                 preloadEnvVar = 'LD_PRELOAD'
                 libdmd = os.path.join(self.xrePath, 'libdmd.so')
             elif sys.platform == 'osx' or sys.platform == 'darwin':
                 preloadEnvVar = 'DYLD_INSERT_LIBRARIES'
                 # self.xrePath is <prefix>/Contents/Resources.
@@ -620,188 +622,133 @@ class XPCShellTestThread(Thread):
                 preloadEnvVar = 'MOZ_REPLACE_MALLOC_LIB'
                 libdmd = os.path.join(self.xrePath, 'dmd.dll')
 
             self.env['PYTHON'] = sys.executable
             self.env['BREAKPAD_SYMBOLS_PATH'] = self.symbolsPath
             self.env['DMD_PRELOAD_VAR'] = preloadEnvVar
             self.env['DMD_PRELOAD_VALUE'] = libdmd
 
-        testTimeoutInterval = HARNESS_TIMEOUT
+        testTimeoutInterval = self.harness_timeout
         # Allow a test to request a multiple of the timeout if it is expected to take long
         if 'requesttimeoutfactor' in self.test_object:
             testTimeoutInterval *= int(self.test_object['requesttimeoutfactor'])
 
         testTimer = None
         if not self.interactive and not self.debuggerInfo:
-            testTimer = Timer(testTimeoutInterval, lambda: self.testTimeout(name, proc))
+            testTimer = Timer(testTimeoutInterval, lambda: self.testTimeout(proc))
             testTimer.start()
 
         proc = None
-        stdout = None
-        stderr = None
+        process_output = None
 
         try:
-            self.log.info("TEST-INFO | %s | running test ..." % name)
+            self.log.test_start(name)
             if self.verbose:
-                self.logCommand(name, completeCmd, test_dir)
+                self.logCommand(name, self.complete_command, test_dir)
 
-            startTime = time.time()
-            proc = self.launchProcess(completeCmd,
+            proc = self.launchProcess(self.complete_command,
                 stdout=self.pStdout, stderr=self.pStderr, env=self.env, cwd=test_dir, timeout=testTimeoutInterval)
 
+            if hasattr(proc, "pid"):
+                self.proc_ident = proc.pid
+            else:
+                # On mobile, "proc" is just a file.
+                self.proc_ident = name
+
             if self.interactive:
-                self.log.info("TEST-INFO | %s | Process ID: %d" % (name, proc.pid))
+                self.log.info("%s | Process ID: %d" % (name, self.proc_ident))
 
-            stdout, stderr = self.communicate(proc)
+            # Communicate returns a tuple of (stdout, stderr), however we always
+            # redirect stderr to stdout, so the second element is ignored.
+            process_output, _ = self.communicate(proc)
 
             if self.interactive:
                 # Not sure what else to do here...
                 self.keep_going = True
                 return
 
             if testTimer:
                 testTimer.cancel()
 
-            if stdout:
-                self.parse_output(stdout)
-            result = not (self.has_failure_output or
-                          (self.getReturnCode(proc) != 0))
+            if process_output:
+                # For the remote case, stdout is not yet depleted, so we parse
+                # it here all at once.
+                self.parse_output(process_output)
+
+            return_code = self.getReturnCode(proc)
+            passed = (not self.has_failure_output) and (return_code == 0)
 
-            if result != expected:
+            status = 'PASS' if passed else 'FAIL'
+            expected = 'PASS' if expect_pass else 'FAIL'
+            message = 'xpcshell return code: %d' % return_code
+
+            if self.timedout:
+                return
+
+            if status != expected:
                 if self.retry:
-                    self.clean_temp_dirs(name, stdout)
+                    self.log.test_end(name, status, expected=status,
+                                      message="Test failed or timed out, will retry")
+                    self.clean_temp_dirs(path)
                     return
 
-                failureType = "TEST-UNEXPECTED-%s" % ("FAIL" if expected else "PASS")
-                message = "%s | %s | test failed (with xpcshell return code: %d)" % (
-                              failureType, name, self.getReturnCode(proc))
-                if self.output_lines:
-                    message += ", see following log:"
-
-                with LOG_MUTEX:
-                    self.log.error(message)
-                    self.log_output(self.output_lines)
+                self.log.test_end(name, status, expected=expected, message=message)
+                self.log_full_output(self.output_lines)
 
                 self.failCount += 1
-                self.xunit_result["passed"] = False
-
-                self.xunit_result["failure"] = {
-                  "type": failureType,
-                  "message": message,
-                  "text": stdout
-                }
 
                 if self.failureManifest:
                     with open(self.failureManifest, 'a') as f:
                         f.write('[%s]\n' % self.test_object['path'])
                         for k, v in self.test_object.items():
                             f.write('%s = %s\n' % (k, v))
 
             else:
-                now = time.time()
-                timeTaken = (now - startTime) * 1000
-                self.xunit_result["time"] = now - startTime
+                self.log.test_end(name, status, expected=expected, message=message)
+                if self.verbose:
+                    self.log_full_output(self.output_lines)
 
-                with LOG_MUTEX:
-                    self.log.info("TEST-%s | %s | test passed (time: %.3fms)" % ("PASS" if expected else "KNOWN-FAIL", name, timeTaken))
-                    if self.verbose:
-                        self.log_output(self.output_lines)
-
-                self.xunit_result["passed"] = True
                 self.retry = False
 
-                if expected:
+                if expect_pass:
                     self.passCount = 1
                 else:
                     self.todoCount = 1
-                    self.xunit_result["todo"] = True
 
             if self.checkForCrashes(self.tempDir, self.symbolsPath, test_name=name):
                 if self.retry:
-                    self.clean_temp_dirs(name, stdout)
-                    return
-
-                message = "PROCESS-CRASH | %s | application crashed" % name
-                self.failCount = 1
-                self.xunit_result["passed"] = False
-                self.xunit_result["failure"] = {
-                    "type": "PROCESS-CRASH",
-                    "message": message,
-                    "text": stdout
-                }
-
-            if self.logfiles and stdout:
-                self.createLogFile(name, stdout)
-
-        finally:
-            # We can sometimes get here before the process has terminated, which would
-            # cause removeDir() to fail - so check for the process & kill it it needed.
-            if proc and self.poll(proc) is None:
-                self.kill(proc)
-
-                if self.retry:
-                    self.clean_temp_dirs(name, stdout)
+                    self.clean_temp_dirs(path)
                     return
 
-                with LOG_MUTEX:
-                    message = "TEST-UNEXPECTED-FAIL | %s | Process still running after test!" % name
-                    self.log.error(message)
-                    self.log_output(self.output_lines)
+                self.failCount = 1
 
-                self.failCount = 1
-                self.xunit_result["passed"] = False
-                self.xunit_result["failure"] = {
-                  "type": "TEST-UNEXPECTED-FAIL",
-                  "message": message,
-                  "text": stdout
-                }
+            if self.logfiles and process_output:
+                self.createLogFile(name, process_output)
 
-            self.clean_temp_dirs(name, stdout)
+        finally:
+            self.postCheck(proc)
+            self.clean_temp_dirs(path)
 
         if gotSIGINT:
-            self.xunit_result["passed"] = False
-            self.xunit_result["time"] = "0.0"
-            self.xunit_result["failure"] = {
-                "type": "SIGINT",
-                "message": "Received SIGINT",
-                "text": "Received SIGINT (control-C) during test execution."
-            }
-
-            self.log.error("TEST-UNEXPECTED-FAIL | Received SIGINT (control-C) during test execution")
+            self.log.error("Received SIGINT (control-C) during test execution")
             if self.keep_going:
                 gotSIGINT = False
             else:
                 self.keep_going = False
                 return
 
         self.keep_going = True
 
 class XPCShellTests(object):
 
-    log = getGlobalLog()
-
     def __init__(self, log=None):
-        """ Init logging and node status """
-        if log:
-            resetGlobalLog(log)
-
-        # Each method of the underlying logger must acquire the log
-        # mutex before writing to stdout.
-        log_funs = ['debug', 'info', 'warning', 'error', 'critical', 'log']
-        for fun_name in log_funs:
-            unwrapped = getattr(self.log, fun_name, None)
-            if unwrapped:
-                def wrap(fn):
-                    def wrapped(*args, **kwargs):
-                        with LOG_MUTEX:
-                            fn(*args, **kwargs)
-                    return wrapped
-                setattr(self.log, fun_name, wrap(unwrapped))
-
+        """ Initializes node status and logger. """
+        self.log = log
+        self.harness_timeout = HARNESS_TIMEOUT
         self.nodeProc = {}
 
     def buildTestList(self):
         """
           read the xpcshell.ini manifest and set self.alltests to be
           an array of test objects.
 
           if we are chunking tests, it will be done here as well
@@ -834,17 +781,17 @@ class XPCShellTests(object):
           self.alltests based on thisChunk, so we only run a subset.
         """
         totalTests = len(self.alltests)
         testsPerChunk = math.ceil(totalTests / float(self.totalChunks))
         start = int(round((self.thisChunk-1) * testsPerChunk))
         end = int(start + testsPerChunk)
         if end > totalTests:
             end = totalTests
-        self.log.info("Running tests %d-%d/%d", start+1, end, totalTests)
+        self.log.info("Running tests %d-%d/%d" % (start + 1, end, totalTests))
         self.alltests = self.alltests[start:end]
 
     def setAbsPath(self):
         """
           Set the absolute path for xpcshell, httpdjspath and xrepath.
           These 3 variables depend on input from the command line and we need to allow for absolute paths.
           This function is overloaded for a remote solution as os.path* won't work remotely.
         """
@@ -913,19 +860,19 @@ class XPCShellTests(object):
             else:
                 self.env["LD_LIBRARY_PATH"] = ":".join([self.xrePath, self.env["LD_LIBRARY_PATH"]])
 
         if "asan" in self.mozInfo and self.mozInfo["asan"]:
             # ASan symbolizer support
             llvmsym = os.path.join(self.xrePath, "llvm-symbolizer")
             if os.path.isfile(llvmsym):
                 self.env["ASAN_SYMBOLIZER_PATH"] = llvmsym
-                self.log.info("INFO | runxpcshelltests.py | ASan using symbolizer at %s", llvmsym)
+                self.log.info("runxpcshelltests.py | ASan using symbolizer at %s" % llvmsym)
             else:
-                self.log.info("TEST-UNEXPECTED-FAIL | runxpcshelltests.py | Failed to find ASan symbolizer at %s", llvmsym)
+                self.log.error("TEST-UNEXPECTED-FAIL | runxpcshelltests.py | Failed to find ASan symbolizer at %s" % llvmsym)
 
         return self.env
 
     def getPipes(self):
         """
           Determine the value of the stdout and stderr for the test.
           Return value is a list (pStdout, pStderr).
         """
@@ -1021,189 +968,49 @@ class XPCShellTests(object):
     def shutdownNode(self):
         """
           Shut down our node process, if it exists
         """
         for name, proc in self.nodeProc.iteritems():
             self.log.info('Node %s server shutting down ...' % name)
             proc.terminate()
 
-    def writeXunitResults(self, results, name=None, filename=None, fh=None):
-        """
-          Write Xunit XML from results.
-
-          The function receives an iterable of results dicts. Each dict must have
-          the following keys:
-
-            classname - The "class" name of the test.
-            name - The simple name of the test.
-
-          In addition, it must have one of the following saying how the test
-          executed:
-
-            passed - Boolean indicating whether the test passed. False if it
-              failed.
-            skipped - True if the test was skipped.
-
-          The following keys are optional:
-
-            time - Execution time of the test in decimal seconds.
-            failure - Dict describing test failure. Requires keys:
-              type - String type of failure.
-              message - String describing basic failure.
-              text - Verbose string describing failure.
-
-          Arguments:
-
-          |name|, Name of the test suite. Many tools expect Java class dot notation
-            e.g. dom.simple.foo. A directory with '/' converted to '.' is a good
-            choice.
-          |fh|, File handle to write XML to.
-          |filename|, File name to write XML to.
-          |results|, Iterable of tuples describing the results.
-        """
-        if filename is None and fh is None:
-            raise Exception("One of filename or fh must be defined.")
-
-        if name is None:
-            name = "xpcshell"
-        else:
-            assert isinstance(name, basestring)
-
-        if filename is not None:
-            fh = open(filename, 'wb')
-
-        doc = xml.dom.minidom.Document()
-        testsuite = doc.createElement("testsuite")
-        testsuite.setAttribute("name", name)
-        doc.appendChild(testsuite)
-
-        total = 0
-        passed = 0
-        failed = 0
-        skipped = 0
-
-        for result in results:
-            total += 1
-
-            if result.get("skipped", None):
-                skipped += 1
-            elif result["passed"]:
-                passed += 1
-            else:
-                failed += 1
-
-            testcase = doc.createElement("testcase")
-            testcase.setAttribute("classname", result["classname"])
-            testcase.setAttribute("name", result["name"])
-
-            if "time" in result:
-                testcase.setAttribute("time", str(result["time"]))
-            else:
-                # It appears most tools expect the time attribute to be present.
-                testcase.setAttribute("time", "0")
-
-            if "failure" in result:
-                failure = doc.createElement("failure")
-                failure.setAttribute("type", str(result["failure"]["type"]))
-                failure.setAttribute("message", result["failure"]["message"])
-
-                # Lossy translation but required to not break CDATA. Also, text could
-                # be None and Python 2.5's minidom doesn't accept None. Later versions
-                # do, however.
-                cdata = result["failure"]["text"]
-                if not isinstance(cdata, str):
-                    cdata = ""
-
-                cdata = cdata.replace("]]>", "]] >")
-                text = doc.createCDATASection(cdata)
-                failure.appendChild(text)
-                testcase.appendChild(failure)
-
-            if result.get("skipped", None):
-                e = doc.createElement("skipped")
-                testcase.appendChild(e)
-
-            testsuite.appendChild(testcase)
-
-        testsuite.setAttribute("tests", str(total))
-        testsuite.setAttribute("failures", str(failed))
-        testsuite.setAttribute("skip", str(skipped))
-
-        doc.writexml(fh, addindent="  ", newl="\n", encoding="utf-8")
-
-    def post_to_autolog(self, results, name):
-        from moztest.results import TestContext, TestResult, TestResultCollection
-        from moztest.output.autolog import AutologOutput
-
-        context = TestContext(
-            testgroup='b2g xpcshell testsuite',
-            operating_system='android',
-            arch='emulator',
-            harness='xpcshell',
-            hostname=socket.gethostname(),
-            tree='b2g',
-            buildtype='opt',
-            )
-
-        collection = TestResultCollection('b2g emulator testsuite')
-
-        for result in results:
-            duration = result.get('time', 0)
-
-            if 'skipped' in result:
-                outcome = 'SKIPPED'
-            elif 'todo' in result:
-                outcome = 'KNOWN-FAIL'
-            elif result['passed']:
-                outcome = 'PASS'
-            else:
-                outcome = 'UNEXPECTED-FAIL'
-
-            output = None
-            if 'failure' in result:
-                output = result['failure']['text']
-
-            t = TestResult(name=result['name'], test_class=name,
-                           time_start=0, context=context)
-            t.finish(result=outcome, time_end=duration, output=output)
-
-            collection.append(t)
-            collection.time_taken += duration
-
-        out = AutologOutput()
-        out.post(out.make_testgroups(collection))
-
     def buildXpcsRunArgs(self):
         """
           Add arguments to run the test or make it interactive.
         """
         if self.interactive:
             self.xpcsRunArgs = [
             '-e', 'print("To start the test, type |_execute_test();|.");',
             '-i']
         else:
             self.xpcsRunArgs = ['-e', '_execute_test(); quit(0);']
 
     def addTestResults(self, test):
         self.passCount += test.passCount
         self.failCount += test.failCount
         self.todoCount += test.todoCount
-        self.xunitResults.append(test.xunit_result)
+
+    def makeTestId(self, test_object):
+        """Calculate an identifier for a test based on its path or a combination of
+        its path and the source manifest."""
+        path = replaceBackSlashes(test_object['path']);
+        if 'dupe-manifest' in test_object and 'ancestor-manifest' in test_object:
+            return '%s:%s' % (os.path.basename(test_object['ancestor-manifest']), path)
+        return path
 
     def runTests(self, xpcshell, xrePath=None, appPath=None, symbolsPath=None,
                  manifest=None, testdirs=None, testPath=None, mobileArgs=None,
                  interactive=False, verbose=False, keepGoing=False, logfiles=True,
                  thisChunk=1, totalChunks=1, debugger=None,
                  debuggerArgs=None, debuggerInteractive=False,
                  profileName=None, mozInfo=None, sequential=False, shuffle=False,
-                 testsRootDir=None, xunitFilename=None, xunitName=None,
-                 testingModulesDir=None, autolog=False, pluginsPath=None,
+                 testsRootDir=None, testingModulesDir=None, pluginsPath=None,
                  testClass=XPCShellTestThread, failureManifest=None,
-                 on_message=None, **otherOptions):
+                 log=None, stream=None, **otherOptions):
         """Run xpcshell tests.
 
         |xpcshell|, is the xpcshell executable to use to run the tests.
         |xrePath|, if provided, is the path to the XRE to use.
         |appPath|, if provided, is the path to an application directory.
         |symbolsPath|, if provided is the path to a directory containing
           breakpad symbols for processing crashes in tests.
         |manifest|, if provided, is a file containing a list of
@@ -1225,41 +1032,26 @@ class XPCShellTests(object):
         |debuggerInteractive|, if set, allows the debugger to be run in interactive
           mode.
         |profileName|, if set, specifies the name of the application for the profile
           directory if running only a subset of tests.
         |mozInfo|, if set, specifies specifies build configuration information, either as a filename containing JSON, or a dict.
         |shuffle|, if True, execute tests in random order.
         |testsRootDir|, absolute path to root directory of all tests. This is used
           by xUnit generation to determine the package name of the tests.
-        |xunitFilename|, if set, specifies the filename to which to write xUnit XML
-          results.
-        |xunitName|, if outputting an xUnit XML file, the str value to use for the
-          testsuite name.
         |testingModulesDir|, if provided, specifies where JS modules reside.
           xpcshell will register a resource handler mapping this path.
         |otherOptions| may be present for the convenience of subclasses
         """
 
         global gotSIGINT
 
         if testdirs is None:
             testdirs = []
 
-        if xunitFilename is not None or xunitName is not None:
-            if not isinstance(testsRootDir, basestring):
-                raise Exception("testsRootDir must be a str when outputting xUnit.")
-
-            if not os.path.isabs(testsRootDir):
-                testsRootDir = os.path.abspath(testsRootDir)
-
-            if not os.path.exists(testsRootDir):
-                raise Exception("testsRootDir path does not exists: %s" %
-                        testsRootDir)
-
         # Try to guess modules directory.
         # This somewhat grotesque hack allows the buildbot machines to find the
         # modules directory without having to configure the buildbot hosts. This
         # code path should never be executed in local runs because the build system
         # should always set this argument.
         if not testingModulesDir:
             ourDir = os.path.dirname(__file__)
             possible = os.path.join(ourDir, os.path.pardir, 'modules')
@@ -1295,17 +1087,16 @@ class XPCShellTests(object):
         self.symbolsPath = symbolsPath
         self.manifest = manifest
         self.testdirs = testdirs
         self.testPath = testPath
         self.interactive = interactive
         self.verbose = verbose
         self.keepGoing = keepGoing
         self.logfiles = logfiles
-        self.on_message = on_message
         self.totalChunks = totalChunks
         self.thisChunk = thisChunk
         self.profileName = profileName or "xpcshell"
         self.mozInfo = mozInfo
         self.testingModulesDir = testingModulesDir
         self.pluginsPath = pluginsPath
         self.sequential = sequential
 
@@ -1363,17 +1154,16 @@ class XPCShellTests(object):
 
         self.buildTestList()
         if self.singleFile:
             self.sequential = True
 
         if shuffle:
             random.shuffle(self.alltests)
 
-        self.xunitResults = []
         self.cleanup_dir_list = []
         self.try_again_list = []
 
         kwargs = {
             'appPath': self.appPath,
             'xrePath': self.xrePath,
             'testingModulesDir': self.testingModulesDir,
             'debuggerInfo': self.debuggerInfo,
@@ -1385,17 +1175,17 @@ class XPCShellTests(object):
             'profileName': self.profileName,
             'singleFile': self.singleFile,
             'env': self.env, # making a copy of this in the testthreads
             'symbolsPath': self.symbolsPath,
             'logfiles': self.logfiles,
             'xpcshell': self.xpcshell,
             'xpcsRunArgs': self.xpcsRunArgs,
             'failureManifest': failureManifest,
-            'on_message': self.on_message,
+            'harness_timeout': self.harness_timeout,
         }
 
         if self.sequential:
             # Allow user to kill hung xpcshell subprocess with SIGINT
             # when we are only running tests sequentially.
             signal.signal(signal.SIGINT, markGotSIGINT)
 
         if self.debuggerInfo:
@@ -1406,46 +1196,54 @@ class XPCShellTests(object):
             if self.debuggerInfo.interactive:
                 signal.signal(signal.SIGINT, lambda signum, frame: None)
 
         # create a queue of all tests that will run
         tests_queue = deque()
         # also a list for the tests that need to be run sequentially
         sequential_tests = []
         for test_object in self.alltests:
-            name = test_object['path']
-            if self.singleFile and not name.endswith(self.singleFile):
+            # Test identifiers are provided for the convenience of logging. These
+            # start as path names but are rewritten in case tests from the same path
+            # are re-run.
+
+            path = test_object['path']
+            test_object['id'] = self.makeTestId(test_object)
+
+            if self.singleFile and not path.endswith(self.singleFile):
                 continue
 
-            if self.testPath and name.find(self.testPath) == -1:
+            if self.testPath and path.find(self.testPath) == -1:
                 continue
 
             self.testCount += 1
 
             test = testClass(test_object, self.event, self.cleanup_dir_list,
                     tests_root_dir=testsRootDir, app_dir_key=appDirKey,
                     interactive=interactive, verbose=verbose, pStdout=pStdout,
                     pStderr=pStderr, keep_going=keepGoing, log=self.log,
                     mobileArgs=mobileArgs, **kwargs)
             if 'run-sequentially' in test_object or self.sequential:
                 sequential_tests.append(test)
             else:
                 tests_queue.append(test)
 
         if self.sequential:
-            self.log.info("INFO | Running tests sequentially.")
+            self.log.info("Running tests sequentially.")
         else:
-            self.log.info("INFO | Using at most %d threads." % NUM_THREADS)
+            self.log.info("Using at most %d threads." % NUM_THREADS)
 
         # keep a set of NUM_THREADS running tests and start running the
         # tests in the queue at most NUM_THREADS at a time
         running_tests = set()
         keep_going = True
         exceptions = []
         tracebacks = []
+        self.log.suite_start([t['id'] for t in self.alltests])
+
         while tests_queue or running_tests:
             # if we're not supposed to continue and all of the running tests
             # are done, stop
             if not keep_going and not running_tests:
                 break
 
             # if there's room to run more tests, start running them
             while keep_going and tests_queue and (len(running_tests) < NUM_THREADS):
@@ -1531,60 +1329,51 @@ class XPCShellTests(object):
         # Clean up any slacker directories that might be lying around
         # Some might fail because of windows taking too long to unlock them.
         # We don't do anything if this fails because the test slaves will have
         # their $TEMP dirs cleaned up on reboot anyway.
         for directory in self.cleanup_dir_list:
             try:
                 shutil.rmtree(directory)
             except:
-                self.log.info("INFO | %s could not be cleaned up." % directory)
+                self.log.info("%s could not be cleaned up." % directory)
 
         if exceptions:
-            self.log.info("INFO | Following exceptions were raised:")
+            self.log.info("Following exceptions were raised:")
             for t in tracebacks:
                 self.log.error(t)
             raise exceptions[0]
 
         if self.testCount == 0:
-            self.log.error("TEST-UNEXPECTED-FAIL | runxpcshelltests.py | No tests run. Did you pass an invalid --test-path?")
+            self.log.error("No tests run. Did you pass an invalid --test-path?")
             self.failCount = 1
 
         self.log.info("INFO | Result summary:")
         self.log.info("INFO | Passed: %d" % self.passCount)
         self.log.info("INFO | Failed: %d" % self.failCount)
         self.log.info("INFO | Todo: %d" % self.todoCount)
         self.log.info("INFO | Retried: %d" % len(self.try_again_list))
 
-        if autolog:
-            self.post_to_autolog(self.xunitResults, xunitName)
-
-        if xunitFilename is not None:
-            self.writeXunitResults(filename=xunitFilename, results=self.xunitResults,
-                                   name=xunitName)
-
         if gotSIGINT and not keepGoing:
             self.log.error("TEST-UNEXPECTED-FAIL | Received SIGINT (control-C), so stopped run. " \
                            "(Use --keep-going to keep running tests after killing one with SIGINT)")
             return False
 
+        self.log.suite_end()
         return self.failCount == 0
 
 class XPCShellOptions(OptionParser):
     def __init__(self):
         """Process command line arguments and call runTests() to do the real work."""
         OptionParser.__init__(self)
 
         addCommonOptions(self)
         self.add_option("--app-path",
                         type="string", dest="appPath", default=None,
                         help="application directory (as opposed to XRE directory)")
-        self.add_option("--autolog",
-                        action="store_true", dest="autolog", default=False,
-                        help="post to autolog")
         self.add_option("--interactive",
                         action="store_true", dest="interactive", default=False,
                         help="don't automatically run tests, drop to an xpcshell prompt")
         self.add_option("--verbose",
                         action="store_true", dest="verbose", default=False,
                         help="always print stdout and stderr from tests")
         self.add_option("--keep-going",
                         action="store_true", dest="keepGoing", default=False,
@@ -1625,38 +1414,38 @@ class XPCShellOptions(OptionParser):
                         type = "string", dest="profileName", default=None,
                         help="name of application profile being tested")
         self.add_option("--build-info-json",
                         type = "string", dest="mozInfo", default=None,
                         help="path to a mozinfo.json including information about the build configuration. defaults to looking for mozinfo.json next to the script.")
         self.add_option("--shuffle",
                         action="store_true", dest="shuffle", default=False,
                         help="Execute tests in random order")
-        self.add_option("--xunit-file", dest="xunitFilename",
-                        help="path to file where xUnit results will be written.")
-        self.add_option("--xunit-suite-name", dest="xunitName",
-                        help="name to record for this xUnit test suite. Many "
-                             "tools expect Java class notation, e.g. "
-                             "dom.basic.foo")
         self.add_option("--failure-manifest", dest="failureManifest",
                         action="store",
                         help="path to file where failure manifest will be written.")
 
 def main():
     parser = XPCShellOptions()
+    structured.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
 
+
+    log = structured.commandline.setup_logging("XPCShell",
+                                               options,
+                                               {"tbpl": sys.stdout})
+
     if len(args) < 2 and options.manifest is None or \
        (len(args) < 1 and options.manifest is not None):
         print >>sys.stderr, """Usage: %s <path to xpcshell> <test dirs>
               or: %s --manifest=test.manifest <path to xpcshell>""" % (sys.argv[0],
                                                               sys.argv[0])
         sys.exit(1)
 
-    xpcsh = XPCShellTests()
+    xpcsh = XPCShellTests(log)
 
     if options.interactive and not options.testPath:
         print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
         sys.exit(1)
 
     if not xpcsh.runTests(args[0], testdirs=args[1:], **options.__dict__):
         sys.exit(1)
 
--- a/testing/xpcshell/selftest.py
+++ b/testing/xpcshell/selftest.py
@@ -4,18 +4,18 @@
 # http://creativecommons.org/publicdomain/zero/1.0/
 #
 
 from __future__ import with_statement
 import sys, os, unittest, tempfile, shutil
 import mozinfo
 
 from StringIO import StringIO
-from xml.etree.ElementTree import ElementTree
 
+from mozlog import structured
 from mozbuild.base import MozbuildObject
 os.environ.pop('MOZ_OBJDIR', None)
 build_obj = MozbuildObject.from_environment()
 
 from runxpcshelltests import XPCShellTests
 
 mozinfo.find_and_update_from_json()
 
@@ -24,16 +24,19 @@ objdir = build_obj.topobjdir.encode("utf
 if mozinfo.isMac:
   from buildconfig import substs
   xpcshellBin = os.path.join(objdir, "dist", substs['MOZ_MACBUNDLE_NAME'], "Contents", "MacOS", "xpcshell")
 else:
   xpcshellBin = os.path.join(objdir, "dist", "bin", "xpcshell")
   if sys.platform == "win32":
     xpcshellBin += ".exe"
 
+TEST_PASS_STRING = "TEST-PASS"
+TEST_FAIL_STRING = "TEST-UNEXPECTED-FAIL"
+
 SIMPLE_PASSING_TEST = "function run_test() { do_check_true(true); }"
 SIMPLE_FAILING_TEST = "function run_test() { do_check_true(false); }"
 
 ADD_TEST_SIMPLE = '''
 function run_test() { run_next_test(); }
 
 add_test(function test_simple() {
   do_check_true(true);
@@ -69,23 +72,40 @@ add_test(function test_child_simple () {
 '''
 
 CHILD_TEST_HANG = '''
 function run_test () { run_next_test(); }
 
 add_test(function test_child_simple () {
   do_test_pending("hang test");
   do_load_child_test_harness();
-  sendCommand("_log('child_test_start', {_message: 'CHILD-TEST-STARTED'}); " +
+  sendCommand("_testLogger.info('CHILD-TEST-STARTED'); " +
               + "const _TEST_FILE=['test_pass.js']; _execute_test(); ",
               do_test_finished);
   run_next_test();
 });
 '''
 
+SIMPLE_LOOPING_TEST = '''
+function run_test () { run_next_test(); }
+
+add_test(function test_loop () {
+  do_test_pending()
+});
+'''
+
+PASSING_TEST_UNICODE = '''
+function run_test () { run_next_test(); }
+
+add_test(function test_unicode_print () {
+  do_check_eq("\u201c\u201d", "\u201c\u201d");
+  run_next_test();
+});
+'''
+
 ADD_TASK_SINGLE = '''
 Components.utils.import("resource://gre/modules/Promise.jsm");
 
 function run_test() { run_next_test(); }
 
 add_task(function test_task() {
   yield Promise.resolve(true);
   yield Promise.resolve(false);
@@ -259,17 +279,21 @@ function run_test() {
 
 class XPCShellTestsTests(unittest.TestCase):
     """
     Yes, these are unit tests for a unit test harness.
     """
     def setUp(self):
         self.log = StringIO()
         self.tempdir = tempfile.mkdtemp()
-        self.x = XPCShellTests(log=self.log)
+        logger = structured.commandline.setup_logging("selftest%s" % id(self),
+                                                      {},
+                                                      {"tbpl": self.log})
+        self.x = XPCShellTests(logger)
+        self.x.harness_timeout = 15
 
     def tearDown(self):
         shutil.rmtree(self.tempdir)
 
     def writeFile(self, name, contents):
         """
         Write |contents| to a file named |name| in the temp directory,
         and return the full path to the file.
@@ -295,29 +319,28 @@ class XPCShellTestsTests(unittest.TestCa
                 testlines.extend(t[1:])
         self.manifest = self.writeFile("xpcshell.ini", """
 [DEFAULT]
 head =
 tail =
 
 """ + "\n".join(testlines))
 
-    def assertTestResult(self, expected, shuffle=False, xunitFilename=None, verbose=False):
+    def assertTestResult(self, expected, shuffle=False, verbose=False):
         """
         Assert that self.x.runTests with manifest=self.manifest
         returns |expected|.
         """
         self.assertEquals(expected,
                           self.x.runTests(xpcshellBin,
                                           manifest=self.manifest,
                                           mozInfo=mozinfo.info,
                                           shuffle=shuffle,
                                           testsRootDir=self.tempdir,
                                           verbose=verbose,
-                                          xunitFilename=xunitFilename,
                                           sequential=True),
                           msg="""Tests should have %s, log:
 ========
 %s
 ========
 """ % ("passed" if expected else "failed", self.log.getvalue()))
 
     def _assertLog(self, s, expected):
@@ -347,53 +370,53 @@ tail =
         self.writeFile("test_basic.js", SIMPLE_PASSING_TEST)
         self.writeManifest(["test_basic.js"])
 
         self.assertTestResult(True)
         self.assertEquals(1, self.x.testCount)
         self.assertEquals(1, self.x.passCount)
         self.assertEquals(0, self.x.failCount)
         self.assertEquals(0, self.x.todoCount)
-        self.assertInLog("TEST-PASS")
-        self.assertNotInLog("TEST-UNEXPECTED-FAIL")
+        self.assertInLog(TEST_PASS_STRING)
+        self.assertNotInLog(TEST_FAIL_STRING)
 
     def testFail(self):
         """
         Check that a simple failing test without any manifest conditions fails.
         """
         self.writeFile("test_basic.js", SIMPLE_FAILING_TEST)
         self.writeManifest(["test_basic.js"])
 
         self.assertTestResult(False)
         self.assertEquals(1, self.x.testCount)
         self.assertEquals(0, self.x.passCount)
         self.assertEquals(1, self.x.failCount)
         self.assertEquals(0, self.x.todoCount)
-        self.assertInLog("TEST-UNEXPECTED-FAIL")
-        self.assertNotInLog("TEST-PASS")
<