Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 06 Jan 2015 11:05:52 -0500
changeset 248209 0ac7246e876e431c4777d4ff48fbefca6e5b2658
parent 248208 fa7cb9ac50212ca4950276c6fd812934a4d2a7c7 (current diff)
parent 248061 b42615e51c8106d2dba57343e34a631190473cb0 (diff)
child 248210 7194852248c0cc60054fe5cd21afd0d6050cb5f9
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.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
gfx/layers/composite/ContainerLayerComposite.cpp
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="6fa7a4936414ceb4055fd27f7a30e76790f834fb"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <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="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "c175a29477e68e70142687587844423a75dcf4cc", 
+    "revision": "23fc9f3f470e238bacb1a6b8ca978db4e63e0b55", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,21 +12,21 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <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="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="0e94c080bee081a50aa2097527b0b40852f9143f">
     <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="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="df362ace56338da8173d30d3e09e08c42c1accfa">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="b77e0d56d197e0ee02d801a25c784130d888c9db"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="69ac77cfa938fae2763ac426a80ca6e5feb6ad25"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
   <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="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f59d8671fff36da22236a4b270b93195889b7ff1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="3e48bfe5f59bd54597d8304c42391a7849b8361f"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1785,14 +1785,15 @@ pref("browser.tabs.remote.autostart.1", 
 pref("print.enable_e10s_testing", false);
 #else
 pref("print.enable_e10s_testing", true);
 #endif
 
 #ifdef NIGHTLY_BUILD
 // Enable e10s add-on interposition by default.
 pref("extensions.interposition.enabled", true);
+pref("extensions.interposition.prefetching", true);
 #endif
 
 pref("browser.defaultbrowser.notificationbar", false);
 
 // How many milliseconds to wait for a CPOW response from the child process.
 pref("dom.ipc.cpow.timeout", 0);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -833,16 +833,17 @@ nsDocShell::nsDocShell():
     mAllowContentRetargeting(true),
     mCreatingDocument(false),
     mUseErrorPages(false),
     mObserveErrorPages(true),
     mAllowAuth(true),
     mAllowKeywordFixup(false),
     mIsOffScreenBrowser(false),
     mIsActive(true),
+    mIsPrerendered(false),
     mIsAppTab(false),
     mUseGlobalHistory(false),
     mInPrivateBrowsing(false),
     mUseRemoteTabs(false),
     mDeviceSizeIsPageSize(false),
     mCanExecuteScripts(false),
     mFiredUnloadEvent(false),
     mEODForCurrentDocument(false),
@@ -3381,16 +3382,21 @@ nsDocShell::SetDocLoaderParent(nsDocLoad
             SetAllowWindowControl(value);
         }
         SetAllowContentRetargeting(
             parentAsDocShell->GetAllowContentRetargeting());
         if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value)))
         {
             SetIsActive(value);
         }
+        if (NS_SUCCEEDED(parentAsDocShell->GetIsPrerendered(&value))) {
+            if (value) {
+                SetIsPrerendered(true);
+            }
+        }
         if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
             value = false;
         }
         SetAllowDNSPrefetch(value);
         value = parentAsDocShell->GetAffectPrivateSessionLifetime();
         SetAffectPrivateSessionLifetime(value);
         uint32_t flags;
         if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags)))
@@ -6048,16 +6054,32 @@ nsDocShell::SetIsActive(bool aIsActive)
 NS_IMETHODIMP
 nsDocShell::GetIsActive(bool *aIsActive)
 {
     *aIsActive = mIsActive;
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShell::SetIsPrerendered(bool aPrerendered)
+{
+    MOZ_ASSERT(!aPrerendered || !mIsPrerendered,
+               "SetIsPrerendered(true) called on already prerendered docshell");
+    mIsPrerendered = aPrerendered;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetIsPrerendered(bool *aIsPrerendered)
+{
+    *aIsPrerendered = mIsPrerendered;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::SetIsAppTab(bool aIsAppTab)
 {
     mIsAppTab = aIsAppTab;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetIsAppTab(bool *aIsAppTab)
@@ -8548,18 +8570,18 @@ nsDocShell::RestoreFromHistory()
 
         bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
 
         uint32_t defaultLoadFlags;
         childShell->GetDefaultLoadFlags(&defaultLoadFlags);
 
         // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
         // that the child inherits our state. Among other things, this means
-        // that the child inherits our mIsActive and mInPrivateBrowsing, which
-        // is what we want.
+        // that the child inherits our mIsActive, mIsPrerendered and mInPrivateBrowsing,
+        // which is what we want.
         AddChild(childItem);
 
         childShell->SetAllowPlugins(allowPlugins);
         childShell->SetAllowJavascript(allowJavascript);
         childShell->SetAllowMetaRedirects(allowRedirects);
         childShell->SetAllowSubframes(allowSubframes);
         childShell->SetAllowImages(allowImages);
         childShell->SetAllowMedia(allowMedia);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -872,16 +872,17 @@ protected:
     bool                       mAllowContentRetargeting;
     bool                       mCreatingDocument; // (should be) debugging only
     bool                       mUseErrorPages;
     bool                       mObserveErrorPages;
     bool                       mAllowAuth;
     bool                       mAllowKeywordFixup;
     bool                       mIsOffScreenBrowser;
     bool                       mIsActive;
+    bool                       mIsPrerendered;
     bool                       mIsAppTab;
     bool                       mUseGlobalHistory;
     bool                       mInPrivateBrowsing;
     bool                       mUseRemoteTabs;
     bool                       mDeviceSizeIsPageSize;
 
     // Because scriptability depends on the mAllowJavascript values of our
     // ancestors, we cache the effective scriptability and recompute it when
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -49,17 +49,17 @@ interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
  
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(c2756385-bc54-417b-9ae4-c5a40053a2a3)]
+[scriptable, builtinclass, uuid(fef3bae1-6673-4c49-9f5a-fcc075926730)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -615,16 +615,23 @@ interface nsIDocShell : nsIDocShellTreeI
   /**
    * Sets whether a docshell is active. An active docshell is one that is
    * visible, and thus is not a good candidate for certain optimizations
    * like image frame discarding. Docshells are active unless told otherwise.
    */
   attribute boolean isActive;
 
   /**
+   * Puts the docshell in prerendering mode. noscript because we want only
+   * native code to be able to put a docshell in prerendering.
+   */
+  [noscript] void SetIsPrerendered(in boolean prerendered);
+  readonly attribute boolean isPrerendered;
+
+  /**
    * The ID of the docshell in the session history.
    */
   readonly attribute unsigned long long historyID;
 
   /**
    * Sets whether a docshell is an app tab. An app tab docshell may behave
    * differently than a non-app tab docshell in some cases, such as when
    * handling link clicks. Docshells are not app tabs unless told otherwise.
--- a/dom/animation/AnimationTimeline.cpp
+++ b/dom/animation/AnimationTimeline.cpp
@@ -55,24 +55,18 @@ AnimationTimeline::FastForward(const Tim
   // nsDOMWindowUtils::AdvanceTimeAndRefresh automatically starts any
   // pending animation players so we don't need to fast-forward the timeline
   // anyway.
   nsRefreshDriver* refreshDriver = GetRefreshDriver();
   if (refreshDriver && refreshDriver->IsTestControllingRefreshesEnabled()) {
     return;
   }
 
-  // Bug 1113413: If the refresh driver has just been restored from test
-  // control it's possible that aTimeStamp could be before the most recent
-  // refresh.
-  if (refreshDriver &&
-      aTimeStamp < refreshDriver->MostRecentRefresh()) {
-    mFastForwardTime = refreshDriver->MostRecentRefresh();
-    return;
-  }
+  MOZ_ASSERT(!refreshDriver || aTimeStamp >= refreshDriver->MostRecentRefresh(),
+             "aTimeStamp must be >= the refresh driver time");
 
   // FIXME: For all animations attached to this timeline, we should mark
   // their target elements as needing restyling. Otherwise, tasks that run
   // in between now and the next refresh driver tick might see inconsistencies
   // between the timing of an animation and the computed style of its target.
 
   mFastForwardTime = aTimeStamp;
 }
--- a/dom/animation/test/css-transitions/test_animation-player-ready.html
+++ b/dom/animation/test/css-transitions/test_animation-player-ready.html
@@ -62,9 +62,41 @@ async_test(function(t) {
 
   // Now remove transform from transition-property and flush styles
   div.style.transitionProperty = 'none';
   window.getComputedStyle(div).transitionProperty;
 
 }, 'ready promise is rejected when a transition is cancelled by updating'
    + ' transition-property');
 
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up pending transition
+  div.style.marginLeft = '0px';
+  window.getComputedStyle(div).marginLeft;
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '100px';
+  window.getComputedStyle(div).marginLeft;
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(player.playState, 'pending', 'Player is initially pending');
+
+  // Set up listeners on ready promise
+  player.ready.then(t.step_func(function() {
+    assert_unreached('ready promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+    assert_equals(player.playState, 'idle',
+                  'Player is idle after transition was cancelled');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now update the transition to animate to something not-interpolable
+  div.style.marginLeft = 'auto';
+  window.getComputedStyle(div).marginLeft;
+
+}, 'ready promise is rejected when a transition is cancelled by changing'
+   + ' the transition property to something not interpolable');
+
 </script>
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -2,17 +2,17 @@
 support-files =
   testcommon.js
 
 [animation-timeline/test_animation-timeline.html]
 skip-if = buildapp == 'mulet'
 [css-animations/test_animations-dynamic-changes.html]
 [css-animations/test_animation-effect-name.html]
 [css-animations/test_animation-pausing.html]
-skip-if = os == "mac" && os_version == "10.8" # disabled until bug 1112480 lands
+skip-if = os == "win" || (os == "mac" && os_version == "10.8") # disabled until bug 1112480 lands
 [css-animations/test_animation-player-playstate.html]
 [css-animations/test_animation-player-ready.html]
 [css-animations/test_animation-target.html]
 [css-animations/test_element-get-animation-players.html]
 skip-if = buildapp == 'mulet'
 [css-transitions/test_animation-effect-name.html]
 [css-transitions/test_animation-pausing.html]
 [css-transitions/test_animation-player-ready.html]
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -402,17 +402,23 @@ this.PermissionsTable =  { geolocation: 
                              certified: ALLOW_ACTION
                            },
                            "audio-capture": {
                              app: PROMPT_ACTION,
                              trusted: PROMPT_ACTION,
                              privileged: PROMPT_ACTION,
                              certified: ALLOW_ACTION
                            },
-                           "nfc": {
+                           "audio-capture:3gpp": {
+			     app: DENY_ACTION,
+			     trusted: DENY_ACTION,
+			     privileged: ALLOW_ACTION,
+			     certified: ALLOW_ACTION
+			   },
+			   "nfc": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "nfc-share": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -196,21 +196,17 @@ EventSource::Init(nsISupports* aOwner,
   nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
   NS_ENSURE_STATE(principal);
 
   mPrincipal = principal;
   mWithCredentials = aWithCredentials;
 
   // The conditional here is historical and not necessarily sane.
   if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
-    const char *filename;
-    if (nsJSUtils::GetCallingLocation(cx, &filename, &mScriptLine)) {
-      mScriptFile.AssignASCII(filename);
-    }
-
+    nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine);
     mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
   }
 
   // Get the load group for the page. When requesting we'll add ourselves to it.
   // This way any pending requests will be automatically aborted if the user
   // leaves the page.
   nsresult rv;
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -78,27 +78,31 @@ WindowNamedPropertiesHandler::getOwnProp
                                                    JS::MutableHandle<JSPropertyDescriptor> aDesc)
                                                    const
 {
   if (!JSID_IS_STRING(aId)) {
     // Nothing to do if we're resolving a non-string property.
     return true;
   }
 
-  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
-  if (HasPropertyOnPrototype(aCx, aProxy, aId)) {
+  bool hasOnPrototype;
+  if (!HasPropertyOnPrototype(aCx, aProxy, aId, &hasOnPrototype)) {
+    return false;
+  }
+  if (hasOnPrototype) {
     return true;
   }
 
   nsAutoJSString str;
   if (!str.init(aCx, JSID_TO_STRING(aId))) {
     return false;
   }
 
   // Grab the DOM window.
+  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
   nsGlobalWindow* win = xpc::WindowOrNull(global);
   if (win->Length() > 0) {
     nsCOMPtr<nsIDOMWindow> childWin = win->GetChildWindow(str);
     if (childWin && ShouldExposeChildWindow(str, childWin)) {
       // We found a subframe of the right name. Shadowing via |var foo| in
       // global scope is still allowed, since |var| only looks up |own|
       // properties. But unqualified shadowing will fail, per-spec.
       JS::Rooted<JS::Value> v(aCx);
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3359,22 +3359,17 @@ nsContentUtils::ReportToConsoleNonLocali
     rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsAutoCString spec;
   if (!aLineNumber) {
     JSContext *cx = GetCurrentJSContext();
     if (cx) {
-      const char* filename;
-      uint32_t lineno;
-      if (nsJSUtils::GetCallingLocation(cx, &filename, &lineno)) {
-        spec = filename;
-        aLineNumber = lineno;
-      }
+      nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber);
     }
   }
   if (spec.IsEmpty() && aURI)
     aURI->GetSpec(spec);
 
   nsCOMPtr<nsIScriptError> errorObject =
       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsElementFrameLoaderOwner.cpp
+++ b/dom/base/nsElementFrameLoaderOwner.cpp
@@ -107,16 +107,19 @@ nsElementFrameLoaderOwner::EnsureFrameLo
       mFrameLoaderCreationDisallowed) {
     // If frame loader is there, we just keep it around, cached
     return;
   }
 
   // Strangely enough, this method doesn't actually ensure that the
   // frameloader exists.  It's more of a best-effort kind of thing.
   mFrameLoader = nsFrameLoader::Create(thisElement, mNetworkCreated);
+  if (mIsPrerendered) {
+    mFrameLoader->SetIsPrerendered();
+  }
 }
 
 NS_IMETHODIMP
 nsElementFrameLoaderOwner::GetFrameLoader(nsIFrameLoader **aFrameLoader)
 {
   NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
   return NS_OK;
 }
@@ -130,16 +133,24 @@ nsElementFrameLoaderOwner::GetFrameLoade
 
 NS_IMETHODIMP
 nsElementFrameLoaderOwner::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
 {
   // We don't support this yet
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP
+nsElementFrameLoaderOwner::SetIsPrerendered()
+{
+  MOZ_ASSERT(!mFrameLoader, "Please call SetIsPrerendered before frameLoader is created");
+  mIsPrerendered = true;
+  return NS_OK;
+}
+
 nsresult
 nsElementFrameLoaderOwner::LoadSrc()
 {
   EnsureFrameLoader();
 
   if (!mFrameLoader) {
     return NS_OK;
   }
--- a/dom/base/nsElementFrameLoaderOwner.h
+++ b/dom/base/nsElementFrameLoaderOwner.h
@@ -28,16 +28,17 @@ class nsXULElement;
 /**
  * A helper class for frame elements
  */
 class nsElementFrameLoaderOwner : public nsIFrameLoaderOwner
 {
 public:
   explicit nsElementFrameLoaderOwner(mozilla::dom::FromParser aFromParser)
     : mNetworkCreated(aFromParser == mozilla::dom::FROM_PARSER_NETWORK)
+    , mIsPrerendered(false)
     , mBrowserFrameListenersRegistered(false)
     , mFrameLoaderCreationDisallowed(false)
   {
   }
 
   virtual ~nsElementFrameLoaderOwner();
 
   NS_DECL_NSIFRAMELOADEROWNER
@@ -65,13 +66,14 @@ protected:
 
   /**
    * True when the element is created by the parser using the
    * NS_FROM_PARSER_NETWORK flag.
    * If the element is modified, it may lose the flag.
    */
   bool mNetworkCreated;
 
+  bool mIsPrerendered;
   bool mBrowserFrameListenersRegistered;
   bool mFrameLoaderCreationDisallowed;
 };
 
 #endif // nsElementFrameLoaderOwner_h
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -149,16 +149,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
 NS_INTERFACE_MAP_END
 
 nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
   : mOwnerContent(aOwner)
   , mAppIdSentToPermissionManager(nsIScriptSecurityManager::NO_APP_ID)
   , mDetachedSubdocViews(nullptr)
+  , mIsPrerendered(false)
   , mDepthTooGreat(false)
   , mIsTopLevelContent(false)
   , mDestroyCalled(false)
   , mNeedsAsyncDestroy(false)
   , mInSwap(false)
   , mInShow(false)
   , mHideCalled(false)
   , mNetworkCreated(aNetworkCreated)
@@ -290,16 +291,25 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
   mURIToLoad = aURI;
   rv = doc->InitializeFrameLoader(this);
   if (NS_FAILED(rv)) {
     mURIToLoad = nullptr;
   }
   return rv;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::SetIsPrerendered()
+{
+  MOZ_ASSERT(!mDocShell, "Please call SetIsPrerendered before docShell is created");
+  mIsPrerendered = true;
+
+  return NS_OK;
+}
+
 nsresult
 nsFrameLoader::ReallyStartLoading()
 {
   nsresult rv = ReallyStartLoadingInternal();
   if (NS_FAILED(rv)) {
     FireErrorEvent();
   }
   
@@ -1608,16 +1618,21 @@ nsFrameLoader::MaybeCreateDocShell()
   nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell);
   NS_ENSURE_STATE(parentAsWebNav);
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
+  if (mIsPrerendered) {
+    nsresult rv = mDocShell->SetIsPrerendered(true);
+    NS_ENSURE_SUCCESS(rv,rv);
+  }
+
   // Apply sandbox flags even if our owner is not an iframe, as this copies
   // flags from our owning content's owning document.
   uint32_t sandboxFlags = 0;
   if (!mOwnerContent->IsSVG(nsGkAtoms::iframe)) {
     HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
     if (iframe) {
       sandboxFlags = iframe->GetSandboxFlags();
     }
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -326,16 +326,17 @@ private:
   nsView* mDetachedSubdocViews;
   // Stores the containing document of the frame corresponding to this
   // frame loader. This is reference is kept valid while the subframe's
   // presentation is detached and stored in mDetachedSubdocViews. This
   // enables us to detect whether the frame has moved documents during
   // a reframe, so that we know not to restore the presentation.
   nsCOMPtr<nsIDocument> mContainerDocWhileDetached;
 
+  bool mIsPrerendered : 1;
   bool mDepthTooGreat : 1;
   bool mIsTopLevelContent : 1;
   bool mDestroyCalled : 1;
   bool mNeedsAsyncDestroy : 1;
   bool mInSwap : 1;
   bool mInShow : 1;
   bool mHideCalled : 1;
   // True when the object is created for an element which the parser has
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -946,16 +946,17 @@ GK_ATOM(popupsinherittooltip, "popupsinh
 GK_ATOM(position, "position")
 GK_ATOM(poster, "poster")
 GK_ATOM(pre, "pre")
 GK_ATOM(preceding, "preceding")
 GK_ATOM(precedingSibling, "preceding-sibling")
 GK_ATOM(predicate, "predicate")
 GK_ATOM(prefix, "prefix")
 GK_ATOM(preload, "preload")
+GK_ATOM(prerendered, "prerendered")
 GK_ATOM(preserve, "preserve")
 GK_ATOM(preserveSpace, "preserve-space")
 GK_ATOM(preventdefault, "preventdefault")
 GK_ATOM(primary, "primary")
 GK_ATOM(print, "print")
 GK_ATOM(priority, "priority")
 GK_ATOM(processingInstruction, "processing-instruction")
 GK_ATOM(profile, "profile")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1113,16 +1113,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mNetworkDownloadObserverEnabled(false),
 #endif
     mCleanedUp(false),
     mDialogAbuseCount(0),
     mAreDialogsEnabled(true),
     mCanSkipCCGeneration(0),
     mVRDevicesInitialized(false)
 {
+  AssertIsOnMainThread();
+
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
   if (aOuterWindow) {
     // |this| is an inner window, add this inner window to the outer
     // window list of inners.
@@ -1213,20 +1215,33 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 
   // Ensure that the current active state is initialized for child process windows.
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     mIsActive = fm->IsParentActivated();
   }
 }
 
+#ifdef DEBUG
+
+/* static */
+void
+nsGlobalWindow::AssertIsOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+#endif // DEBUG
+
 /* static */
 void
 nsGlobalWindow::Init()
 {
+  AssertIsOnMainThread();
+
   CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
   NS_ASSERTION(gEntropyCollector,
                "gEntropyCollector should have been initialized!");
 
 #ifdef PR_LOGGING
   gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
   NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
 #endif
@@ -1240,16 +1255,18 @@ DisconnectEventTargetObjects(nsPtrHashKe
 {
   nsRefPtr<DOMEventTargetHelper> target = aKey->GetKey();
   target->DisconnectFromOwner();
   return PL_DHASH_NEXT;
 }
 
 nsGlobalWindow::~nsGlobalWindow()
 {
+  AssertIsOnMainThread();
+
   mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
   mEventTargetObjects.Clear();
 
   // We have to check if sWindowsById isn't null because ::Shutdown might have
   // been called.
   if (sWindowsById) {
     NS_ASSERTION(sWindowsById->Get(mWindowID),
                  "This window should be in the hash table");
@@ -1358,16 +1375,18 @@ nsGlobalWindow::RemoveEventTargetObject(
   MOZ_ASSERT(IsInnerWindow());
   mEventTargetObjects.RemoveEntry(aObject);
 }
 
 // static
 void
 nsGlobalWindow::ShutDown()
 {
+  AssertIsOnMainThread();
+
   if (gDumpFile && gDumpFile != stdout) {
     fclose(gDumpFile);
   }
   gDumpFile = nullptr;
 
   NS_IF_RELEASE(gEntropyCollector);
 
   delete sWindowsById;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -329,16 +329,24 @@ class nsGlobalWindow : public mozilla::d
                        public nsIInterfaceRequestor,
                        public PRCListStr
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindow*> WindowByIdTable;
 
+  static void
+  AssertIsOnMainThread()
+#ifdef DEBUG
+  ;
+#else
+  { }
+#endif
+
   // public methods
   nsPIDOMWindow* GetPrivateParent();
 
   // callback for close event
   void ReallyCloseWindow();
 
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -665,34 +673,40 @@ public:
                         const nsAString& aPopupWindowName,
                         const nsAString& aPopupWindowFeatures) MOZ_OVERRIDE;
 
   virtual uint32_t GetSerial() {
     return mSerial;
   }
 
   static nsGlobalWindow* GetOuterWindowWithId(uint64_t aWindowID) {
+    AssertIsOnMainThread();
+
     if (!sWindowsById) {
       return nullptr;
     }
 
     nsGlobalWindow* outerWindow = sWindowsById->Get(aWindowID);
     return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nullptr;
   }
 
   static nsGlobalWindow* GetInnerWindowWithId(uint64_t aInnerWindowID) {
+    AssertIsOnMainThread();
+
     if (!sWindowsById) {
       return nullptr;
     }
 
     nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
     return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
   }
 
   static WindowByIdTable* GetWindowsTable() {
+    AssertIsOnMainThread();
+
     return sWindowsById;
   }
 
   void AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;
 
   void UnmarkGrayTimers();
 
   // Inner windows only.
--- a/dom/base/nsIFrameLoader.idl
+++ b/dom/base/nsIFrameLoader.idl
@@ -11,17 +11,17 @@ interface nsIURI;
 interface nsIFrame;
 interface nsSubDocumentFrame;
 interface nsIMessageSender;
 interface nsIVariant;
 interface nsIDOMElement;
 interface nsITabParent;
 interface nsILoadContext;
 
-[scriptable, builtinclass, uuid(7600aa92-88dc-491c-896d-0564159b6a66)]
+[scriptable, builtinclass, uuid(28b6b043-46ec-412f-9be9-db22938b0d6d)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -45,16 +45,21 @@ interface nsIFrameLoader : nsISupports
 
   /**
    * Loads the specified URI in this frame. Behaves identically to loadFrame,
    * except that this method allows specifying the URI to load.
    */
   void loadURI(in nsIURI aURI);
 
   /**
+   * Puts the frameloader in prerendering mode.
+   */
+  void setIsPrerendered();
+
+  /**
    * Destroy the frame loader and everything inside it. This will
    * clear the weak owner content reference.
    */
   void destroy();
 
   /**
    * Find out whether the loader's frame is at too great a depth in
    * the frame tree.  This can be used to decide what operations may
@@ -187,26 +192,31 @@ interface nsIFrameLoader : nsISupports
 };
 
 %{C++
 class nsFrameLoader;
 %}
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
-[scriptable, uuid(5879040e-83e9-40e3-b2bb-5ddf43b76e47)]
+[scriptable, uuid(c4abebcf-55f3-47d4-af15-151311971255)]
 interface nsIFrameLoaderOwner : nsISupports
 {
   /**
    * The frame loader owned by this nsIFrameLoaderOwner
    */
   readonly attribute nsIFrameLoader frameLoader;
   [noscript, notxpcom] alreadyAddRefed_nsFrameLoader GetFrameLoader();
 
   /**
+   * Puts the FrameLoaderOwner in prerendering mode.
+   */
+  void setIsPrerendered();
+
+  /**
    * Swap frame loaders with the given nsIFrameLoaderOwner.  This may
    * only be posible in a very limited range of circumstances, or
    * never, depending on the object implementing this interface.
    *
    * @throws NS_ERROR_NOT_IMPLEMENTED if the swapping logic is not
    *   implemented for the two given frame loader owners.
    * @throws NS_ERROR_DOM_SECURITY_ERR if the swap is not allowed on
    *   security grounds.
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -168,21 +168,18 @@ CheckCSPForEval(JSContext* aCx, nsGlobal
 
   if (reportViolation) {
     // TODO : need actual script sample in violation report.
     NS_NAMED_LITERAL_STRING(scriptSample,
                             "call to eval() or related function blocked by CSP");
 
     // Get the calling location.
     uint32_t lineNum = 0;
-    const char *fileName;
     nsAutoString fileNameString;
-    if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNum)) {
-      AppendUTF8toUTF16(fileName, fileNameString);
-    } else {
+    if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum)) {
       fileNameString.AssignLiteral("unknown");
     }
 
     csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
                              fileNameString, scriptSample, lineNum,
                              EmptyString(), EmptyString());
   }
 
@@ -228,20 +225,17 @@ nsJSScriptTimeoutHandler::nsJSScriptTime
   }
 
   *aAllowEval = CheckCSPForEval(aCx, aWindow, aError);
   if (aError.Failed() || !*aAllowEval) {
     return;
   }
 
   // Get the calling location.
-  const char *filename;
-  if (nsJSUtils::GetCallingLocation(aCx, &filename, &mLineNo)) {
-    mFileName.Assign(filename);
-  }
+  nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo);
 }
 
 nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler()
 {
   ReleaseJSObjects();
 }
 
 void
@@ -348,20 +342,17 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
     if (error.Failed() || !*aAllowEval) {
       return error.ErrorCode();
     }
 
     MOZ_ASSERT(mExpr.IsEmpty());
     AssignJSFlatString(mExpr, expr);
 
     // Get the calling location.
-    const char *filename;
-    if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
-      mFileName.Assign(filename);
-    }
+    nsJSUtils::GetCallingLocation(cx, mFileName, &mLineNo);
   } else if (funobj) {
     *aAllowEval = true;
 
     mozilla::HoldJSObjects(this);
 
     mFunction = new Function(funobj, GetIncumbentGlobal());
 
     // Create our arg array.  argc is the number of arguments passed
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -29,29 +29,38 @@
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using namespace mozilla::dom;
 
 bool
-nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
+nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
                               uint32_t* aLineno)
 {
   JS::AutoFilename filename;
-  unsigned lineno = 0;
-
-  if (!JS::DescribeScriptedCaller(aContext, &filename, &lineno)) {
+  if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
     return false;
   }
 
-  *aFilename = filename.get();
-  *aLineno = lineno;
+  aFilename.Assign(filename.get());
+  return true;
+}
 
+bool
+nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
+                              uint32_t* aLineno)
+{
+  JS::AutoFilename filename;
+  if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
+    return false;
+  }
+
+  aFilename.Assign(NS_ConvertUTF8toUTF16(filename.get()));
   return true;
 }
 
 nsIScriptGlobalObject *
 nsJSUtils::GetStaticScriptGlobal(JSObject* aObj)
 {
   if (!aObj)
     return nullptr;
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -27,17 +27,19 @@ namespace dom {
 class AutoJSAPI;
 class Element;
 }
 }
 
 class nsJSUtils
 {
 public:
-  static bool GetCallingLocation(JSContext* aContext, const char* *aFilename,
+  static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
+                                 uint32_t* aLineno);
+  static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
                                  uint32_t* aLineno);
 
   static nsIScriptGlobalObject *GetStaticScriptGlobal(JSObject* aObj);
 
   static nsIScriptContext *GetStaticScriptContext(JSObject* aObj);
 
   /**
    * Retrieve the inner window ID based on the given JSContext.
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -319,16 +319,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
                   "Can't insert document or attribute nodes into a parent");
 
   *aResult = nullptr;
 
   // First deal with aNode and walk its attributes (and their children). Then,
   // if aDeep is true, deal with aNode's children (and recurse into their
   // attributes and children).
 
+  nsAutoScriptBlocker scriptBlocker;
   AutoJSContext cx;
   nsresult rv;
 
   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
 
   // aNode.
   NodeInfo *nodeInfo = aNode->mNodeInfo;
   nsRefPtr<NodeInfo> newNodeInfo;
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -1195,16 +1195,22 @@ nsObjectLoadingContent::GetFrameLoader(n
 NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
 nsObjectLoadingContent::GetFrameLoader()
 {
   nsRefPtr<nsFrameLoader> loader = mFrameLoader;
   return loader.forget();
 }
 
 NS_IMETHODIMP
+nsObjectLoadingContent::SetIsPrerendered()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsObjectLoadingContent::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoader)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetActualType(nsACString& aType)
 {
--- a/dom/base/test/TestCSPParser.cpp
+++ b/dom/base/test/TestCSPParser.cpp
@@ -361,16 +361,20 @@ nsresult TestPaths() {
     { "report-uri /examplepath",
       "report-uri http://www.selfuri.com/examplepath" },
     { "connect-src http://www.example.com/foo%3Bsessionid=12%2C34",
       "connect-src http://www.example.com/foo;sessionid=12,34" },
     { "connect-src http://www.example.com/foo%3bsessionid=12%2c34",
       "connect-src http://www.example.com/foo;sessionid=12,34" },
     { "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@",
       "connect-src http://test.com/pathincludingaz19-._~!$&'()*+=:@" },
+    { "script-src http://www.example.com:88/.js",
+      "script-src http://www.example.com:88/.js" },
+    { "script-src https://foo.com/_abc/abc_/_/_a_b_c_",
+      "script-src https://foo.com/_abc/abc_/_/_a_b_c_" }
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 1);
 }
 
 // ============================= TestSimplePolicies ========================
 
@@ -485,18 +489,16 @@ nsresult TestPoliciesWithInvalidSrc() {
     { "script-src http://www.example.com:88path-1/",
       "script-src 'none'" },
     { "script-src http://www.example.com:88//",
       "script-src 'none'" },
     { "script-src http://www.example.com:88//path-1",
       "script-src 'none'" },
     { "script-src http://www.example.com:88//path-1",
       "script-src 'none'" },
-    { "script-src http://www.example.com:88/.js",
-      "script-src 'none'" },
     { "script-src http://www.example.com:88.js",
       "script-src 'none'" },
     { "script-src http://www.example.com:*.js",
       "script-src 'none'" },
     { "script-src http://www.example.com:*.",
       "script-src 'none'" },
     { "connect-src http://www.example.com/foo%zz;",
       "connect-src 'none'" },
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -87,17 +87,20 @@ public:
   bool Failed() const
   {
     return !Get();
   }
 
 protected:
   JS::Rooted<JSObject*> mGlobalJSObject;
   JSContext* mCx;
-  mutable nsISupports* mGlobalObject;
+  mutable nsISupports* MOZ_UNSAFE_REF("Valid because GlobalObject is a stack "
+                                      "class, and mGlobalObject points to the "
+                                      "global, so it won't be destroyed as long "
+                                      "as GlobalObject lives on the stack") mGlobalObject;
 };
 
 // Class for representing optional arguments.
 template<typename T, typename InternalType>
 class Optional_base
 {
 public:
   Optional_base()
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1608,54 +1608,52 @@ NativePropertyHooks sWorkerNativePropert
   prototypes::id::_ID_Count,
   constructors::id::_ID_Count,
   nullptr
 };
 
 bool
 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id, bool* found,
-                       JS::Value* vp)
+                       JS::MutableHandle<JS::Value> vp)
 {
   JS::Rooted<JSObject*> proto(cx);
   if (!js::GetObjectProto(cx, proxy, &proto)) {
     return false;
   }
   if (!proto) {
     *found = false;
     return true;
   }
 
-  bool hasProp;
-  if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
+  if (!JS_HasPropertyById(cx, proto, id, found)) {
     return false;
   }
 
-  *found = hasProp;
-  if (!hasProp || !vp) {
+  if (!*found) {
     return true;
   }
 
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_ForwardGetPropertyTo(cx, proto, id, proxy, &value)) {
-    return false;
-  }
-
-  *vp = value;
-  return true;
+  return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
 }
 
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       JS::Handle<jsid> id)
+                       JS::Handle<jsid> id, bool* has)
 {
-  bool found;
-  // We ignore an error from GetPropertyOnPrototype.  We pass nullptr
-  // for vp so that GetPropertyOnPrototype won't actually do a get.
-  return !GetPropertyOnPrototype(cx, proxy, id, &found, nullptr) || found;
+  JS::Rooted<JSObject*> proto(cx);
+  if (!js::GetObjectProto(cx, proxy, &proto)) {
+    return false;
+  }
+  if (!proto) {
+    *has = false;
+    return true;
+  }
+
+  return JS_HasPropertyById(cx, proto, id, has);
 }
 
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                        nsTArray<nsString>& names,
                        bool shadowPrototypeProperties,
                        JS::AutoIdVector& props)
 {
@@ -1665,17 +1663,26 @@ AppendNamedPropertyIds(JSContext* cx, JS
       return false;
     }
 
     JS::Rooted<jsid> id(cx);
     if (!JS_ValueToId(cx, v, &id)) {
       return false;
     }
 
-    if (shadowPrototypeProperties || !HasPropertyOnPrototype(cx, proxy, id)) {
+    bool shouldAppend = shadowPrototypeProperties;
+    if (!shouldAppend) {
+      bool has;
+      if (!HasPropertyOnPrototype(cx, proxy, id, &has)) {
+        return false;
+      }
+      shouldAppend = !has;
+    }
+
+    if (shouldAppend) {
       if (!props.append(id)) {
         return false;
       }
     }
   }
 
   return true;
 }
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1805,26 +1805,25 @@ bool
 UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
 ThrowConstructorWithoutNew(JSContext* cx, const char* name);
 
-// vp is allowed to be null; in that case no get will be attempted,
-// and *found will simply indicate whether the property exists.
 bool
 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id, bool* found,
-                       JS::Value* vp);
-
+                       JS::MutableHandle<JS::Value> vp);
+
+//
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       JS::Handle<jsid> id);
+                       JS::Handle<jsid> id, bool* has);
 
 
 // Append the property names in "names" to "props". If
 // shadowPrototypeProperties is false then skip properties that are also
 // present on the proto chain of proxy.  If shadowPrototypeProperties is true,
 // then the "proxy" argument is ignored.
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -10099,25 +10099,51 @@ class CGDOMJSProxyHandler_getOwnPropDesc
                 # "arguments" as opposed to return type, [0] means first (and
                 # only) argument.
                 operations['NamedGetter'].signatures()[0][1][0].identifier.name)
             fillDescriptor = (
                 "FillPropertyDescriptor(desc, proxy, %s, %s);\n"
                 "return true;\n" % (readonly, enumerable))
             templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
                               'obj': 'proxy', 'successCode': fillDescriptor}
-            condition = "!HasPropertyOnPrototype(cx, proxy, id)"
+
+            computeCondition = dedent("""
+                bool hasOnProto;
+                if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
+                  return false;
+                }
+                callNamedGetter = !hasOnProto;
+                """)
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
-                condition = "(!isXray || %s)" % condition
-            condition = "!ignoreNamedProps && " + condition
+                computeCondition = fill("""
+                    if (!isXray) {
+                      callNamedGetter = true;
+                    } else {
+                      $*{hasOnProto}
+                    }
+                    """,
+                    hasOnProto=computeCondition)
+
+            outerCondition = "!ignoreNamedProps"
             if self.descriptor.supportsIndexedProperties():
-                condition = "!IsArrayIndex(index) && " + condition
-            namedGet = (CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
-                                    condition).define() +
-                        "\n")
+                outerCondition = "!IsArrayIndex(index) && " + outerCondition
+
+            namedGet = fill("""
+                bool callNamedGetter = false;
+                if (${outerCondition}) {
+                  $*{computeCondition}
+                }
+                if (callNamedGetter) {
+                  $*{namedGetCode}
+                }
+                """,
+                outerCondition=outerCondition,
+                computeCondition=computeCondition,
+                namedGetCode=CGProxyNamedGetter(self.descriptor, templateValues).define())
+            namedGet += "\n"
         else:
             namedGet = ""
 
         return fill(
             """
             bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
             $*{getIndexed}
             $*{getUnforgeable}
@@ -10340,18 +10366,26 @@ class CGDOMJSProxyHandler_delete(ClassMe
                 bool found = false;
                 $*{namedBody}
                 if (found) {
                   return true;
                 }
                 """,
                 namedBody=namedBody)
             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
-                delete = CGIfWrapper(CGGeneric(delete),
-                                     "!HasPropertyOnPrototype(cx, proxy, id)").define()
+                delete = fill("""
+                    bool hasOnProto;
+                    if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
+                      return false;
+                    }
+                    if (!hasOnProto) {
+                      $*{delete}
+                    }
+                    """,
+                    delete=delete)
 
         delete += dedent("""
 
             return dom::DOMProxyHandler::delete_(cx, proxy, id, bp);
             """)
 
         return delete
 
@@ -10480,18 +10514,27 @@ class CGDOMJSProxyHandler_hasOwn(ClassMe
                 """
                 bool found = false;
                 $*{presenceChecker}
 
                 *bp = found;
                 """,
                 presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
-                named = CGIfWrapper(CGGeneric(named + "return true;\n"),
-                                    "!HasPropertyOnPrototype(cx, proxy, id)").define()
+                named = fill("""
+                    bool hasOnProto;
+                    if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
+                      return false;
+                    }
+                    if (!hasOnProto) {
+                      $*{protoLacksProperty}
+                      return true;
+                    }
+                    """,
+                    protoLacksProperty=named)
                 named += "*bp = false;\n"
             else:
                 named += "\n"
         else:
             named = "*bp = false;\n"
 
         return fill(
             """
@@ -10588,17 +10631,17 @@ class CGDOMJSProxyHandler_get(ClassMetho
             if self.descriptor.supportsIndexedProperties():
                 getNamed = CGIfWrapper(getNamed, "!IsArrayIndex(index)")
             getNamed = getNamed.define() + "\n"
         else:
             getNamed = ""
 
         getOnPrototype = dedent("""
             bool foundOnPrototype;
-            if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp.address())) {
+            if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp)) {
               return false;
             }
 
             if (foundOnPrototype) {
               return true;
             }
 
             """)
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -141,25 +141,32 @@ static const double THRESHOLD_LOW_PLAYBA
 // so we need to stay alive.
 // 2) If the element is not paused and playback has not ended, then
 // we will (or might) play, sending timeupdate and ended events and possibly
 // audio output, so we need to stay alive.
 // 3) if the element is seeking then we will fire seeking events and possibly
 // start playing afterward, so we need to stay alive.
 // 4) If autoplay could start playback in this element (if we got enough data),
 // then we need to stay alive.
-// 5) if the element is currently loading and not suspended,
-// script might be waiting for progress events or a 'suspend' event,
-// so we need to stay alive. If we're already suspended then (all other
-// conditions being met) it's OK to just disappear without firing any more
-// events, since we have the freedom to remain suspended indefinitely. Note
+// 5) if the element is currently loading, not suspended, and its source is
+// not a MediaSource, then script might be waiting for progress events or a
+// 'stalled' or 'suspend' event, so we need to stay alive.
+// If we're already suspended then (all other conditions being met),
+// it's OK to just disappear without firing any more events,
+// since we have the freedom to remain suspended indefinitely. Note
 // that we could use this 'suspended' loophole to garbage-collect a suspended
 // element in case 4 even if it had 'autoplay' set, but we choose not to.
 // If someone throws away all references to a loading 'autoplay' element
 // sound should still eventually play.
+// 6) If the source is a MediaSource, most loading events will not fire unless
+// appendBuffer() is called on a SourceBuffer, in which case something is
+// already referencing the SourceBuffer, which keeps the associated media
+// element alive. Further, a MediaSource will never time out the resource
+// fetch, and so should not keep the media element alive if it is
+// unreferenced. A pending 'stalled' event keeps the media element alive.
 //
 // Media elements owned by inactive documents (i.e. documents not contained in any
 // document viewer) should never hold a self-reference because none of the
 // above conditions are allowed: the element will stop loading and playing
 // and never resume loading or playing unless its owner document changes to
 // an active document (which can only happen if there is an external reference
 // to the element).
 // Media elements with no owner doc should be able to hold a self-reference.
@@ -679,32 +686,31 @@ void HTMLMediaElement::AbortExistingLoad
       // will now be reported as 0. The playback position was non-zero when
       // we destroyed the decoder, so fire a timeupdate event so that the
       // change will be reflected in the controls.
       FireTimeUpdate(false);
     }
     DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
   }
 
-  // We may have changed mPaused, mAutoplaying, mNetworkState and other
+  // We may have changed mPaused, mAutoplaying, and other
   // things which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
 
   mIsRunningSelectResource = false;
 }
 
 void HTMLMediaElement::NoSupportedMediaSourceError()
 {
   NS_ASSERTION(mNetworkState == NETWORK_LOADING,
                "Not loading during source selection?");
 
   mError = new MediaError(this, nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
   DispatchAsyncEvent(NS_LITERAL_STRING("error"));
-  // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
   ChangeDelayLoadStatus(false);
 }
 
 typedef void (HTMLMediaElement::*SyncSectionFn)();
 
 // Runs a "synchronous section", a function that must run once the event loop
 // has reached a "stable state". See:
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#synchronous-section
@@ -809,26 +815,23 @@ void HTMLMediaElement::SelectResourceWra
 
 void HTMLMediaElement::SelectResource()
 {
   if (!mSrcAttrStream && !HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
       !HasSourceChildren(this)) {
     // The media element has neither a src attribute nor any source
     // element children, abort the load.
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
-    // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
     ChangeDelayLoadStatus(false);
     return;
   }
 
   ChangeDelayLoadStatus(true);
 
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
-  // Load event was delayed, and still is, so no need to call
-  // AddRemoveSelfReference, since it must still be held
   DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
 
   // Delay setting mIsRunningSeletResource until after UpdatePreloadAction
   // so that we don't lose our state change by bailing out of the preload
   // state update
   UpdatePreloadAction();
   mIsRunningSelectResource = true;
 
@@ -2128,17 +2131,16 @@ void HTMLMediaElement::SetPlayedOrSeeked
 
 void
 HTMLMediaElement::ResetConnectionState()
 {
   SetCurrentTime(0);
   FireTimeUpdate(false);
   DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
-  AddRemoveSelfReference();
   ChangeDelayLoadStatus(false);
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
 }
 
 void
 HTMLMediaElement::Play(ErrorResult& aRv)
 {
   StopSuspendingAfterFirstFrame();
@@ -2853,17 +2855,16 @@ void HTMLMediaElement::SetupSrcMediaStre
   // Note: we must call DisconnectTrackListListeners(...)  before dropping
   // mSrcStream
   mSrcStream->ConstructMediaTracks(AudioTracks(), VideoTracks());
 
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
   DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
-  AddRemoveSelfReference();
   // FirstFrameLoaded() will be called when the stream has current data.
 }
 
 void HTMLMediaElement::EndSrcMediaStreamPlayback()
 {
   MediaStream* stream = GetSrcMediaStream();
   if (stream) {
     stream->RemoveListener(mSrcStreamListener);
@@ -3005,17 +3006,16 @@ void HTMLMediaElement::Error(uint16_t aE
   mError = new MediaError(this, aErrorCode);
   DispatchAsyncEvent(NS_LITERAL_STRING("error"));
   if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
     DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
   } else {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
   }
-  AddRemoveSelfReference();
   ChangeDelayLoadStatus(false);
 }
 
 void HTMLMediaElement::PlaybackEnded()
 {
   // We changed state which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
 
@@ -3079,25 +3079,23 @@ void HTMLMediaElement::NotifySuspendedBy
 
 void HTMLMediaElement::DownloadSuspended()
 {
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
     DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
   }
   if (mBegun) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
-    AddRemoveSelfReference();
   }
 }
 
 void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading)
 {
   if (mBegun || aForceNetworkLoading) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
-    AddRemoveSelfReference();
   }
 }
 
 void HTMLMediaElement::CheckProgress(bool aHaveNewProgress)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
 
@@ -3140,16 +3138,18 @@ void HTMLMediaElement::CheckProgress(boo
     DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
     ChangeDelayLoadStatus(false);
 
     NS_ASSERTION(mProgressTimer, "detected stalled without timer");
     // Stop timer events, which prevents repeated stalled events until there
     // is more progress.
     StopProgress();
   }
+
+  AddRemoveSelfReference();
 }
 
 /* static */
 void HTMLMediaElement::ProgressTimerCallback(nsITimer* aTimer, void* aClosure)
 {
   auto decoder = static_cast<HTMLMediaElement*>(aClosure);
   decoder->CheckProgress(false);
 }
@@ -3353,16 +3353,19 @@ void HTMLMediaElement::ChangeNetworkStat
     // Download is begun.
     mBegun = true;
     // Start progress notification when entering NETWORK_LOADING.
     StartProgress();
   } else if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE && !mError) {
     // Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
     DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
   }
+
+  // Changing mNetworkState affects AddRemoveSelfReference().
+  AddRemoveSelfReference();
 }
 
 bool HTMLMediaElement::CanActivateAutoplay()
 {
   // For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
   // this element itself might be blocking the stream from making progress by
   // being paused.
   return !mPausedForInactiveDocumentOrChannel &&
@@ -3623,17 +3626,18 @@ void HTMLMediaElement::AddRemoveSelfRefe
   // boolean expression.
   bool needSelfReference = !mShuttingDown &&
     ownerDoc->IsActive() &&
     (mDelayingLoadEvent ||
      (!mPaused && mDecoder && !mDecoder->IsEnded()) ||
      (!mPaused && mSrcStream && !mSrcStream->IsFinished()) ||
      (mDecoder && mDecoder->IsSeeking()) ||
      CanActivateAutoplay() ||
-     mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
+     (mMediaSource ? mProgressTimer :
+      mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING));
 
   if (needSelfReference != mHasSelfReference) {
     mHasSelfReference = needSelfReference;
     if (needSelfReference) {
       // The observer service will hold a strong reference to us. This
       // will do to keep us alive. We need to know about shutdown so that
       // we can release our self-reference.
       nsContentUtils::RegisterShutdownObserver(this);
--- a/dom/icc/Assertions.cpp
+++ b/dom/icc/Assertions.cpp
@@ -89,13 +89,25 @@ ASSERT_ICC_LOCK_TYPE_EQUALITY(Fdn, CARD_
   ASSERT_EQUALITY(IccContactType, webidlState, xpidlState)
 
 ASSERT_ICC_CONTACT_TYPE_EQUALITY(Adn, CARD_CONTACT_TYPE_ADN);
 ASSERT_ICC_CONTACT_TYPE_EQUALITY(Fdn, CARD_CONTACT_TYPE_FDN);
 ASSERT_ICC_CONTACT_TYPE_EQUALITY(Sdn, CARD_CONTACT_TYPE_SDN);
 
 #undef ASSERT_ICC_CONTACT_TYPE_EQUALITY
 
+/**
+ * Enum IccMvnoType
+ */
+#define ASSERT_ICC_MVNO_TYPE_EQUALITY(webidlState, xpidlState) \
+  ASSERT_EQUALITY(IccMvnoType, webidlState, xpidlState)
+
+ASSERT_ICC_MVNO_TYPE_EQUALITY(Imsi, CARD_MVNO_TYPE_IMSI);
+ASSERT_ICC_MVNO_TYPE_EQUALITY(Spn, CARD_MVNO_TYPE_SPN);
+ASSERT_ICC_MVNO_TYPE_EQUALITY(Gid, CARD_MVNO_TYPE_GID);
+
+#undef ASSERT_ICC_MVNO_TYPE_EQUALITY
+
 #undef ASSERT_EQUALITY
 
 } // namespace icc
 } // namespace dom
 } // namespace mozilla
--- a/dom/icc/Icc.cpp
+++ b/dom/icc/Icc.cpp
@@ -379,29 +379,28 @@ Icc::UpdateContact(const JSContext* aCx,
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget().downcast<DOMRequest>();
 }
 
 already_AddRefed<DOMRequest>
-Icc::MatchMvno(const nsAString& aMvnoType,
-               const nsAString& aMvnoData,
+Icc::MatchMvno(IccMvnoType aMvnoType, const nsAString& aMvnoData,
                ErrorResult& aRv)
 {
   if (!mProvider) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<nsIDOMDOMRequest> request;
   nsresult rv = mProvider->MatchMvno(mClientId, GetOwner(),
-                                     aMvnoType, aMvnoData,
-                                     getter_AddRefs(request));
+                                     static_cast<uint32_t>(aMvnoType),
+                                     aMvnoData, getter_AddRefs(request));
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget().downcast<DOMRequest>();
 }
 
--- a/dom/icc/Icc.h
+++ b/dom/icc/Icc.h
@@ -93,17 +93,17 @@ public:
   ReadContacts(IccContactType aContactType, ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
   UpdateContact(const JSContext* aCx, IccContactType aContactType,
                 JS::Handle<JS::Value> aContact, const nsAString& aPin2,
                 ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
-  MatchMvno(const nsAString& aMvnoType, const nsAString& aMatchData,
+  MatchMvno(IccMvnoType aMvnoType, const nsAString& aMatchData,
             ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(iccinfochange)
   IMPL_EVENT_HANDLER(cardstatechange)
   IMPL_EVENT_HANDLER(stkcommand)
   IMPL_EVENT_HANDLER(stksessionend)
 
 private:
--- a/dom/icc/interfaces/nsIIccProvider.idl
+++ b/dom/icc/interfaces/nsIIccProvider.idl
@@ -12,20 +12,58 @@ interface nsIIccInfo;
 interface nsIIccListener : nsISupports
 {
   void notifyStkCommand(in DOMString aMessage);
   void notifyStkSessionEnd();
   void notifyCardStateChanged();
   void notifyIccInfoChanged();
 };
 
+[scriptable, uuid(6136acab-b50e-494a-a86d-df392a032897)]
+interface nsIIccChannelCallback : nsISupports
+{
+  /**
+   * Callback function to notify on successfully opening a logical channel.
+   *
+   * @param channel
+   *        The Channel Number/Handle that is successfully opened.
+   */
+  void notifyOpenChannelSuccess(in long channel);
+
+  /**
+   * Callback function to notify on successfully closing the logical channel.
+   *
+   */
+  void notifyCloseChannelSuccess();
+
+  /**
+   * Callback function to notify the status of 'iccExchangeAPDU' command.
+   *
+   * @param sw1
+   *        Response's First Status Byte
+   * @param sw2
+   *        Response's Second Status Byte
+   * @param data
+   *        Response's data
+   */
+  void notifyExchangeAPDUResponse(in octet sw1,
+                                  in octet sw2,
+                                  in DOMString data);
+
+  /**
+   * Callback function to notify error
+   *
+   */
+  void notifyError(in DOMString error);
+};
+
 /**
  * XPCOM component (in the content process) that provides the ICC information.
  */
-[scriptable, uuid(937213c3-f64e-4f58-b4e0-3010f219d0c3)]
+[scriptable, uuid(bf985ee1-14c9-43c6-a471-8ab52fb24b0d)]
 interface nsIIccProvider : nsISupports
 {
   // MUST match enum IccCardState in MozIcc.webidl!
   const unsigned long CARD_STATE_UNKNOWN = 0;
   const unsigned long CARD_STATE_READY = 1;
   const unsigned long CARD_STATE_PIN_REQUIRED = 2;
   const unsigned long CARD_STATE_PUK_REQUIRED = 3;
   const unsigned long CARD_STATE_PERMANENT_BLOCKED = 4;
@@ -80,16 +118,21 @@ interface nsIIccProvider : nsISupports
   const unsigned long CARD_LOCK_TYPE_RSPCK_PUK = 19;
   const unsigned long CARD_LOCK_TYPE_FDN = 20;
 
   // MUST match with enum IccContactType in MozIcc.webidl
   const unsigned long CARD_CONTACT_TYPE_ADN = 0;
   const unsigned long CARD_CONTACT_TYPE_FDN = 1;
   const unsigned long CARD_CONTACT_TYPE_SDN = 2;
 
+  // MUST match with enum IccMvnoType in MozIcc.webidl
+  const unsigned long CARD_MVNO_TYPE_IMSI = 0;
+  const unsigned long CARD_MVNO_TYPE_SPN = 1;
+  const unsigned long CARD_MVNO_TYPE_GID = 2;
+
   /**
    * Called when a content process registers receiving unsolicited messages from
    * RadioInterfaceLayer in the chrome process. Only a content process that has
    * the 'mobileconnection' permission is allowed to register.
    */
   void registerIccMsg(in unsigned long clientId, in nsIIccListener listener);
   void unregisterIccMsg(in unsigned long clientId, in nsIIccListener listener);
 
@@ -156,32 +199,44 @@ interface nsIIccProvider : nsISupports
                                 in unsigned long contactType);
 
   nsIDOMDOMRequest updateContact(in unsigned long clientId,
                                  in nsIDOMWindow window,
                                  in unsigned long contactType,
                                  in jsval contact,
                                  in DOMString pin2);
 
-  /**
+/**
    * Secure Card Icc communication channel
    */
-  nsIDOMDOMRequest iccOpenChannel(in unsigned long clientId,
-                                  in nsIDOMWindow window,
-                                  in DOMString aid);
+  void iccOpenChannel(in unsigned long clientId,
+                      in DOMString aid,
+                      in nsIIccChannelCallback callback);
 
-  nsIDOMDOMRequest iccExchangeAPDU(in unsigned long clientId,
-                                   in nsIDOMWindow window,
-                                   in long channel,
-                                   in jsval apdu);
+  /**
+   * Exchange Command APDU (C-APDU) with SIM on the given logical channel.
+   * Note that 'P3' parameter could be Le/Lc depending on command APDU case.
+   * For Case 1 scenario (when only command header is present), the value
+   * of 'P3' should be set to '-1' explicitly.
+   * Refer to 3G TS 31.101 , 10.2 'Command APDU Structure' for all the cases.
+   */
+  void iccExchangeAPDU(in unsigned long clientId,
+                       in long channel,
+                       in octet cla,
+                       in octet ins,
+                       in octet p1,
+                       in octet p2,
+                       in short p3,
+                       in DOMString data,
+                       in nsIIccChannelCallback callback);
 
-  nsIDOMDOMRequest iccCloseChannel(in unsigned long clientId,
-                                   in nsIDOMWindow window,
-                                   in long channel);
+  void iccCloseChannel(in unsigned long clientId,
+                       in long channel,
+                       in nsIIccChannelCallback callback);
 
   /**
    * Helpers
    */
   nsIDOMDOMRequest matchMvno(in unsigned long clientId,
                              in nsIDOMWindow window,
-                             in DOMString mvnoType,
+                             in unsigned long mvnoType,
                              in DOMString mvnoData);
 };
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -163,26 +163,17 @@ IDBRequest::SetLoggingSerialNumber(uint6
 
 void
 IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo)
 {
   MOZ_ASSERT(aFilename.IsEmpty());
   MOZ_ASSERT(aLineNo);
 
   ThreadsafeAutoJSContext cx;
-
-  const char* filename = nullptr;
-  uint32_t lineNo = 0;
-  if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
-    *aLineNo = 0;
-    return;
-  }
-
-  aFilename.Assign(NS_ConvertUTF8toUTF16(filename));
-  *aLineNo = lineNo;
+  nsJSUtils::GetCallingLocation(cx, aFilename, aLineNo);
 }
 
 void
 IDBRequest::GetSource(
              Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const
 {
   AssertIsOnOwningThread();
 
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/AudioStreamTrack.h"
 #include "mozilla/dom/BlobEvent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/RecordErrorEvent.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 #include "nsError.h"
 #include "nsIDocument.h"
+#include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsMimeTypes.h"
 #include "nsProxyRelease.h"
 #include "nsTArray.h"
 #include "GeckoProfiler.h"
 
 #ifdef LOG
 #undef LOG
@@ -540,32 +541,53 @@ private:
       TracksAvailableCallback* tracksAvailableCallback = new TracksAvailableCallback(this);
       domStream->OnTracksAvailable(tracksAvailableCallback);
     } else {
       // Web Audio node has only audio.
       InitEncoder(DOMMediaStream::HINT_CONTENTS_AUDIO);
     }
   }
 
+  bool Check3gppPermission()
+  {
+    nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
+    if (!doc) {
+      return false;
+    }
+
+    uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
+    doc->NodePrincipal()->GetAppStatus(&appStatus);
+
+    // Certified applications can always assign AUDIO_3GPP
+    if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
+      return true;
+    }
+
+    nsCOMPtr<nsIPermissionManager> pm =
+       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+
+    if (!pm) {
+      return false;
+    }
+
+    uint32_t perm = nsIPermissionManager::DENY_ACTION;
+    pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), "audio-capture:3gpp", &perm);
+    return perm == nsIPermissionManager::ALLOW_ACTION;
+  }
+
   void InitEncoder(uint8_t aTrackTypes)
   {
     LOG(PR_LOG_DEBUG, ("Session.InitEncoder %p", this));
     MOZ_ASSERT(NS_IsMainThread());
 
     // Allocate encoder and bind with union stream.
     // At this stage, the API doesn't allow UA to choose the output mimeType format.
 
-    nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
-    uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
-    if (doc) {
-      doc->NodePrincipal()->GetAppStatus(&appStatus);
-    }
-    // Only allow certificated application can assign AUDIO_3GPP
-    if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
-         mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP)) {
+    // Make sure the application has permission to assign AUDIO_3GPP
+    if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && Check3gppPermission()) {
       mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP), aTrackTypes);
     } else {
       mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
     }
 
     if (!mEncoder) {
       DoSessionEndTask(NS_ERROR_ABORT);
       return;
--- a/dom/media/MediaRecorder.h
+++ b/dom/media/MediaRecorder.h
@@ -143,14 +143,16 @@ protected:
   nsTArray<nsRefPtr<Session> > mSessions;
   // It specifies the container format as well as the audio and video capture formats.
   nsString mMimeType;
 
 private:
   // Register MediaRecorder into Document to listen the activity changes.
   void RegisterActivityObserver();
   void UnRegisterActivityObserver();
+
+  bool Check3gppPermission();
 };
 
 }
 }
 
 #endif
--- a/dom/media/RtspMediaResource.cpp
+++ b/dom/media/RtspMediaResource.cpp
@@ -215,16 +215,23 @@ nsresult RtspTrackBuffer::ReadBuffer(uin
            ,mBufferSlotData[mConsumerIdx].mLength);
   // Reader should skip the slots with mLength==BUFFER_SLOT_INVALID.
   // The loop ends when
   // 1. Read data successfully
   // 2. Fail to read data due to aToBuffer's space
   // 3. No data in this buffer
   // 4. mIsStarted is not set
   while (1) {
+    // Make sure the track buffer is started.
+    // It could be stopped when RTSP connection is disconnected.
+    if (!mIsStarted) {
+      RTSPMLOG("ReadBuffer: mIsStarted is false");
+      return NS_ERROR_FAILURE;
+    }
+
     // Do not read from buffer if we are still in the playout delay duration.
     if (mDuringPlayoutDelay) {
       monitor.Wait();
       continue;
     }
 
     if (mBufferSlotData[mConsumerIdx].mFrameType & MEDIASTREAM_FRAMETYPE_END_OF_STREAM) {
       return NS_BASE_STREAM_CLOSED;
@@ -256,20 +263,16 @@ nsresult RtspTrackBuffer::ReadBuffer(uin
         mBufferSlotData[i].mTime = BUFFER_SLOT_EMPTY;
       }
       mConsumerIdx = (mConsumerIdx + slots) % BUFFER_SLOT_NUM;
       break;
     } else if (mBufferSlotData[mConsumerIdx].mLength == BUFFER_SLOT_INVALID) {
       mConsumerIdx = (mConsumerIdx + 1) % BUFFER_SLOT_NUM;
       RTSPMLOG("BUFFER_SLOT_INVALID move forward");
     } else {
-      // No data, and disconnected.
-      if (!mIsStarted) {
-        return NS_ERROR_FAILURE;
-      }
       // No data, the decode thread is blocked here until we receive
       // OnMediaDataAvailable. The OnMediaDataAvailable will call WriteBuffer()
       // to wake up the decode thread.
       RTSPMLOG("monitor.Wait()");
       monitor.Wait();
     }
   }
   return NS_OK;
@@ -611,16 +614,21 @@ RtspMediaResource::ReadFrameFromTrack(ui
                                       uint32_t aTrackIdx, uint32_t& aBytes,
                                       uint64_t& aTime, uint32_t& aFrameSize)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
   NS_ASSERTION(aTrackIdx < mTrackBuffer.Length(),
                "ReadTrack index > mTrackBuffer");
   MOZ_ASSERT(aBuffer);
 
+  if (!mIsConnected) {
+    RTSPMLOG("ReadFrameFromTrack: RTSP not connected");
+    return NS_ERROR_FAILURE;
+  }
+
   return mTrackBuffer[aTrackIdx]->ReadBuffer(aBuffer, aBufferSize, aBytes,
                                              aTime, aFrameSize);
 }
 
 nsresult
 RtspMediaResource::OnMediaDataAvailable(uint8_t aTrackIdx,
                                         const nsACString &data,
                                         uint32_t length,
@@ -764,16 +772,17 @@ RtspMediaResource::OnDisconnected(uint8_
 
   if (mDecoder) {
     if (aReason == NS_ERROR_NOT_INITIALIZED ||
         aReason == NS_ERROR_CONNECTION_REFUSED ||
         aReason == NS_ERROR_NOT_CONNECTED ||
         aReason == NS_ERROR_NET_TIMEOUT) {
       // Report error code to Decoder.
       RTSPMLOG("Error in OnDisconnected 0x%x", aReason);
+      mIsConnected = false;
       mDecoder->NetworkError();
     } else {
       // Resetting the decoder and media element when the connection
       // between RTSP client and server goes down.
       mDecoder->ResetConnectionState();
     }
   }
 
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -307,19 +307,22 @@ MediaSource::IsTypeSupported(const Globa
 }
 
 bool
 MediaSource::Attach(MediaSourceDecoder* aDecoder)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("MediaSource(%p)::Attach(aDecoder=%p) owner=%p", this, aDecoder, aDecoder->GetOwner());
   MOZ_ASSERT(aDecoder);
+  MOZ_ASSERT(aDecoder->GetOwner());
   if (mReadyState != MediaSourceReadyState::Closed) {
     return false;
   }
+  MOZ_ASSERT(!mMediaElement);
+  mMediaElement = aDecoder->GetOwner()->GetMediaElement();
   MOZ_ASSERT(!mDecoder);
   mDecoder = aDecoder;
   mDecoder->AttachMediaSource(this);
   SetReadyState(MediaSourceReadyState::Open);
   return true;
 }
 
 void
@@ -330,16 +333,17 @@ MediaSource::Detach()
             this, mDecoder.get(), mDecoder ? mDecoder->GetOwner() : nullptr);
   if (!mDecoder) {
     MOZ_ASSERT(mReadyState == MediaSourceReadyState::Closed);
     MOZ_ASSERT(mActiveSourceBuffers->IsEmpty() && mSourceBuffers->IsEmpty());
     return;
   }
   mDecoder->DetachMediaSource();
   mDecoder = nullptr;
+  mMediaElement = nullptr;
   mFirstSourceBufferInitialized = false;
   SetReadyState(MediaSourceReadyState::Closed);
   if (mActiveSourceBuffers) {
     mActiveSourceBuffers->Clear();
   }
   if (mSourceBuffers) {
     mSourceBuffers->Clear();
   }
@@ -482,16 +486,17 @@ MediaSource::GetParentObject() const
 
 JSObject*
 MediaSource::WrapObject(JSContext* aCx)
 {
   return MediaSourceBinding::Wrap(aCx, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaSource, DOMEventTargetHelper,
+                                   mMediaElement,
                                    mSourceBuffers, mActiveSourceBuffers)
 
 NS_IMPL_ADDREF_INHERITED(MediaSource, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MediaSource, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaSource)
   NS_INTERFACE_MAP_ENTRY(mozilla::dom::MediaSource)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
--- a/dom/media/mediasource/MediaSource.h
+++ b/dom/media/mediasource/MediaSource.h
@@ -123,16 +123,19 @@ private:
   void DurationChange(double aOldDuration, double aNewDuration);
 
   void InitializationEvent();
 
   nsRefPtr<SourceBufferList> mSourceBuffers;
   nsRefPtr<SourceBufferList> mActiveSourceBuffers;
 
   nsRefPtr<MediaSourceDecoder> mDecoder;
+  // Ensures the media element remains alive to dispatch progress and
+  // durationchanged events.
+  nsRefPtr<HTMLMediaElement> mMediaElement;
 
   nsRefPtr<nsIPrincipal> mPrincipal;
 
   MediaSourceReadyState mReadyState;
 
   bool mFirstSourceBufferInitialized;
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/dataChannel.js
@@ -0,0 +1,230 @@
+/* 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/. */
+
+function addInitialDataChannel(chain) {
+  chain.insertBefore('PC_LOCAL_CREATE_OFFER', [
+    ['PC_LOCAL_CREATE_DATA_CHANNEL',
+      function (test) {
+        var channel = test.pcLocal.createDataChannel({});
+
+        is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
+        is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
+
+        is(test.pcLocal.signalingState, STABLE,
+           "Create datachannel does not change signaling state");
+
+        test.next();
+      }
+    ]
+  ]);
+  chain.insertAfter('PC_REMOTE_CREATE_ANSWER', [
+    [
+      'PC_LOCAL_SETUP_DATA_CHANNEL_CALLBACK',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcLocal, function () {
+          ok(true, test.pcLocal + " dataChannels[0] switched to 'open'");
+        },
+        // At this point a timeout failure will be of no value
+        null);
+        test.next();
+      }
+    ],
+    [
+      'PC_REMOTE_SETUP_DATA_CHANNEL_CALLBACK',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcRemote, function () {
+          ok(true, test.pcRemote + " dataChannels[0] switched to 'open'");
+        },
+        // At this point a timeout failure will be of no value
+        null);
+        test.next();
+      }
+    ]
+  ]);
+  chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS', [
+    [
+      'PC_LOCAL_VERIFY_DATA_CHANNEL_STATE',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcLocal, function() {
+          test.next();
+        }, function() {
+          ok(false, test.pcLocal + " initial dataChannels[0] failed to switch to 'open'");
+          //TODO: use stopAndExit() once bug 1019323 has landed
+          unexpectedEventAndFinish(this, 'timeout')
+          // to prevent test framework timeouts
+          test.next();
+        });
+      }
+    ],
+    [
+      'PC_REMOTE_VERIFY_DATA_CHANNEL_STATE',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcRemote, function() {
+          test.next();
+        }, function() {
+          ok(false, test.pcRemote + " initial dataChannels[0] failed to switch to 'open'");
+          //TODO: use stopAndExit() once bug 1019323 has landed
+          unexpectedEventAndFinish(this, 'timeout');
+          // to prevent test framework timeouts
+          test.next();
+        });
+      }
+    ]
+  ]);
+  chain.removeAfter('PC_REMOTE_CHECK_ICE_CONNECTIONS');
+  chain.append([
+    [
+      'SEND_MESSAGE',
+      function (test) {
+        var message = "Lorem ipsum dolor sit amet";
+
+        test.send(message, function (channel, data) {
+          is(data, message, "Message correctly transmitted from pcLocal to pcRemote.");
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_BLOB',
+      function (test) {
+        var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
+        var blob = new Blob(contents, { "type" : "text/plain" });
+
+        test.send(blob, function (channel, data) {
+          ok(data instanceof Blob, "Received data is of instance Blob");
+          is(data.size, blob.size, "Received data has the correct size.");
+
+          getBlobContent(data, function (recv_contents) {
+            is(recv_contents, contents, "Received data has the correct content.");
+
+            test.next();
+          });
+        });
+      }
+    ],
+    [
+      'CREATE_SECOND_DATA_CHANNEL',
+      function (test) {
+        test.createDataChannel({ }, function (sourceChannel, targetChannel) {
+          is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
+          is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
+
+          is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
+          is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL',
+      function (test) {
+        var channels = test.pcRemote.dataChannels;
+        var message = "Lorem ipsum dolor sit amet";
+
+        test.send(message, function (channel, data) {
+          is(channels.indexOf(channel), channels.length - 1, "Last channel used");
+          is(data, message, "Received message has the correct content.");
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_MESSAGE_THROUGH_FIRST_CHANNEL',
+      function (test) {
+        var message = "Message through 1st channel";
+        var options = {
+          sourceChannel: test.pcLocal.dataChannels[0],
+          targetChannel: test.pcRemote.dataChannels[0]
+        };
+
+        test.send(message, function (channel, data) {
+          is(test.pcRemote.dataChannels.indexOf(channel), 0, "1st channel used");
+          is(data, message, "Received message has the correct content.");
+
+          test.next();
+        }, options);
+      }
+    ],
+    [
+      'SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL',
+      function (test) {
+        var message = "Return a message also through 1st channel";
+        var options = {
+          sourceChannel: test.pcRemote.dataChannels[0],
+          targetChannel: test.pcLocal.dataChannels[0]
+        };
+
+        test.send(message, function (channel, data) {
+          is(test.pcLocal.dataChannels.indexOf(channel), 0, "1st channel used");
+          is(data, message, "Return message has the correct content.");
+
+          test.next();
+        }, options);
+      }
+    ],
+    [
+      'CREATE_NEGOTIATED_DATA_CHANNEL',
+      function (test) {
+        var options = {negotiated:true, id: 5, protocol:"foo/bar", ordered:false,
+          maxRetransmits:500};
+        test.createDataChannel(options, function (sourceChannel2, targetChannel2) {
+          is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
+          is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
+
+          is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
+          is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
+
+          if (options.id != undefined) {
+            is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
+          }
+          else {
+            options.id = sourceChannel2.id;
+          }
+          var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
+          is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
+          is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
+  /*
+    These aren't exposed by IDL yet
+          is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
+          is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
+       sourceChannel2.maxRetransmits);
+          is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
+       sourceChannel2.maxRetransmitTime);
+  */
+
+          is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
+          is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
+          is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
+  /*
+    These aren't exposed by IDL yet
+         is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
+          is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
+       targetChannel2.maxRetransmits);
+          is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
+       targetChannel2.maxRetransmitTime);
+  */
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2',
+      function (test) {
+        var channels = test.pcRemote.dataChannels;
+        var message = "Lorem ipsum dolor sit amet";
+
+        test.send(message, function (channel, data) {
+          is(channels.indexOf(channel), channels.length - 1, "Last channel used");
+          is(data, message, "Received message has the correct content.");
+
+          test.next();
+        });
+      }
+    ]
+  ]);
+}
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 # strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
 skip-if = (os == 'win' && strictContentSandbox) || android_version == '10'
 support-files =
   head.js
   constraints.js
+  dataChannel.js
   mediaStreamPlayback.js
   nonTrickleIce.js
   pc.js
   templates.js
   NetworkPreparationChromeScript.js
   blacksilence.js
   turnConfig.js
 
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -579,17 +579,17 @@ function PeerConnectionTest(options) {
 }
 
 /**
  * Closes the peer connection if it is active
  *
  * @param {Function} onSuccess
  *        Callback to execute when the peer connection has been closed successfully
  */
-PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
+PeerConnectionTest.prototype.closePC = function PCT_closePC(onSuccess) {
   info("Closing peer connections");
 
   var self = this;
   var closeTimeout = null;
   var waitingForLocal = false;
   var waitingForRemote = false;
   var everythingClosed = false;
 
@@ -651,16 +651,326 @@ PeerConnectionTest.prototype.close = fun
     // it is not a success, but the show must go on
     onSuccess();
   }, 60000);
 
   closeEverything();
 };
 
 /**
+ * Close the open data channels, followed by the underlying peer connection
+ *
+ * @param {Function} onSuccess
+ *        Callback to execute when all connections have been closed
+ */
+PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
+  var self = this;
+  var pendingDcClose = []
+  var closeTimeout = null;
+
+  info("PeerConnectionTest.close() called");
+
+  function _closePeerConnection() {
+    info("Now closing PeerConnection");
+    self.closePC.call(self, onSuccess);
+  }
+
+  function _closePeerConnectionCallback(index) {
+    info("_closePeerConnection called with index " + index);
+    var pos = pendingDcClose.indexOf(index);
+    if (pos != -1) {
+      pendingDcClose.splice(pos, 1);
+    }
+    else {
+      info("_closePeerConnection index " + index + " is missing from pendingDcClose: " + pendingDcClose);
+    }
+    if (pendingDcClose.length === 0) {
+      clearTimeout(closeTimeout);
+      _closePeerConnection();
+    }
+  }
+
+  var myDataChannels = null;
+  if (self.pcLocal) {
+    myDataChannels = self.pcLocal.dataChannels;
+  }
+  else if (self.pcRemote) {
+    myDataChannels = self.pcRemote.dataChannels;
+  }
+  var length = myDataChannels.length;
+  for (var i = 0; i < length; i++) {
+    var dataChannel = myDataChannels[i];
+    if (dataChannel.readyState !== "closed") {
+      pendingDcClose.push(i);
+      self.closeDataChannels(i, _closePeerConnectionCallback);
+    }
+  }
+  if (pendingDcClose.length === 0) {
+    _closePeerConnection();
+  }
+  else {
+    closeTimeout = setTimeout(function() {
+      ok(false, "Failed to properly close data channels: " +
+        pendingDcClose);
+      _closePeerConnection();
+    }, 60000);
+  }
+};
+
+/**
+ * Close the specified data channels
+ *
+ * @param {Number} index
+ *        Index of the data channels to close on both sides
+ * @param {Function} onSuccess
+ *        Callback to execute when the data channels has been closed
+ */
+PeerConnectionTest.prototype.closeDataChannels = function PCT_closeDataChannels(index, onSuccess) {
+  info("closeDataChannels called with index: " + index);
+  var localChannel = null;
+  if (this.pcLocal) {
+    localChannel = this.pcLocal.dataChannels[index];
+  }
+  var remoteChannel = null;
+  if (this.pcRemote) {
+    remoteChannel = this.pcRemote.dataChannels[index];
+  }
+
+  var self = this;
+  var wait = false;
+  var pollingMode = false;
+  var everythingClosed = false;
+  var verifyInterval = null;
+  var remoteCloseTimer = null;
+
+  function _allChannelsAreClosed() {
+    var ret = null;
+    if (localChannel) {
+      ret = (localChannel.readyState === "closed");
+    }
+    if (remoteChannel) {
+      if (ret !== null) {
+        ret = (ret && (remoteChannel.readyState === "closed"));
+      }
+      else {
+        ret = (remoteChannel.readyState === "closed");
+      }
+    }
+    return ret;
+  }
+
+  function verifyClosedChannels() {
+    if (everythingClosed) {
+      // safety protection against events firing late
+      return;
+    }
+    if (_allChannelsAreClosed()) {
+      ok(true, "DataChannel(s) have reached 'closed' state for data channel " + index);
+      if (remoteCloseTimer !== null) {
+        clearTimeout(remoteCloseTimer);
+      }
+      if (verifyInterval !== null) {
+        clearInterval(verifyInterval);
+      }
+      everythingClosed = true;
+      onSuccess(index);
+    }
+    else {
+      info("Still waiting for DataChannel closure");
+    }
+  }
+
+  if ((localChannel) && (localChannel.readyState !== "closed")) {
+    // in case of steeplechase there is no far end, so we can only poll
+    if (remoteChannel) {
+      remoteChannel.onclose = function () {
+        is(remoteChannel.readyState, "closed", "remoteChannel is in state 'closed'");
+        verifyClosedChannels();
+      };
+    }
+    else {
+      pollingMode = true;
+      verifyInterval = setInterval(verifyClosedChannels, 1000);
+    }
+
+    localChannel.close();
+    wait = true;
+  }
+  if ((remoteChannel) && (remoteChannel.readyState !== "closed")) {
+    if (localChannel) {
+      localChannel.onclose = function () {
+        is(localChannel.readyState, "closed", "localChannel is in state 'closed'");
+        verifyClosedChannels();
+      };
+
+      // Apparently we are running a local test which has both ends of the
+      // data channel locally available, so by default lets wait for the
+      // remoteChannel.onclose handler from above to confirm closure on both
+      // ends.
+      remoteCloseTimer = setTimeout(function() {
+        todo(false, "localChannel.close() did not resulted in close signal on remote side");
+        remoteChannel.close();
+        verifyClosedChannels();
+      }, 30000);
+    }
+    else {
+      pollingMode = true;
+      verifyTimer = setInterval(verifyClosedChannels, 1000);
+
+      remoteChannel.close();
+    }
+
+    wait = true;
+  }
+
+  if (!wait) {
+    onSuccess(index);
+  }
+};
+
+
+/**
+ * Wait for the initial data channel to get into the open state
+ *
+ * @param {PeerConnectionWrapper} peer
+ *        The peer connection wrapper to run the command on
+ * @param {Function} onSuccess
+ *        Callback when the creation was successful
+ */
+PeerConnectionTest.prototype.waitForInitialDataChannel =
+        function PCT_waitForInitialDataChannel(peer, onSuccess, onFailure) {
+  var dcConnectionTimeout = null;
+  var dcOpened = false;
+
+  function dataChannelConnected(channel) {
+    // in case the switch statement below had called onSuccess already we
+    // don't want to call it again
+    if (!dcOpened) {
+      clearTimeout(dcConnectionTimeout);
+      is(channel.readyState, "open", peer + " dataChannels[0] switched to state: 'open'");
+      dcOpened = true;
+      onSuccess();
+    } else {
+      info("dataChannelConnected() called, but data channel was open already");
+    }
+  }
+
+  // TODO: drno: convert dataChannels into an object and make
+  //             registerDataChannelOpenEvent a generic function
+  if (peer == this.pcLocal) {
+    peer.dataChannels[0].onopen = dataChannelConnected;
+  } else {
+    peer.registerDataChannelOpenEvents(dataChannelConnected);
+  }
+
+  if (peer.dataChannels.length >= 1) {
+    // snapshot of the live value as it might change during test execution
+    const readyState = peer.dataChannels[0].readyState;
+    switch (readyState) {
+      case "open": {
+        is(readyState, "open", peer + " dataChannels[0] is already in state: 'open'");
+        dcOpened = true;
+        onSuccess();
+        break;
+      }
+      case "connecting": {
+        is(readyState, "connecting", peer + " dataChannels[0] is in state: 'connecting'");
+        if (onFailure) {
+          dcConnectionTimeout = setTimeout(function () {
+            is(peer.dataChannels[0].readyState, "open", peer + " timed out while waiting for dataChannels[0] to open");
+            onFailure();
+          }, 60000);
+        }
+        break;
+      }
+      default: {
+        ok(false, "dataChannels[0] is in unexpected state " + readyState);
+        if (onFailure) {
+          onFailure()
+        }
+      }
+    }
+  }
+};
+
+/**
+ * Send data (message or blob) to the other peer
+ *
+ * @param {String|Blob} data
+ *        Data to send to the other peer. For Blobs the MIME type will be lost.
+ * @param {Function} onSuccess
+ *        Callback to execute when data has been sent
+ * @param {Object} [options={ }]
+ *        Options to specify the data channels to be used
+ * @param {DataChannelWrapper} [options.sourceChannel=pcLocal.dataChannels[length - 1]]
+ *        Data channel to use for sending the message
+ * @param {DataChannelWrapper} [options.targetChannel=pcRemote.dataChannels[length - 1]]
+ *        Data channel to use for receiving the message
+ */
+PeerConnectionTest.prototype.send = function PCT_send(data, onSuccess, options) {
+  options = options || { };
+  var source = options.sourceChannel ||
+           this.pcLocal.dataChannels[this.pcLocal.dataChannels.length - 1];
+  var target = options.targetChannel ||
+           this.pcRemote.dataChannels[this.pcRemote.dataChannels.length - 1];
+
+  // Register event handler for the target channel
+  target.onmessage = function (recv_data) {
+    onSuccess(target, recv_data);
+  };
+
+  source.send(data);
+};
+
+/**
+ * Create a data channel
+ *
+ * @param {Dict} options
+ *        Options for the data channel (see nsIPeerConnection)
+ * @param {Function} onSuccess
+ *        Callback when the creation was successful
+ */
+PeerConnectionTest.prototype.createDataChannel = function DCT_createDataChannel(options, onSuccess) {
+  var localChannel = null;
+  var remoteChannel = null;
+  var self = this;
+
+  // Method to synchronize all asynchronous events.
+  function check_next_test() {
+    if (localChannel && remoteChannel) {
+      onSuccess(localChannel, remoteChannel);
+    }
+  }
+
+  if (!options.negotiated) {
+    // Register handlers for the remote peer
+    this.pcRemote.registerDataChannelOpenEvents(function (channel) {
+      remoteChannel = channel;
+      check_next_test();
+    });
+  }
+
+  // Create the datachannel and handle the local 'onopen' event
+  this.pcLocal.createDataChannel(options, function (channel) {
+    localChannel = channel;
+
+    if (options.negotiated) {
+      // externally negotiated - we need to open from both ends
+      options.id = options.id || channel.id;  // allow for no id to let the impl choose
+      self.pcRemote.createDataChannel(options, function (channel) {
+        remoteChannel = channel;
+        check_next_test();
+      });
+    } else {
+      check_next_test();
+    }
+  });
+};
+
+/**
  * Executes the next command.
  */
 PeerConnectionTest.prototype.next = function PCT_next() {
   if (this._stepTimeout) {
     clearTimeout(this._stepTimeout);
     this._stepTimeout = null;
   }
   this.chain.executeNext();
@@ -990,382 +1300,16 @@ PCT_getSignalingMessage(messageType, onM
       info("invoking callback on message " + i + " from message queue, for message type:" + messageType);
       onMessage(this.signalingMessageQueue.splice(i, 1)[0]);
       return;
     }
   }
   this.registerSignalingCallback(messageType, onMessage);
 }
 
-/**
- * This class handles tests for data channels.
- *
- * @constructor
- * @param {object} [options={}]
- *        Optional options for the peer connection test
- * @param {object} [options.commands=commandsDataChannel]
- *        Commands to run for the test
- * @param {object} [options.config_local=undefined]
- *        Configuration for the local peer connection instance
- * @param {object} [options.config_remote=undefined]
- *        Configuration for the remote peer connection instance. If not defined
- *        the configuration from the local instance will be used
- */
-function DataChannelTest(options) {
-  options = options || { };
-  options.commands = options.commands || commandsDataChannel;
-
-  PeerConnectionTest.call(this, options);
-}
-
-DataChannelTest.prototype = Object.create(PeerConnectionTest.prototype, {
-  close : {
-    /**
-     * Close the open data channels, followed by the underlying peer connection
-     *
-     * @param {Function} onSuccess
-     *        Callback to execute when all connections have been closed
-     */
-    value : function DCT_close(onSuccess) {
-      var self = this;
-      var pendingDcClose = []
-      var closeTimeout = null;
-
-      info("DataChannelTest.close() called");
-
-      function _closePeerConnection() {
-        info("DataChannelTest closing PeerConnection");
-        PeerConnectionTest.prototype.close.call(self, onSuccess);
-      }
-
-      function _closePeerConnectionCallback(index) {
-        info("_closePeerConnection called with index " + index);
-        var pos = pendingDcClose.indexOf(index);
-        if (pos != -1) {
-          pendingDcClose.splice(pos, 1);
-        }
-        else {
-          info("_closePeerConnection index " + index + " is missing from pendingDcClose: " + pendingDcClose);
-        }
-        if (pendingDcClose.length === 0) {
-          clearTimeout(closeTimeout);
-          _closePeerConnection();
-        }
-      }
-
-      var myDataChannels = null;
-      if (self.pcLocal) {
-        myDataChannels = self.pcLocal.dataChannels;
-      }
-      else if (self.pcRemote) {
-        myDataChannels = self.pcRemote.dataChannels;
-      }
-      var length = myDataChannels.length;
-      for (var i = 0; i < length; i++) {
-        var dataChannel = myDataChannels[i];
-        if (dataChannel.readyState !== "closed") {
-          pendingDcClose.push(i);
-          self.closeDataChannels(i, _closePeerConnectionCallback);
-        }
-      }
-      if (pendingDcClose.length === 0) {
-        _closePeerConnection();
-      }
-      else {
-        closeTimeout = setTimeout(function() {
-          ok(false, "Failed to properly close data channels: " +
-            pendingDcClose);
-          _closePeerConnection();
-        }, 60000);
-      }
-    }
-  },
-
-  closeDataChannels : {
-    /**
-     * Close the specified data channels
-     *
-     * @param {Number} index
-     *        Index of the data channels to close on both sides
-     * @param {Function} onSuccess
-     *        Callback to execute when the data channels has been closed
-     */
-    value : function DCT_closeDataChannels(index, onSuccess) {
-      info("_closeDataChannels called with index: " + index);
-      var localChannel = null;
-      if (this.pcLocal) {
-        localChannel = this.pcLocal.dataChannels[index];
-      }
-      var remoteChannel = null;
-      if (this.pcRemote) {
-        remoteChannel = this.pcRemote.dataChannels[index];
-      }
-
-      var self = this;
-      var wait = false;
-      var pollingMode = false;
-      var everythingClosed = false;
-      var verifyInterval = null;
-      var remoteCloseTimer = null;
-
-      function _allChannelsAreClosed() {
-        var ret = null;
-        if (localChannel) {
-          ret = (localChannel.readyState === "closed");
-        }
-        if (remoteChannel) {
-          if (ret !== null) {
-            ret = (ret && (remoteChannel.readyState === "closed"));
-          }
-          else {
-            ret = (remoteChannel.readyState === "closed");
-          }
-        }
-        return ret;
-      }
-
-      function verifyClosedChannels() {
-        if (everythingClosed) {
-          // safety protection against events firing late
-          return;
-        }
-        if (_allChannelsAreClosed) {
-          ok(true, "DataChannel(s) have reached 'closed' state for data channel " + index);
-          if (remoteCloseTimer !== null) {
-            clearTimeout(remoteCloseTimer);
-          }
-          if (verifyInterval !== null) {
-            clearInterval(verifyInterval);
-          }
-          everythingClosed = true;
-          onSuccess(index);
-        }
-        else {
-          info("Still waiting for DataChannel closure");
-        }
-      }
-
-      if ((localChannel) && (localChannel.readyState !== "closed")) {
-        // in case of steeplechase there is no far end, so we can only poll
-        if (remoteChannel) {
-          remoteChannel.onclose = function () {
-            is(remoteChannel.readyState, "closed", "remoteChannel is in state 'closed'");
-            verifyClosedChannels();
-          };
-        }
-        else {
-          pollingMode = true;
-          verifyInterval = setInterval(verifyClosedChannels, 1000);
-        }
-
-        localChannel.close();
-        wait = true;
-      }
-      if ((remoteChannel) && (remoteChannel.readyState !== "closed")) {
-        if (localChannel) {
-          localChannel.onclose = function () {
-            is(localChannel.readyState, "closed", "localChannel is in state 'closed'");
-            verifyClosedChannels();
-          };
-
-          // Apparently we are running a local test which has both ends of the
-          // data channel locally available, so by default lets wait for the
-          // remoteChannel.onclose handler from above to confirm closure on both
-          // ends.
-          remoteCloseTimer = setTimeout(function() {
-            todo(false, "localChannel.close() did not resulted in close signal on remote side");
-            remoteChannel.close();
-            verifyClosedChannels();
-          }, 30000);
-        }
-        else {
-          pollingMode = true;
-          verifyTimer = setInterval(verifyClosedChannels, 1000);
-
-          remoteChannel.close();
-        }
-
-        wait = true;
-      }
-
-      if (!wait) {
-        onSuccess(index);
-      }
-    }
-  },
-
-  createDataChannel : {
-    /**
-     * Create a data channel
-     *
-     * @param {Dict} options
-     *        Options for the data channel (see nsIPeerConnection)
-     * @param {Function} onSuccess
-     *        Callback when the creation was successful
-     */
-    value : function DCT_createDataChannel(options, onSuccess) {
-      var localChannel = null;
-      var remoteChannel = null;
-      var self = this;
-
-      // Method to synchronize all asynchronous events.
-      function check_next_test() {
-        if (localChannel && remoteChannel) {
-          onSuccess(localChannel, remoteChannel);
-        }
-      }
-
-      if (!options.negotiated) {
-        // Register handlers for the remote peer
-        this.pcRemote.registerDataChannelOpenEvents(function (channel) {
-          remoteChannel = channel;
-          check_next_test();
-        });
-      }
-
-      // Create the datachannel and handle the local 'onopen' event
-      this.pcLocal.createDataChannel(options, function (channel) {
-        localChannel = channel;
-
-        if (options.negotiated) {
-          // externally negotiated - we need to open from both ends
-          options.id = options.id || channel.id;  // allow for no id to let the impl choose
-          self.pcRemote.createDataChannel(options, function (channel) {
-            remoteChannel = channel;
-            check_next_test();
-          });
-        } else {
-          check_next_test();
-        }
-      });
-    }
-  },
-
-  send : {
-    /**
-     * Send data (message or blob) to the other peer
-     *
-     * @param {String|Blob} data
-     *        Data to send to the other peer. For Blobs the MIME type will be lost.
-     * @param {Function} onSuccess
-     *        Callback to execute when data has been sent
-     * @param {Object} [options={ }]
-     *        Options to specify the data channels to be used
-     * @param {DataChannelWrapper} [options.sourceChannel=pcLocal.dataChannels[length - 1]]
-     *        Data channel to use for sending the message
-     * @param {DataChannelWrapper} [options.targetChannel=pcRemote.dataChannels[length - 1]]
-     *        Data channel to use for receiving the message
-     */
-    value : function DCT_send(data, onSuccess, options) {
-      options = options || { };
-      var source = options.sourceChannel ||
-               this.pcLocal.dataChannels[this.pcLocal.dataChannels.length - 1];
-      var target = options.targetChannel ||
-               this.pcRemote.dataChannels[this.pcRemote.dataChannels.length - 1];
-
-      // Register event handler for the target channel
-      target.onmessage = function (recv_data) {
-        onSuccess(target, recv_data);
-      };
-
-      source.send(data);
-    }
-  },
-
-  createOffer : {
-    value : function DCT_createOffer(peer, onSuccess) {
-      PeerConnectionTest.prototype.createOffer.call(this, peer, onSuccess);
-    }
-  },
-
-  setLocalDescription : {
-    /**
-     * Sets the local description for the specified peer connection instance
-     * and automatically handles the failure case.
-     *
-     * @param {PeerConnectionWrapper} peer
-              The peer connection wrapper to run the command on
-     * @param {mozRTCSessionDescription} desc
-     *        Session description for the local description request
-     * @param {function} onSuccess
-     *        Callback to execute if the local description was set successfully
-     */
-    value : function DCT_setLocalDescription(peer, desc, state, onSuccess) {
-      PeerConnectionTest.prototype.setLocalDescription.call(this, peer,
-                                                              desc, state, onSuccess);
-
-    }
-  },
-
-  waitForInitialDataChannel : {
-    /**
-     * Wait for the initial data channel to get into the open state
-     *
-     * @param {PeerConnectionWrapper} peer
-     *        The peer connection wrapper to run the command on
-     * @param {Function} onSuccess
-     *        Callback when the creation was successful
-     */
-    value : function DCT_waitForInitialDataChannel(peer, onSuccess, onFailure) {
-      var dcConnectionTimeout = null;
-      var dcOpened = false;
-
-      function dataChannelConnected(channel) {
-        // in case the switch statement below had called onSuccess already we
-        // don't want to call it again
-        if (!dcOpened) {
-          clearTimeout(dcConnectionTimeout);
-          is(channel.readyState, "open", peer + " dataChannels[0] switched to state: 'open'");
-          dcOpened = true;
-          onSuccess();
-        } else {
-          info("dataChannelConnected() called, but data channel was open already");
-        }
-      }
-
-      // TODO: drno: convert dataChannels into an object and make
-      //             registerDataChannelOpenEvent a generic function
-      if (peer == this.pcLocal) {
-        peer.dataChannels[0].onopen = dataChannelConnected;
-      } else {
-        peer.registerDataChannelOpenEvents(dataChannelConnected);
-      }
-
-      if (peer.dataChannels.length >= 1) {
-        // snapshot of the live value as it might change during test execution
-        const readyState = peer.dataChannels[0].readyState;
-        switch (readyState) {
-          case "open": {
-            is(readyState, "open", peer + " dataChannels[0] is already in state: 'open'");
-            dcOpened = true;
-            onSuccess();
-            break;
-          }
-          case "connecting": {
-            is(readyState, "connecting", peer + " dataChannels[0] is in state: 'connecting'");
-            if (onFailure) {
-              dcConnectionTimeout = setTimeout(function () {
-                is(peer.dataChannels[0].readyState, "open", peer + " timed out while waiting for dataChannels[0] to open");
-                onFailure();
-              }, 60000);
-            }
-            break;
-          }
-          default: {
-            ok(false, "dataChannels[0] is in unexpected state " + readyState);
-            if (onFailure) {
-              onFailure()
-            }
-          }
-        }
-      }
-    }
-  }
-
-});
 
 /**
  * This class acts as a wrapper around a DataChannel instance.
  *
  * @param dataChannel
  * @param peerConnectionWrapper
  * @constructor
  */
@@ -2569,27 +2513,28 @@ PeerConnectionWrapper.prototype = {
         if (!res.isRemote) {
           counters2[res.type] = toNum(counters2[res.type]) + 1;
         }
       });
     is(JSON.stringify(counters), JSON.stringify(counters2),
        "Spec and MapClass variant of RTCStatsReport enumeration agree");
     var nin = numTracks(this._pc.getRemoteStreams());
     var nout = numTracks(this._pc.getLocalStreams());
+    var ndata = this.dataChannels.length;
 
     // TODO(Bug 957145): Restore stronger inboundrtp test once Bug 948249 is fixed
     //is(toNum(counters["inboundrtp"]), nin, "Have " + nin + " inboundrtp stat(s)");
     ok(toNum(counters.inboundrtp) >= nin, "Have at least " + nin + " inboundrtp stat(s) *");
 
     is(toNum(counters.outboundrtp), nout, "Have " + nout + " outboundrtp stat(s)");
 
     var numLocalCandidates  = toNum(counters.localcandidate);
     var numRemoteCandidates = toNum(counters.remotecandidate);
     // If there are no tracks, there will be no stats either.
-    if (nin + nout > 0) {
+    if (nin + nout + ndata > 0) {
       ok(numLocalCandidates, "Have localcandidate stat(s)");
       ok(numRemoteCandidates, "Have remotecandidate stat(s)");
     } else {
       is(numLocalCandidates, 0, "Have no localcandidate stats");
       is(numRemoteCandidates, 0, "Have no remotecandidate stats");
     }
   },
 
@@ -2643,17 +2588,17 @@ PeerConnectionWrapper.prototype = {
    * @param {object} stats
    *        The stats to check for ICE candidate pairs
    * @param {object} counters
    *        The counters for media and data tracks based on constraints
    * @param {object} answer
    *        The SDP answer to check for SDP bundle support
    */
   checkStatsIceConnections : function PCW_checkStatsIceConnections(stats,
-      offerConstraintsList, offerOptions, numDataTracks, answer) {
+      offerConstraintsList, offerOptions, answer) {
     var numIceConnections = 0;
     Object.keys(stats).forEach(function(key) {
       if ((stats[key].type === "candidatepair") && stats[key].selected) {
         numIceConnections += 1;
       }
     });
     info("ICE connections according to stats: " + numIceConnections);
     if (answer.sdp.contains('a=group:BUNDLE')) {
@@ -2664,16 +2609,18 @@ PeerConnectionWrapper.prototype = {
       var numAudioTracks =
         this.countAudioTracksInMediaConstraint(offerConstraintsList) ||
         this.audioInOfferOptions(offerOptions);
 
       var numVideoTracks =
         this.countVideoTracksInMediaConstraint(offerConstraintsList) ||
         this.videoInOfferOptions(offerOptions);
 
+      var numDataTracks = this.dataChannels.length;
+
       var numAudioVideoDataTracks = numAudioTracks + numVideoTracks + numDataTracks;
       info("expected audio + video + data tracks: " + numAudioVideoDataTracks);
       is(numAudioVideoDataTracks, numIceConnections, "stats ICE connections matches expected A/V tracks");
     }
   },
 
   /**
    * Property-matching function for finding a certain stat in passed-in stats
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -530,30 +530,28 @@ var commandsPeerConnection = [
   ],
   [
     'PC_LOCAL_CHECK_ICE_CONNECTIONS',
     function (test) {
       test.pcLocal.getStats(null, function(stats) {
         test.pcLocal.checkStatsIceConnections(stats,
                                               test._offer_constraints,
                                               test._offer_options,
-                                              0,
                                               test.originalAnswer);
         test.next();
       });
     }
   ],
   [
     'PC_REMOTE_CHECK_ICE_CONNECTIONS',
     function (test) {
       test.pcRemote.getStats(null, function(stats) {
         test.pcRemote.checkStatsIceConnections(stats,
                                                test._offer_constraints,
                                                test._offer_options,
-                                               0,
                                                test.originalAnswer);
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
     function (test) {
@@ -719,631 +717,8 @@ var commandsPeerConnection = [
         });
       } else {
         test.next();
       }
     }
   ]
 ];
 
-
-/**
- * Default list of commands to execute for a Datachannel test.
- */
-var commandsDataChannel = [
-  [
-    'PC_LOCAL_SETUP_ICE_LOGGER',
-    function (test) {
-      test.pcLocal.logIceConnectionState();
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_ICE_LOGGER',
-    function (test) {
-      test.pcRemote.logIceConnectionState();
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SETUP_SIGNALING_LOGGER',
-    function (test) {
-      test.pcLocal.logSignalingState();
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_SIGNALING_LOGGER',
-    function (test) {
-      test.pcRemote.logSignalingState();
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_GUM',
-    function (test) {
-      test.pcLocal.getAllUserMedia(test.pcLocal.constraints, function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_INITIAL_SIGNALINGSTATE',
-    function (test) {
-      is(test.pcLocal.signalingState, STABLE,
-         "Initial local signalingState is stable");
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_INITIAL_ICE_STATE',
-    function (test) {
-      is(test.pcLocal.iceConnectionState, ICE_NEW,
-        "Initial local ICE connection state is 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_GUM',
-    function (test) {
-      test.pcRemote.getAllUserMedia(test.pcRemote.constraints, function () {
-      test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_INITIAL_SIGNALINGSTATE',
-    function (test) {
-      is(test.pcRemote.signalingState, STABLE,
-         "Initial remote signalingState is stable");
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_INITIAL_ICE_STATE',
-    function (test) {
-      is(test.pcRemote.iceConnectionState, ICE_NEW,
-        "Initial remote ICE connection state is 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SETUP_ICE_HANDLER',
-    function (test) {
-      test.pcLocal.setupIceCandidateHandler(test);
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_ICE_HANDLER',
-    function (test) {
-      test.pcRemote.setupIceCandidateHandler(test);
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_CREATE_DATA_CHANNEL',
-    function (test) {
-      var channel = test.pcLocal.createDataChannel({});
-
-      is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
-      is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
-
-      is(test.pcLocal.signalingState, STABLE,
-         "Create datachannel does not change signaling state");
-
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_CREATE_OFFER',
-    function (test) {
-      test.createOffer(test.pcLocal, function (offer) {
-        is(test.pcLocal.signalingState, STABLE,
-           "Local create offer does not change signaling state");
-        ok(offer.sdp.contains("m=application"),
-           "m=application is contained in the SDP");
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_STEEPLECHASE_SIGNAL_OFFER',
-    function (test) {
-      if (test.steeplechase) {
-        send_message({"type": "offer",
-          "offer": test.originalOffer,
-          "offer_constraints": test.pcLocal.constraints,
-          "offer_options": test.pcLocal.offerOptions});
-        test._local_offer = test.originalOffer;
-        test._offer_constraints = test.pcLocal.constraints;
-        test._offer_options = test.pcLocal.offerOptions;
-      }
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SET_LOCAL_DESCRIPTION',
-    function (test) {
-      test.setLocalDescription(test.pcLocal, test.originalOffer, HAVE_LOCAL_OFFER,
-        function () {
-        is(test.pcLocal.signalingState, HAVE_LOCAL_OFFER,
-           "signalingState after local setLocalDescription is 'have-local-offer'");
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_GET_OFFER',
-    function (test) {
-      if (!test.steeplechase) {
-        test._local_offer = test.originalOffer;
-        test._offer_constraints = test.pcLocal.constraints;
-        test._offer_options = test.pcLocal.offerOptions;
-        test.next();
-      } else {
-        test.getSignalingMessage("offer", function (message) {
-          ok("offer" in message, "Got an offer message");
-          test._local_offer = new mozRTCSessionDescription(message.offer);
-          test._offer_constraints = message.offer_constraints;
-          test._offer_options = message.offer_options;
-          test.next();
-        });
-      }
-    }
-  ],
-  [
-    'PC_REMOTE_SET_REMOTE_DESCRIPTION',
-    function (test) {
-      test.setRemoteDescription(test.pcRemote, test._local_offer, HAVE_REMOTE_OFFER,
-        function () {
-        is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
-           "signalingState after remote setRemoteDescription is 'have-remote-offer'");
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_SANE_LOCAL_SDP',
-    function (test) {
-      test.pcLocal.verifySdp(test._local_offer, "offer",
-        test._offer_constraints, test._offer_options,
-        function(trickle) {
-          test.pcLocal.localRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SANE_REMOTE_SDP',
-    function (test) {
-      test.pcRemote.verifySdp(test._local_offer, "offer",
-        test._offer_constraints, test._offer_options,
-        function (trickle) {
-          test.pcRemote.remoteRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_CREATE_ANSWER',
-    function (test) {
-      test.createAnswer(test.pcRemote, function (answer) {
-        is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
-           "Remote createAnswer does not change signaling state");
-        ok(answer.sdp.contains("m=application"),
-           "m=application is contained in the SDP");
-        if (test.steeplechase) {
-          send_message({"type":"answer",
-                        "answer": test.originalAnswer,
-                        "answer_constraints": test.pcRemote.constraints});
-          test._remote_answer = test.pcRemote._last_answer;
-          test._answer_constraints = test.pcRemote.constraints;
-        }
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_SETUP_DATA_CHANNEL_CALLBACK',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcLocal, function () {
-        ok(true, test.pcLocal + " dataChannels[0] switched to 'open'");
-      },
-      // At this point a timeout failure will be of no value
-      null);
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_DATA_CHANNEL_CALLBACK',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcRemote, function () {
-        ok(true, test.pcRemote + " dataChannels[0] switched to 'open'");
-      },
-      // At this point a timeout failure will be of no value
-      null);
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SET_LOCAL_DESCRIPTION',
-    function (test) {
-      test.setLocalDescription(test.pcRemote, test.originalAnswer, STABLE,
-        function () {
-          is(test.pcRemote.signalingState, STABLE,
-            "signalingState after remote setLocalDescription is 'stable'");
-          test.next();
-        }
-      );
-    }
-  ],
-  [
-    'PC_LOCAL_GET_ANSWER',
-    function (test) {
-      if (!test.steeplechase) {
-        test._remote_answer = test.originalAnswer;
-        test._answer_constraints = test.pcRemote.constraints;
-        test.next();
-      } else {
-        test.getSignalingMessage("answer", function (message) {
-          ok("answer" in message, "Got an answer message");
-          test._remote_answer = new mozRTCSessionDescription(message.answer);
-          test._answer_constraints = message.answer_constraints;
-          test.next();
-        });
-      }
-    }
-  ],
-  [
-    'PC_LOCAL_SET_REMOTE_DESCRIPTION',
-    function (test) {
-      test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE,
-        function () {
-          is(test.pcLocal.signalingState, STABLE,
-            "signalingState after local setRemoteDescription is 'stable'");
-          test.next();
-        }
-      );
-    }
-  ],
-  [
-    'PC_REMOTE_SANE_LOCAL_SDP',
-    function (test) {
-      test.pcRemote.verifySdp(test._remote_answer, "answer",
-        test._offer_constraints, test._offer_options,
-        function (trickle) {
-          test.pcRemote.localRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SANE_REMOTE_SDP',
-    function (test) {
-      test.pcLocal.verifySdp(test._remote_answer, "answer",
-        test._offer_constraints, test._offer_options,
-        function (trickle) {
-          test.pcLocal.remoteRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_WAIT_FOR_ICE_CONNECTED',
-    function (test) {
-      var myTest = test;
-      var myPc = myTest.pcLocal;
-
-      function onIceConnectedSuccess () {
-        info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
-        ok(true, "pc_local: ICE switched to 'connected' state");
-        myTest.next();
-      };
-      function onIceConnectedFailed () {
-        dumpSdp(myTest);
-        ok(false, "pc_local: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
-        myTest.next();
-      };
-
-      if (myPc.isIceConnected()) {
-        info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
-        ok(true, "pc_local: ICE is in connected state");
-        myTest.next();
-      } else if (myPc.isIceConnectionPending()) {
-        myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
-      } else {
-        dumpSdp(myTest);
-        ok(false, "pc_local: ICE is already in bad state: " + myPc.iceConnectionState);
-        myTest.next();
-      }
-    }
-  ],
-  [
-    'PC_LOCAL_VERIFY_ICE_GATHERING',
-    function (test) {
-      if (test.pcLocal.localRequiresTrickleIce) {
-        ok(test.pcLocal._local_ice_candidates.length > 0, "Received local trickle ICE candidates");
-      }
-      isnot(test.pcLocal._pc.iceGatheringState, GATH_NEW, "ICE gathering state is not 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_WAIT_FOR_ICE_CONNECTED',
-    function (test) {
-      var myTest = test;
-      var myPc = myTest.pcRemote;
-
-      function onIceConnectedSuccess () {
-        info("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog);
-        ok(true, "pc_remote: ICE switched to 'connected' state");
-        myTest.next();
-      };
-      function onIceConnectedFailed () {
-        dumpSdp(myTest);
-        ok(false, "pc_remote: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
-        myTest.next();
-      };
-
-      if (myPc.isIceConnected()) {
-        info("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog);
-        ok(true, "pc_remote: ICE is in connected state");
-        myTest.next();
-      } else if (myPc.isIceConnectionPending()) {
-        myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
-      } else {
-        dumpSdp(myTest);
-        ok(false, "pc_remote: ICE is already in bad state: " + myPc.iceConnectionState);
-        myTest.next();
-      }
-    }
-  ],
-  [
-    'PC_REMOTE_VERIFY_ICE_GATHERING',
-    function (test) {
-      if (test.pcRemote.localRequiresTrickleIce) {
-        ok(test.pcRemote._local_ice_candidates.length > 0, "Received local trickle ICE candidates");
-      }
-      isnot(test.pcRemote._pc.iceGatheringState, GATH_NEW, "ICE gathering state is not 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_VERIFY_DATA_CHANNEL_STATE',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcLocal, function() {
-        test.next();
-      }, function() {
-        ok(false, test.pcLocal + " initial dataChannels[0] failed to switch to 'open'");
-        //TODO: use stopAndExit() once bug 1019323 has landed
-        unexpectedEventAndFinish(this, 'timeout')
-        // to prevent test framework timeouts
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_VERIFY_DATA_CHANNEL_STATE',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcRemote, function() {
-        test.next();
-      }, function() {
-        ok(false, test.pcRemote + " initial dataChannels[0] failed to switch to 'open'");
-        //TODO: use stopAndExit() once bug 1019323 has landed
-        unexpectedEventAndFinish(this, 'timeout');
-        // to prevent test framework timeouts
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_MEDIA_TRACKS',
-    function (test) {
-      test.pcLocal.checkMediaTracks(test._answer_constraints, function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_MEDIA_TRACKS',
-    function (test) {
-      test.pcRemote.checkMediaTracks(test._offer_constraints, function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_MEDIA_FLOW_PRESENT',
-    function (test) {
-      test.pcLocal.checkMediaFlowPresent(function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT',
-    function (test) {
-      test.pcRemote.checkMediaFlowPresent(function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_ICE_CONNECTIONS',
-    function (test) {
-      test.pcLocal.getStats(null, function(stats) {
-        test.pcLocal.checkStatsIceConnections(stats,
-                                              test._offer_constraints,
-                                              test._offer_options,
-                                              1,
-                                              test.originalAnswer);
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_ICE_CONNECTIONS',
-    function (test) {
-      test.pcRemote.getStats(null, function(stats) {
-        test.pcRemote.checkStatsIceConnections(stats,
-                                               test._offer_constraints,
-                                               test._offer_options,
-                                               1,
-                                               test.originalAnswer);
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE',
-    function (test) {
-      var message = "Lorem ipsum dolor sit amet";
-
-      test.send(message, function (channel, data) {
-        is(data, message, "Message correctly transmitted from pcLocal to pcRemote.");
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_BLOB',
-    function (test) {
-      var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
-      var blob = new Blob(contents, { "type" : "text/plain" });
-
-      test.send(blob, function (channel, data) {
-        ok(data instanceof Blob, "Received data is of instance Blob");
-        is(data.size, blob.size, "Received data has the correct size.");
-
-        getBlobContent(data, function (recv_contents) {
-          is(recv_contents, contents, "Received data has the correct content.");
-
-          test.next();
-        });
-      });
-    }
-  ],
-  [
-    'CREATE_SECOND_DATA_CHANNEL',
-    function (test) {
-      test.createDataChannel({ }, function (sourceChannel, targetChannel) {
-        is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
-        is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
-
-        is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
-        is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL',
-    function (test) {
-      var channels = test.pcRemote.dataChannels;
-      var message = "Lorem ipsum dolor sit amet";
-
-      test.send(message, function (channel, data) {
-        is(channels.indexOf(channel), channels.length - 1, "Last channel used");
-        is(data, message, "Received message has the correct content.");
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE_THROUGH_FIRST_CHANNEL',
-    function (test) {
-      var message = "Message through 1st channel";
-      var options = {
-        sourceChannel: test.pcLocal.dataChannels[0],
-        targetChannel: test.pcRemote.dataChannels[0]
-      };
-
-      test.send(message, function (channel, data) {
-        is(test.pcRemote.dataChannels.indexOf(channel), 0, "1st channel used");
-        is(data, message, "Received message has the correct content.");
-
-        test.next();
-      }, options);
-    }
-  ],
-  [
-    'SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL',
-    function (test) {
-      var message = "Return a message also through 1st channel";
-      var options = {
-        sourceChannel: test.pcRemote.dataChannels[0],
-        targetChannel: test.pcLocal.dataChannels[0]
-      };
-
-      test.send(message, function (channel, data) {
-        is(test.pcLocal.dataChannels.indexOf(channel), 0, "1st channel used");
-        is(data, message, "Return message has the correct content.");
-
-        test.next();
-      }, options);
-    }
-  ],
-  [
-    'CREATE_NEGOTIATED_DATA_CHANNEL',
-    function (test) {
-      var options = {negotiated:true, id: 5, protocol:"foo/bar", ordered:false,
-        maxRetransmits:500};
-      test.createDataChannel(options, function (sourceChannel2, targetChannel2) {
-        is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
-        is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
-
-        is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
-        is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
-
-        if (options.id != undefined) {
-          is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
-        }
-        else {
-          options.id = sourceChannel2.id;
-        }
-        var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
-        is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
-        is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
-/*
-  These aren't exposed by IDL yet
-        is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
-        is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
-	   sourceChannel2.maxRetransmits);
-        is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
-	   sourceChannel2.maxRetransmitTime);
-*/
-
-        is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
-        is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
-        is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
-/*
-  These aren't exposed by IDL yet
-       is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
-        is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
-	   targetChannel2.maxRetransmits);
-        is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
-	   targetChannel2.maxRetransmitTime);
-*/
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2',
-    function (test) {
-      var channels = test.pcRemote.dataChannels;
-      var message = "Lorem ipsum dolor sit amet";
-
-      test.send(message, function (channel, data) {
-        is(channels.indexOf(channel), channels.length - 1, "Last channel used");
-        is(data, message, "Received message has the correct content.");
-
-        test.next();
-      });
-    }
-  ]
-];
-
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudio.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudio.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796895",
     title: "Basic data channel audio connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideo.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideo.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796891",
     title: "Basic data channel audio/video connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{audio: true}, {video: true}],
                              [{audio: true}, {video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoCombined.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoCombined.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796891",
     title: "Basic data channel audio/video connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{audio: true, video: true}],
                              [{audio: true, video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html
@@ -1,44 +1,44 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
-  SimpleTest.requestFlakyTimeout("untriaged");
-
   createHTML({
     bug: "1016476",
     title: "Basic data channel audio/video connection without bundle"
   });
 
   var test;
   runNetworkTest(function () {
-    test = new DataChannelTest();
-    test.setMediaConstraints([{audio: true}, {video: true}],
-                             [{audio: true}, {video: true}]);
+    test = new PeerConnectionTest();
+    addInitialDataChannel(test.chain);
     test.chain.insertAfter("PC_LOCAL_CREATE_OFFER",
       [[
         'PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER',
         function (test) {
           // Just replace a=group:BUNDLE with something that will be ignored.
           test.originalOffer.sdp = test.originalOffer.sdp.replace(
             "a=group:BUNDLE",
             "a=foo:");
           test.next();
         }
       ]]
       );
+    test.setMediaConstraints([{audio: true}, {video: true}],
+                             [{audio: true}, {video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_basicDataOnly.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicDataOnly.html
@@ -1,28 +1,30 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796894",
     title: "Basic datachannel only connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_basicVideo.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicVideo.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796889",
     title: "Basic data channel video connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{video: true}], [{video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_bug1013809.html
+++ b/dom/media/tests/mochitest/test_dataChannel_bug1013809.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796895",
     title: "Basic data channel audio connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     var sld = test.chain.remove("PC_REMOTE_SET_LOCAL_DESCRIPTION");
     test.chain.insertAfter("PC_LOCAL_SET_REMOTE_DESCRIPTION", sld);
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
 
 </script>
 </pre>
--- a/dom/nfc/nsNfc.js
+++ b/dom/nfc/nsNfc.js
@@ -187,16 +187,20 @@ MozNFCTagImpl.prototype = {
                                       "NFCTag object is not formatable");
     }
 
     let callback = new NfcCallback(this._window);
     this._nfcContentHelper.format(this.session, callback);
     return callback.promise;
   },
 
+  notifyLost: function notifyLost() {
+    this.isLost = true;
+  },
+
   classID: Components.ID("{4e1e2e90-3137-11e3-aa6e-0800200c9a66}"),
   contractID: "@mozilla.org/nfc/tag;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 };
 
 /**
  * Implementation of NFCPeer.
@@ -239,16 +243,20 @@ MozNFCPeerImpl.prototype = {
     };
 
     let callback = new NfcCallback(this._window);
     this._nfcContentHelper.sendFile(Cu.cloneInto(data, this._window),
                                     this.session, callback);
     return callback.promise;
   },
 
+  notifyLost: function notifyLost() {
+    this.isLost = true;
+  },
+
   classID: Components.ID("{c1b2bcf0-35eb-11e3-aa6e-0800200c9a66}"),
   contractID: "@mozilla.org/nfc/peer;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 };
 
 // Should be mapped to the RFState defined in WebIDL.
 let RFState = {
@@ -427,17 +435,17 @@ MozNFCImpl.prototype = {
     }
 
     // Remove system event listener only when tag and peer are both lost.
     if (!this.nfcPeer) {
       this.eventService.removeSystemEventListener(this._window, "visibilitychange",
         this, /* useCapture */false);
     }
 
-    this.nfcTag.isLost = true;
+    this.nfcTag.notifyLost();
     this.nfcTag = null;
 
     debug("fire ontaglost " + sessionToken);
     let event = new this._window.Event("taglost");
     this.__DOM_IMPL__.dispatchEvent(event);
   },
 
   notifyPeerFound: function notifyPeerFound(sessionToken, isPeerReady) {
@@ -486,17 +494,17 @@ MozNFCImpl.prototype = {
     }
 
     // Remove system event listener only when tag and peer are both lost.
     if (!this.nfcTag) {
       this.eventService.removeSystemEventListener(this._window, "visibilitychange",
         this, /* useCapture */false);
     }
 
-    this.nfcPeer.isLost = true;
+    this.nfcPeer.notifyLost();
     this.nfcPeer = null;
 
     debug("fire onpeerlost");
     let event = new this._window.Event("peerlost");
     this.__DOM_IMPL__.dispatchEvent(event);
   },
 
   handleEvent: function handleEvent (event) {
--- a/dom/plugins/base/android/ANPAudio.cpp
+++ b/dom/plugins/base/android/ANPAudio.cpp
@@ -255,25 +255,25 @@ anp_audio_newTrack(uint32_t sampleRate, 
                                 s->rate,
                                 jChannels,
                                 jformat,
                                 s->bufferSize,
                                 MODE_STREAM);
 
   if (autoFrame.CheckForException() || obj == nullptr) {
     jenv->DeleteGlobalRef(s->at_class);
-    free(s);
+    delete s;
     return nullptr;
   }
 
   jint state = jenv->CallIntMethod(obj, at.getstate);
 
   if (autoFrame.CheckForException() || state == STATE_UNINITIALIZED) {
     jenv->DeleteGlobalRef(s->at_class);
-    free(s);
+    delete s;
     return nullptr;
   }
 
   s->output_unit = jenv->NewGlobalRef(obj);
   return s;
 }
 
 void
@@ -305,17 +305,17 @@ anp_audio_start(ANPAudioTrack* s)
 
   JNIEnv *jenv = GetJNIForThread();
 
   mozilla::AutoLocalJNIFrame autoFrame(jenv, 0);
   jenv->CallVoidMethod(s->output_unit, at.play);
 
   if (autoFrame.CheckForException()) {
     jenv->DeleteGlobalRef(s->at_class);
-    free(s);
+    delete s;
     return;
   }
 
   s->isStopped = false;
   s->keepGoing = true;
 
   // AudioRunnable now owns the ANPAudioTrack
   nsRefPtr<AudioRunnable> runnable = new AudioRunnable(s);
--- a/dom/plugins/ipc/BrowserStreamChild.cpp
+++ b/dom/plugins/ipc/BrowserStreamChild.cpp
@@ -57,17 +57,20 @@ BrowserStreamChild::StreamConstructed(
   NPError rv = NPERR_NO_ERROR;
 
   *stype = NP_NORMAL;
   rv = mInstance->mPluginIface->newstream(
     &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
     &mStream, seekable, stype);
   if (rv != NPERR_NO_ERROR) {
     mState = DELETING;
-    mStreamNotify = nullptr;
+    if (mStreamNotify) {
+      mStreamNotify->SetAssociatedStream(nullptr);
+      mStreamNotify = nullptr;
+    }
   }
   else {
     mState = ALIVE;
   }
 
   return rv;
 }
 
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -2435,17 +2435,16 @@ StreamNotifyChild::ActorDestroy(ActorDes
         mBrowserStream = nullptr;
     }
 }
 
 
 void
 StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs)
 {
-    NS_ASSERTION(bs, "Shouldn't be null");
     NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?");
 
     mBrowserStream = bs;
 }
 
 bool
 StreamNotifyChild::Recv__delete__(const NPReason& reason)
 {
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -30,18 +30,19 @@
 #include "nsIObserverService.h"
 #include "nsNPAPIPlugin.h"
 #include "nsPrintfCString.h"
 #include "prsystem.h"
 #include "GeckoProfiler.h"
 #include "nsPluginTags.h"
 
 #ifdef XP_WIN
+#include "mozilla/widget/AudioSession.h"
+#include "nsWindowsHelpers.h"
 #include "PluginHangUIParent.h"
-#include "mozilla/widget/AudioSession.h"
 #endif
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "nsIProfiler.h"
 #include "nsIProfileSaveEvent.h"
 #endif
 
 #ifdef MOZ_WIDGET_GTK
@@ -2476,17 +2477,17 @@ PluginModuleChromeParent::InitializeInje
     if (kNotFound == lastSlash)
         return;
 
     if (!StringBeginsWith(Substring(path, lastSlash + 1),
                           NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
         return;
 
     TimeStamp th32Start = TimeStamp::Now();
-    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    nsAutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
     if (INVALID_HANDLE_VALUE == snapshot)
         return;
     TimeStamp th32End = TimeStamp::Now();
     mTimeBlocked += (th32End - th32Start);
 
     DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
     mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, snapshot);
     if (mFlashProcess1) {
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -439,17 +439,17 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost
     // www.example.com/ should result in www.example.com/
     // please note that we do not have to perform any pct-decoding here
     // because we are just appending a '/' and not any actual chars.
     aCspHost->appendPath(NS_LITERAL_STRING("/"));
     return true;
   }
   // path can begin with "/" but not "//"
   // see http://tools.ietf.org/html/rfc3986#section-3.3
-  if (!hostChar()) {
+  if (peek(SLASH)) {
     const char16_t* params[] = { mCurToken.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
                              params, ArrayLength(params));
     return false;
   }
   return subPath(aCspHost);
 }
 
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -117,16 +117,17 @@ typedef Tuple3<NetdCommand*, CommandChai
 
 static NetworkUtils* gNetworkUtils;
 static nsTArray<QueueData> gCommandQueue;
 static CurrentCommand gCurrentCommand;
 static bool gPending = false;
 static nsTArray<nsCString> gReason;
 static NetworkParams *gWifiTetheringParms = 0;
 
+static nsTArray<CommandChain*> gCommandChainQueue;
 
 const CommandFunc NetworkUtils::sWifiEnableChain[] = {
   NetworkUtils::clearWifiTetherParms,
   NetworkUtils::wifiFirmwareReload,
   NetworkUtils::startAccessPointDriver,
   NetworkUtils::setAccessPoint,
   NetworkUtils::startSoftAP,
   NetworkUtils::setInterfaceUp,
@@ -380,30 +381,46 @@ static void postMessage(NetworkParams& a
   MOZ_ASSERT(gNetworkUtils->getMessageCallback());
 
   aResult.mId = aOptions.mId;
 
   if (*(gNetworkUtils->getMessageCallback()))
     (*(gNetworkUtils->getMessageCallback()))(aResult);
 }
 
+void NetworkUtils::runNextQueuedCommandChain()
+{
+  if (gCommandChainQueue.IsEmpty()) {
+    NU_DBG("No command chain left in the queue. Done!");
+    return;
+  }
+  NU_DBG("Process the queued command chain.");
+  CommandChain* nextChain = gCommandChainQueue[0];
+  NetworkResultOptions newResult;
+  next(nextChain, false, newResult);
+}
+
 void NetworkUtils::next(CommandChain* aChain, bool aError, NetworkResultOptions& aResult)
 {
   if (aError) {
     ErrorCallback onError = aChain->getErrorCallback();
     if(onError) {
       aResult.mError = true;
       (*onError)(aChain->getParams(), aResult);
     }
     delete aChain;
+    gCommandChainQueue.RemoveElementAt(0);
+    runNextQueuedCommandChain();
     return;
   }
   CommandFunc f = aChain->getNextCommand();
   if (!f) {
     delete aChain;
+    gCommandChainQueue.RemoveElementAt(0);
+    runNextQueuedCommandChain();
     return;
   }
 
   (*f)(aChain, next, aResult);
 }
 
 CommandResult::CommandResult(int32_t aResultCode)
   : mIsPending(false)
@@ -804,23 +821,26 @@ void NetworkUtils::startTethering(Comman
 {
   char command[MAX_COMMAND_SIZE];
 
   // We don't need to start tethering again.
   // Send the dummy command to continue the function chain.
   if (aResult.mResultReason.Find("started") != kNotFound) {
     snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
   } else {
-    snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s", GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp));
-
     // If usbStartIp/usbEndIp is not valid, don't append them since
     // the trailing white spaces will be parsed to extra empty args
     // See: http://androidxref.com/4.3_r2.1/xref/system/core/libsysutils/src/FrameworkListener.cpp#78
     if (!GET_FIELD(mUsbStartIp).IsEmpty() && !GET_FIELD(mUsbEndIp).IsEmpty()) {
-      snprintf(command, MAX_COMMAND_SIZE - 1, "%s %s %s", command, GET_CHAR(mUsbStartIp), GET_CHAR(mUsbEndIp));
+      snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s %s %s",
+               GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp),
+               GET_CHAR(mUsbStartIp),  GET_CHAR(mUsbEndIp));
+    } else {
+      snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s",
+               GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp));
     }
   }
 
   doCommand(command, aChain, aCallback);
 }
 
 void NetworkUtils::untetherInterface(CommandChain* aChain,
                                      CommandCallback aCallback,
@@ -932,57 +952,76 @@ void NetworkUtils::setInterfaceDns(Comma
 #undef GET_FIELD
 
 /*
  * Netd command success/fail function
  */
 #define ASSIGN_FIELD(prop)  aResult.prop = aChain->getParams().prop;
 #define ASSIGN_FIELD_VALUE(prop, value)  aResult.prop = value;
 
-#define RUN_CHAIN(param, cmds, err)                                \
-  uint32_t size = sizeof(cmds) / sizeof(CommandFunc);              \
-  CommandChain* chain = new CommandChain(param, cmds, size, err);  \
-  NetworkResultOptions result;                                     \
-  next(chain, false, result);
+template<size_t N>
+void NetworkUtils::runChain(const NetworkParams& aParams,
+                            const CommandFunc (&aCmds)[N],
+                            ErrorCallback aError)
+{
+  CommandChain* chain = new CommandChain(aParams, aCmds, N, aError);
+  gCommandChainQueue.AppendElement(chain);
+
+  if (gCommandChainQueue.Length() > 1) {
+    NU_DBG("%d command chains are queued. Wait!", gCommandChainQueue.Length());
+    return;
+  }
+
+  NetworkResultOptions result;
+  NetworkUtils::next(gCommandChainQueue[0], false, result);
+}
+
+// Called to clean up the command chain and process the queued command chain if any.
+void NetworkUtils::finalizeSuccess(CommandChain* aChain,
+                                   NetworkResultOptions& aResult)
+{
+  next(aChain, false, aResult);
+}
 
 void NetworkUtils::wifiTetheringFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   // Notify the main thread.
   postMessage(aOptions, aResult);
 
   // If one of the stages fails, we try roll back to ensure
   // we don't leave the network systems in limbo.
   ASSIGN_FIELD_VALUE(mEnable, false)
-  RUN_CHAIN(aOptions, sWifiFailChain, nullptr)
+  runChain(aOptions, sWifiFailChain, nullptr);
 }
 
 void NetworkUtils::wifiTetheringSuccess(CommandChain* aChain,
                                         CommandCallback aCallback,
                                         NetworkResultOptions& aResult)
 {
   ASSIGN_FIELD(mEnable)
 
   if (aChain->getParams().mEnable) {
     MOZ_ASSERT(!gWifiTetheringParms);
     gWifiTetheringParms = new NetworkParams(aChain->getParams());
   }
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::usbTetheringFail(NetworkParams& aOptions,
                                     NetworkResultOptions& aResult)
 {
   // Notify the main thread.
   postMessage(aOptions, aResult);
   // Try to roll back to ensure
   // we don't leave the network systems in limbo.
   // This parameter is used to disable ipforwarding.
   {
     aOptions.mEnable = false;
-    RUN_CHAIN(aOptions, sUSBFailChain, nullptr)
+    runChain(aOptions, sUSBFailChain, nullptr);
   }
 
   // Disable usb rndis function.
   {
     NetworkParams options;
     options.mEnable = false;
     options.mReport = false;
     gNetworkUtils->enableUsbRndis(options);
@@ -990,68 +1029,73 @@ void NetworkUtils::usbTetheringFail(Netw
 }
 
 void NetworkUtils::usbTetheringSuccess(CommandChain* aChain,
                                        CommandCallback aCallback,
                                        NetworkResultOptions& aResult)
 {
   ASSIGN_FIELD(mEnable)
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::networkInterfaceAlarmFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::networkInterfaceAlarmSuccess(CommandChain* aChain,
                                                 CommandCallback aCallback,
                                                 NetworkResultOptions& aResult)
 {
   // TODO : error is not used , and it is conflict with boolean type error.
   // params.error = parseFloat(params.resultReason);
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::updateUpStreamFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::updateUpStreamSuccess(CommandChain* aChain,
                                          CommandCallback aCallback,
                                          NetworkResultOptions& aResult)
 {
   ASSIGN_FIELD(mCurExternalIfname)
   ASSIGN_FIELD(mCurInternalIfname)
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::setDhcpServerFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   aResult.mSuccess = false;
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::setDhcpServerSuccess(CommandChain* aChain, CommandCallback aCallback, NetworkResultOptions& aResult)
 {
   aResult.mSuccess = true;
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::wifiOperationModeFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 void NetworkUtils::wifiOperationModeSuccess(CommandChain* aChain,
                                             CommandCallback aCallback,
                                             NetworkResultOptions& aResult)
 {
   postMessage(aChain->getParams(), aResult);
+  finalizeSuccess(aChain, aResult);
 }
 
 void NetworkUtils::setDnsFail(NetworkParams& aOptions, NetworkResultOptions& aResult)
 {
   postMessage(aOptions, aResult);
 }
 
 #undef ASSIGN_FIELD
@@ -1183,17 +1227,17 @@ void NetworkUtils::onNetdMessage(NetdCom
       if (gWifiTetheringParms) {
         char linkdownReason[MAX_COMMAND_SIZE];
         snprintf(linkdownReason, MAX_COMMAND_SIZE - 1,
                  "Iface linkstate %s down",
                  NS_ConvertUTF16toUTF8(gWifiTetheringParms->mIfname).get());
 
         if (!strcmp(reason, linkdownReason)) {
           NU_DBG("Wifi link down, restarting tethering.");
-          RUN_CHAIN(*gWifiTetheringParms, sWifiRetryChain, wifiTetheringFail)
+          runChain(*gWifiTetheringParms, sWifiRetryChain, wifiTetheringFail);
         }
       }
     }
 
     nextNetdCommand();
     return;
   }
 
@@ -1237,19 +1281,19 @@ CommandResult NetworkUtils::setDhcpServe
 {
   if (aOptions.mEnabled) {
     aOptions.mWifiStartIp = aOptions.mStartIp;
     aOptions.mWifiEndIp = aOptions.mEndIp;
     aOptions.mIp = aOptions.mServerIp;
     aOptions.mPrefix = aOptions.mMaskLength;
     aOptions.mLink = NS_ConvertUTF8toUTF16("up");
 
-    RUN_CHAIN(aOptions, sStartDhcpServerChain, setDhcpServerFail)
+    runChain(aOptions, sStartDhcpServerChain, setDhcpServerFail);
   } else {
-    RUN_CHAIN(aOptions, sStopDhcpServerChain, setDhcpServerFail)
+    runChain(aOptions, sStopDhcpServerChain, setDhcpServerFail);
   }
   return CommandResult::Pending();
 }
 
 /**
  * Set DNS servers for given network interface.
  */
 CommandResult NetworkUtils::setDNS(NetworkParams& aOptions)
@@ -1278,17 +1322,17 @@ CommandResult NetworkUtils::setDNS(Netwo
   property_get("net.dnschange", dnschange, "0");
 
   char num[PROPERTY_VALUE_MAX];
   snprintf(num, PROPERTY_VALUE_MAX - 1, "%d", atoi(dnschange) + 1);
   property_set("net.dnschange", num);
 
   // DNS needs to be set through netd since JellyBean (4.3).
   if (SDK_VERSION >= 18) {
-    RUN_CHAIN(aOptions, sSetDnsChain, setDnsFail)
+    runChain(aOptions, sSetDnsChain, setDnsFail);
     return CommandResult::Pending();
   }
 
   return SUCCESS;
 }
 
 CommandResult NetworkUtils::configureInterface(NetworkParams& aOptions)
 {
@@ -1595,41 +1639,41 @@ CommandResult NetworkUtils::removeSecond
 
   doCommand(command, nullptr, nullptr);
   return SUCCESS;
 }
 
 CommandResult NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   NU_DBG("setNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
-  RUN_CHAIN(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
+  runChain(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail);
   return CommandResult::Pending();
 }
 
 CommandResult NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   NU_DBG("enableNetworkInterfaceAlarm: %s", GET_CHAR(mIfname));
-  RUN_CHAIN(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
+  runChain(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail);
   return CommandResult::Pending();
 }
 
 CommandResult NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions)
 {
   NU_DBG("disableNetworkInterfaceAlarms: %s", GET_CHAR(mIfname));
-  RUN_CHAIN(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
+  runChain(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail);
   return CommandResult::Pending();
 }
 
 /**
  * handling main thread's reload Wifi firmware request
  */
 CommandResult NetworkUtils::setWifiOperationMode(NetworkParams& aOptions)
 {
   NU_DBG("setWifiOperationMode: %s %s", GET_CHAR(mIfname), GET_CHAR(mMode));
-  RUN_CHAIN(aOptions, sWifiOperationModeChain, wifiOperationModeFail);
+  runChain(aOptions, sWifiOperationModeChain, wifiOperationModeFail);
   return CommandResult::Pending();
 }
 
 /**
  * handling main thread's enable/disable WiFi Tethering request
  */
 CommandResult NetworkUtils::setWifiTethering(NetworkParams& aOptions)
 {
@@ -1649,21 +1693,21 @@ CommandResult NetworkUtils::setWifiTethe
       aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2);
     }
   }
   dumpParams(aOptions, "WIFI");
 
   if (enable) {
     NU_DBG("Starting Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sWifiEnableChain, wifiTetheringFail)
+    runChain(aOptions, sWifiEnableChain, wifiTetheringFail);
   } else {
     NU_DBG("Stopping Wifi Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sWifiDisableChain, wifiTetheringFail)
+    runChain(aOptions, sWifiDisableChain, wifiTetheringFail);
   }
   return CommandResult::Pending();
 }
 
 CommandResult NetworkUtils::setUSBTethering(NetworkParams& aOptions)
 {
   bool enable = aOptions.mEnable;
   IFProperties interfaceProperties;
@@ -1681,21 +1725,21 @@ CommandResult NetworkUtils::setUSBTether
       aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2);
     }
   }
   dumpParams(aOptions, "USB");
 
   if (enable) {
     NU_DBG("Starting USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sUSBEnableChain, usbTetheringFail)
+    runChain(aOptions, sUSBEnableChain, usbTetheringFail);
   } else {
     NU_DBG("Stopping USB Tethering on %s <-> %s",
            GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname));
-    RUN_CHAIN(aOptions, sUSBDisableChain, usbTetheringFail)
+    runChain(aOptions, sUSBDisableChain, usbTetheringFail);
   }
   return CommandResult::Pending();
 }
 
 void NetworkUtils::escapeQuote(nsCString& aString)
 {
   aString.ReplaceSubstring("\\", "\\\\");
   aString.ReplaceSubstring("\"", "\\\"");
@@ -1795,17 +1839,17 @@ CommandResult NetworkUtils::enableUsbRnd
   return SUCCESS;
 }
 
 /**
  * handling upstream interface change event.
  */
 CommandResult NetworkUtils::updateUpStream(NetworkParams& aOptions)
 {
-  RUN_CHAIN(aOptions, sUpdateUpStreamChain, updateUpStreamFail)
+  runChain(aOptions, sUpdateUpStreamChain, updateUpStreamFail);
   return CommandResult::Pending();
 }
 
 void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason)
 {
   NetworkResultOptions result;
   switch(code) {
     case NETD_COMMAND_INTERFACE_CHANGE:
--- a/dom/system/gonk/NetworkUtils.h
+++ b/dom/system/gonk/NetworkUtils.h
@@ -355,16 +355,25 @@ private:
 
   static void escapeQuote(nsCString& aString);
   inline uint32_t netdResponseType(uint32_t code);
   inline bool isBroadcastMessage(uint32_t code);
   inline bool isError(uint32_t code);
   inline bool isComplete(uint32_t code);
   inline bool isProceeding(uint32_t code);
   void Shutdown();
+  static void runNextQueuedCommandChain();
+  static void finalizeSuccess(CommandChain* aChain,
+                              mozilla::dom::NetworkResultOptions& aResult);
+
+  template<size_t N>
+  static void runChain(const NetworkParams& aParams,
+                       const CommandFunc (&aCmds)[N],
+                       ErrorCallback aError);
+
   /**
    * Callback function to send netd result to main thread.
    */
   MessageCallback mMessageCallback;
 
   /*
    * Utility class to access libnetutils.
    */
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -57,16 +57,20 @@ const RIL_IPC_MSG_NAMES = [
   "RIL:UpdateIccContact",
   "RIL:MatchMvno"
 ];
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsISyncMessageSender");
 
+XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
+                  "@mozilla.org/uuid-generator;1",
+                  "nsIUUIDGenerator");
+
 XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
   let appInfo = Cc["@mozilla.org/xre/app-info;1"];
   let isParentProcess = !appInfo || appInfo.getService(Ci.nsIXULRuntime)
                           .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
 
   if (isParentProcess) {
     let ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer);
     return ril.numRadioInterfaces;
@@ -405,73 +409,68 @@ RILContentHelper.prototype = {
     cpmm.sendAsyncMessage("RIL:SendStkEventDownload", {
       clientId: clientId,
       data: {
         event: event
       }
     });
   },
 
-  iccOpenChannel: function(clientId, window, aid) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
+  iccOpenChannel: function(clientId, aid, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._addIccChannelCallback(requestId, callback);
 
     cpmm.sendAsyncMessage("RIL:IccOpenChannel", {
       clientId: clientId,
       data: {
         requestId: requestId,
         aid: aid
       }
     });
-    return request;
   },
 
-  iccExchangeAPDU: function(clientId, window, channel, apdu) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
+  iccExchangeAPDU: function(clientId, channel, cla, ins, p1, p2, p3, data, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._addIccChannelCallback(requestId, callback);
+
+    if (!data) {
+      if (DEBUG) debug('data is not set , p3 : ' + p3);
     }
 
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
+    let apdu = {
+      cla: cla,
+      command: ins,
+      p1: p1,
+      p2: p2,
+      p3: p3,
+      data: data
+    };
 
     //Potentially you need serialization here and can't pass the jsval through
     cpmm.sendAsyncMessage("RIL:IccExchangeAPDU", {
       clientId: clientId,
       data: {
         requestId: requestId,
         channel: channel,
         apdu: apdu
       }
     });
-    return request;
   },
 
-  iccCloseChannel: function(clientId, window, channel) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
+  iccCloseChannel: function(clientId, channel, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._addIccChannelCallback(requestId, callback);
 
     cpmm.sendAsyncMessage("RIL:IccCloseChannel", {
       clientId: clientId,
       data: {
         requestId: requestId,
         channel: channel
       }
     });
-    return request;
   },
 
   readContacts: function(clientId, window, contactType) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
 
@@ -567,16 +566,32 @@ RILContentHelper.prototype = {
 
     let index = listeners.indexOf(listener);
     if (index != -1) {
       listeners.splice(index, 1);
       if (DEBUG) debug("Unregistered listener: " + listener);
     }
   },
 
+  _addIccChannelCallback: function(requestId, channelCb) {
+    let cbInterfaces = this._iccChannelCallback;
+    if (!cbInterfaces[requestId] && channelCb) {
+      cbInterfaces[requestId] = channelCb;
+      return;
+    }
+
+    if (DEBUG) debug("Unable to add channelCbInterface for requestId : " + requestId);
+  },
+
+  _getIccChannelCallback: function(requestId) {
+    let cb = this._iccChannelCallback[requestId];
+    delete this._iccChannelCallback[requestId];
+    return cb;
+  },
+
   registerIccMsg: function(clientId, listener) {
     if (DEBUG) debug("Registering for ICC related messages");
     this.registerListener("_iccListeners", clientId, listener);
     cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
   },
 
   unregisterIccMsg: function(clientId, listener) {
     this.unregisterListener("_iccListeners", clientId, listener);
@@ -735,21 +750,20 @@ RILContentHelper.prototype = {
       case "RIL:StkCommand":
         this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand",
                            [JSON.stringify(data)]);
         break;
       case "RIL:StkSessionEnd":
         this._deliverEvent(clientId, "_iccListeners", "notifyStkSessionEnd", null);
         break;
       case "RIL:IccOpenChannel":
-        this.handleSimpleRequest(data.requestId, data.errorMsg,
-                                 data.channel);
+        this.handleIccOpenChannel(data);
         break;
       case "RIL:IccCloseChannel":
-        this.handleSimpleRequest(data.requestId, data.errorMsg, null);
+        this.handleIccCloseChannel(data);
         break;
       case "RIL:IccExchangeAPDU":
         this.handleIccExchangeAPDU(data);
         break;
       case "RIL:ReadIccContacts":
         this.handleReadIccContacts(data);
         break;
       case "RIL:UpdateIccContact":
@@ -764,23 +778,48 @@ RILContentHelper.prototype = {
   handleSimpleRequest: function(requestId, errorMsg, result) {
     if (errorMsg) {
       this.fireRequestError(requestId, errorMsg);
     } else {
       this.fireRequestSuccess(requestId, result);
     }
   },
 
+  handleIccOpenChannel: function(message) {
+    let requestId = message.requestId;
+    let callback = this._getIccChannelCallback(requestId);
+    if (!callback) {
+      return;
+    }
+
+    return !message.errorMsg ? callback.notifyOpenChannelSuccess(message.channel) :
+                               callback.notifyError(message.errorMsg);
+  },
+
+  handleIccCloseChannel: function(message) {
+    let requestId = message.requestId;
+    let callback = this._getIccChannelCallback(requestId);
+    if (!callback) {
+      return;
+    }
+
+    return !message.errorMsg ? callback.notifyCloseChannelSuccess() :
+                               callback.notifyError(message.errorMsg);
+  },
+
   handleIccExchangeAPDU: function(message) {
-    if (message.errorMsg) {
-      this.fireRequestError(message.requestId, message.errorMsg);
-    } else {
-      var result = [message.sw1, message.sw2, message.simResponse];
-      this.fireRequestSuccess(message.requestId, result);
+    let requestId = message.requestId;
+    let callback = this._getIccChannelCallback(requestId);
+    if (!callback) {
+      return;
     }
+
+    return !message.errorMsg ?
+           callback.notifyExchangeAPDUResponse(message.sw1, message.sw2, message.simResponse) :
+           callback.notifyError(message.errorMsg);
   },
 
   handleReadIccContacts: function(message) {
     if (message.errorMsg) {
       this.fireRequestError(message.requestId, message.errorMsg);
       return;
     }
 
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1988,38 +1988,38 @@ RadioInterface.prototype = {
       }
     }
     return true;
   },
 
   matchMvno: function(target, message) {
     if (DEBUG) this.debug("matchMvno: " + JSON.stringify(message));
 
-    if (!message || !message.mvnoType || !message.mvnoData) {
+    if (!message || !message.mvnoData) {
       message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER;
     }
 
     if (!message.errorMsg) {
       switch (message.mvnoType) {
-        case "imsi":
+        case RIL.GECKO_CARDMVNO_TYPE_IMSI:
           if (!this.rilContext.imsi) {
             message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
             break;
           }
           message.result = this.isImsiMatches(message.mvnoData);
           break;
-        case "spn":
+        case RIL.GECKO_CARDMVNO_TYPE_SPN:
           let spn = this.rilContext.iccInfo && this.rilContext.iccInfo.spn;
           if (!spn) {
             message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
             break;
           }
           message.result = spn == message.mvnoData;
           break;
-        case "gid":
+        case RIL.GECKO_CARDMVNO_TYPE_GID:
           this.workerMessenger.send("getGID1", null, (function(response) {
             let gid = response.gid1;
             let mvnoDataLength = message.mvnoData.length;
 
             if (!gid) {
               message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
             } else if (mvnoDataLength > gid.length) {
               message.result = false;
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -1311,16 +1311,17 @@ this.GECKO_ICC_SERVICES = {
     PNN: 45,
     OPL: 46,
     MDN: 47,
     MWIS: 48,
     SPDI: 51
   },
   // @see 3GPP2 C.S0023-D 3.4.18 (RUIM).
   ruim: {
+    FDN: 3,
     ENHANCED_PHONEBOOK: 6,
     SPN: 17,
     SDN: 18
   },
   // @see B.3.1.1 CPHS Information in CPHS Phase 2:
   // Indicates which of the CPHS 'optional' data-fields are present in the SIM card:
   //   EF_CPHS_CSP, EF_CPHS_SST, EF_CPHS_MBN, EF_CPHS_ONSF, EF_CPHS_INFO_NUM
   // Note: Mandatory EFs are: (B.3.1 Enhanced SIM Requirements)
@@ -2640,16 +2641,21 @@ GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOC
 GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_CCK] = ICC_SEL_CODE_PH_CORP_PIN;
 GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_SPCK] = ICC_SEL_CODE_PH_SP_PIN;
 
 // See nsIIccProvider::CARD_CONTACT_TYPE_*
 this.GECKO_CARDCONTACT_TYPE_ADN = 0;
 this.GECKO_CARDCONTACT_TYPE_FDN = 1;
 this.GECKO_CARDCONTACT_TYPE_SDN = 2;
 
+// See nsIIccProvider::CARD_MVNO_TYPE_*
+this.GECKO_CARDMVNO_TYPE_IMSI = 0;
+this.GECKO_CARDMVNO_TYPE_SPN = 1;
+this.GECKO_CARDMVNO_TYPE_GID = 2;
+
 // See ril.h RIL_PersoSubstate
 this.PERSONSUBSTATE = {};
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_UNKNOWN] = GECKO_CARDSTATE_UNKNOWN;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_IN_PROGRESS] = GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_READY] = GECKO_CARDSTATE_PERSONALIZATION_READY;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK] = GECKO_CARDSTATE_NETWORK_LOCKED;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET] = GECKO_CARDSTATE_NETWORK_SUBSET_LOCKED;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_CORPORATE] = GECKO_CARDSTATE_CORPORATE_LOCKED;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1682,29 +1682,34 @@ RilObject.prototype = {
     Buf.sendParcel();
   },
 
   /**
    * Hang up all calls
    */
   hangUpAll: function() {
     for (let callIndex in this.currentCalls) {
-      this.hangUp({callIndex: callIndex});
+      this.hangUpCall({callIndex: callIndex});
     }
   },
 
   /**
    * Hang up the phone.
    *
    * @param callIndex
    *        Call index (1-based) as reported by REQUEST_GET_CURRENT_CALLS.
    */
-  hangUp: function(options) {
+  hangUpCall: function(options) {
     let call = this.currentCalls[options.callIndex];
     if (!call) {
+      // |hangUpCall()| is used to remove a call from the current call list,
+      // so we consider it as an successful case when hanging up a call that
+      // doesn't exist in the current call list.
+      options.success = true;
+      this.sendChromeMessage(options);
       return;
     }
 
     call.hangUpLocal = true;
     if (call.state === CALL_STATE_HOLDING) {
       this.hangUpBackground(options);
     } else {
       this.telephonyRequestQueue.push(REQUEST_HANGUP, () => {
@@ -1776,68 +1781,88 @@ RilObject.prototype = {
    * Answer an incoming/waiting call.
    *
    * @param callIndex
    *        Call index of the call to answer.
    */
   answerCall: function(options) {
     let call = this.currentCalls[options.callIndex];
     if (!call) {
+      options.success = false;
+      options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
+      this.sendChromeMessage(options);
       return;
     }
 
     // Check for races. Since we dispatched the incoming/waiting call
     // notification the incoming/waiting call may have changed. The main
     // thread thinks that it is answering the call with the given index,
     // so only answer if that is still incoming/waiting.
     switch (call.state) {
       case CALL_STATE_INCOMING:
         this.telephonyRequestQueue.push(REQUEST_ANSWER, () => {
-          this.context.Buf.simpleRequest(REQUEST_ANSWER);
+          this.context.Buf.simpleRequest(REQUEST_ANSWER, options);
         });
         break;
       case CALL_STATE_WAITING:
         // Answer the waiting (second) call, and hold the first call.
         this.switchActiveCall(options);
         break;
+      default:
+        if (DEBUG) this.context.debug("AnswerCall: Invalid call state");
+
+        options.success = false;
+        options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
+        this.sendChromeMessage(options);
     }
   },
 
   /**
    * Reject an incoming/waiting call.
    *
    * @param callIndex
    *        Call index of the call to reject.
    */
   rejectCall: function(options) {
-    // Check for races. Since we dispatched the incoming/waiting call
-    // notification the incoming/waiting call may have changed. The main
-    // thread thinks that it is rejecting the call with the given index,
-    // so only reject if that is still incoming/waiting.
     let call = this.currentCalls[options.callIndex];
     if (!call) {
+      // |hangUpCall()| is used to remove an imcoming call from the current
+      // call list, so we consider it as an successful case when rejecting
+      // a call that doesn't exist in the current call list.
+      options.success = true;
+      this.sendChromeMessage(options);
       return;
     }
 
     call.hangUpLocal = true;
 
     if (this._isCdma) {
       // AT+CHLD=0 means "release held or UDUB."
       this.hangUpBackground(options);
       return;
     }
 
+    // Check for races. Since we dispatched the incoming/waiting call
+    // notification the incoming/waiting call may have changed. The main
+    // thread thinks that it is rejecting the call with the given index,
+    // so only reject if that is still incoming/waiting.
     switch (call.state) {
       case CALL_STATE_INCOMING:
         this.udub(options);
         break;
       case CALL_STATE_WAITING:
         // Reject the waiting (second) call, and remain the first call.
         this.hangUpBackground(options);
         break;
+      default:
+        if (DEBUG) this.context.debug("RejectCall: Invalid call state");
+
+        options.success = false;
+        options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
+        this.sendChromeMessage(options);
     }
   },
 
   holdCall: function(options) {
     let call = this.currentCalls[options.callIndex];
     if (!call) {
       options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
       options.success = false;
@@ -1916,17 +1941,17 @@ RilObject.prototype = {
       if (!call) {
         options.success = false;
         options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
         this.sendChromeMessage(options);
         return;
       }
 
       options.callIndex = 1;
-      this.hangUp(options);
+      this.hangUpCall(options);
       return;
     }
 
     if (this.currentConferenceState === CALL_STATE_ACTIVE) {
       this.hangUpForeground(options);
     } else {
       this.hangUpBackground(options);
     }
@@ -5482,16 +5507,20 @@ RilObject.prototype[REQUEST_GET_IMSI] = 
     this.context.debug("IMSI: " + this.iccInfoPrivate.imsi);
   }
 
   options.rilMessageType = "iccimsi";
   options.imsi = this.iccInfoPrivate.imsi;
   this.sendChromeMessage(options);
 };
 RilObject.prototype[REQUEST_HANGUP] = function REQUEST_HANGUP(length, options) {
+  if (options.rilMessageType == null) {
+    return;
+  }
+
   options.success = (options.rilRequestError === 0);
   options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
   this.sendChromeMessage(options);
 };
 RilObject.prototype[REQUEST_HANGUP_WAITING_OR_BACKGROUND] = function REQUEST_HANGUP_WAITING_OR_BACKGROUND(length, options) {
   RilObject.prototype[REQUEST_HANGUP].call(this, length, options);
 };
 RilObject.prototype[REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = function REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND(length, options) {
@@ -5509,16 +5538,21 @@ RilObject.prototype[REQUEST_CONFERENCE] 
     options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
     this.sendChromeMessage(options);
     return;
   }
 
   this.sendChromeMessage(options);
 };
 RilObject.prototype[REQUEST_UDUB] = function REQUEST_UDUB(length, options) {
+  options.success = (options.rilRequestError === 0);
+  if (!options.success) {
+    options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
+  }
+  this.sendChromeMessage(options);
 };
 RilObject.prototype[REQUEST_LAST_CALL_FAIL_CAUSE] = function REQUEST_LAST_CALL_FAIL_CAUSE(length, options) {
   let Buf = this.context.Buf;
   let num = length ? Buf.readInt32() : 0;
   let failCause = null;
 
   if (num) {
     let causeNum = Buf.readInt32();
@@ -5963,16 +5997,21 @@ RilObject.prototype[REQUEST_GET_IMEI] = 
 RilObject.prototype[REQUEST_GET_IMEISV] = function REQUEST_GET_IMEISV(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   this.IMEISV = this.context.Buf.readString();
 };
 RilObject.prototype[REQUEST_ANSWER] = function REQUEST_ANSWER(length, options) {
+  options.success = (options.rilRequestError === 0);
+  if (!options.success) {
+    options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
+  }
+  this.sendChromeMessage(options);
 };
 RilObject.prototype[REQUEST_DEACTIVATE_DATA_CALL] = function REQUEST_DEACTIVATE_DATA_CALL(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   let datacall = this.currentDataCalls[options.cid];
   delete this.currentDataCalls[options.cid];
@@ -15227,30 +15266,34 @@ ICCContactHelperObject.prototype = {
    *
    * @param appType       One of CARD_APPTYPE_*.
    * @param contactType   One of GECKO_CARDCONTACT_TYPE_*.
    * @param onsuccess     Callback to be called when success.
    * @param onerror       Callback to be called when error.
    */
   readICCContacts: function(appType, contactType, onsuccess, onerror) {
     let ICCRecordHelper = this.context.ICCRecordHelper;
+    let ICCUtilsHelper = this.context.ICCUtilsHelper;
 
     switch (contactType) {
       case GECKO_CARDCONTACT_TYPE_ADN:
         if (!this.hasDfPhoneBook(appType)) {
           ICCRecordHelper.readADNLike(ICC_EF_ADN, onsuccess, onerror);
         } else {
           this.readUSimContacts(onsuccess, onerror);
         }
         break;
       case GECKO_CARDCONTACT_TYPE_FDN:
+        if (!ICCUtilsHelper.isICCServiceAvailable("FDN")) {
+          onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
+          break;
+        }
         ICCRecordHelper.readADNLike(ICC_EF_FDN, onsuccess, onerror);
         break;
       case GECKO_CARDCONTACT_TYPE_SDN:
-        let ICCUtilsHelper = this.context.ICCUtilsHelper;
         if (!ICCUtilsHelper.isICCServiceAvailable("SDN")) {
           onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
           break;
         }
 
         ICCRecordHelper.readADNLike(ICC_EF_SDN, onsuccess, onerror);
         break;
       default:
@@ -15367,30 +15410,35 @@ ICCContactHelperObject.prototype = {
    * @param contactType   One of GECKO_CARDCONTACT_TYPE_*.
    * @param contact       The contact will be updated.
    * @param pin2          PIN2 is required for FDN.
    * @param onsuccess     Callback to be called when success.
    * @param onerror       Callback to be called when error.
    */
   updateICCContact: function(appType, contactType, contact, pin2, onsuccess, onerror) {
     let ICCRecordHelper = this.context.ICCRecordHelper;
+    let ICCUtilsHelper = this.context.ICCUtilsHelper;
 
     switch (contactType) {
       case GECKO_CARDCONTACT_TYPE_ADN:
         if (!this.hasDfPhoneBook(appType)) {
           ICCRecordHelper.updateADNLike(ICC_EF_ADN, contact, null, onsuccess, onerror);
         } else {
           this.updateUSimContact(contact, onsuccess, onerror);
         }
         break;
       case GECKO_CARDCONTACT_TYPE_FDN:
         if (!pin2) {
           onerror(GECKO_ERROR_SIM_PIN2);
           return;
         }
+        if (!ICCUtilsHelper.isICCServiceAvailable("FDN")) {
+          onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
+          break;
+        }
         ICCRecordHelper.updateADNLike(ICC_EF_FDN, contact, pin2, onsuccess, onerror);
         break;
       default:
         if (DEBUG) {
           this.context.debug("Unsupported contactType :" + contactType);
         }
         onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
         break;
--- a/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js
@@ -125,18 +125,22 @@ add_test(function test_read_icc_contacts
   let record = context.ICCRecordHelper;
   let contactHelper = context.ICCContactHelper;
   let ril = context.RIL;
 
   function do_test(aSimType, aContactType, aExpectedContact, aEnhancedPhoneBook) {
     ril.appType = aSimType;
     ril._isCdma = (aSimType === CARD_APPTYPE_RUIM);
     ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ?
-                                    [0x0, 0x0C, 0x0, 0x0, 0x0]:
-                                    [0x0, 0x00, 0x0, 0x0, 0x0];
+                                    [0x20, 0x0C, 0x0, 0x0, 0x0]:
+                                    [0x20, 0x00, 0x0, 0x0, 0x0];
+
+    ril.iccInfoPrivate.sst = (aSimType === CARD_APPTYPE_SIM)?
+                                    [0x20, 0x0, 0x0, 0x0, 0x0]:
+                                    [0x2, 0x0, 0x0, 0x0, 0x0];
 
     // Override some functions to test.
     contactHelper.getContactFieldRecordId = function(pbr, contact, field, onsuccess, onerror) {
       onsuccess(1);
     };
 
     record.readPBR = function readPBR(onsuccess, onerror) {
       onsuccess([{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}]);
@@ -237,18 +241,21 @@ add_test(function test_update_icc_contac
   let context = worker.ContextPool._contexts[0];
   let recordHelper = context.ICCRecordHelper;
   let contactHelper = context.ICCContactHelper;
   let ril = context.RIL;
 
   function do_test(aSimType, aContactType, aContact, aPin2, aFileType, aHaveIapIndex, aEnhancedPhoneBook) {
     ril.appType = aSimType;
     ril._isCdma = (aSimType === CARD_APPTYPE_RUIM);
-    ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? [0x0, 0x0C, 0x0, 0x0, 0x0]
-                                                  : [0x0, 0x00, 0x0, 0x0, 0x0];
+    ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? [0x20, 0x0C, 0x0, 0x0, 0x0]
+                                                  : [0x20, 0x00, 0x0, 0x0, 0x0];
+    ril.iccInfoPrivate.sst = (aSimType === CARD_APPTYPE_SIM)?
+                                    [0x20, 0x0, 0x0, 0x0, 0x0]:
+                                    [0x2, 0x0, 0x0, 0x0, 0x0];
 
     recordHelper.readPBR = function(onsuccess, onerror) {
       if (aFileType === ICC_USIM_TYPE1_TAG) {
         onsuccess([{
           adn:   {fileId: ICC_EF_ADN},
           email: {fileId: EMAIL_FILE_ID,
                   fileType: ICC_USIM_TYPE1_TAG},
           anr0:  {fileId: ANR0_FILE_ID,
--- a/dom/telephony/TelephonyCall.cpp
+++ b/dom/telephony/TelephonyCall.cpp
@@ -2,23 +2,25 @@
 /* vim: set ts=2 et sw=2 tw=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 "TelephonyCall.h"
 #include "mozilla/dom/CallEvent.h"
 #include "mozilla/dom/TelephonyCallBinding.h"
+#include "mozilla/dom/telephony/TelephonyCallback.h"
 
 #include "mozilla/dom/DOMError.h"
 
 #include "Telephony.h"
 #include "TelephonyCallGroup.h"
 
 using namespace mozilla::dom;
+using namespace mozilla::dom::telephony;
 using mozilla::ErrorResult;
 
 // static
 already_AddRefed<TelephonyCall>
 TelephonyCall::Create(Telephony* aTelephony, TelephonyCallId* aId,
                       uint32_t aServiceId, uint32_t aCallIndex,
                       uint16_t aCallState, bool aEmergency, bool aConference,
                       bool aSwitchable, bool aMergeable)
@@ -221,105 +223,145 @@ TelephonyCall::GetError() const
 
 already_AddRefed<TelephonyCallGroup>
 TelephonyCall::GetGroup() const
 {
   nsRefPtr<TelephonyCallGroup> group = mGroup;
   return group.forget();
 }
 
-void
+already_AddRefed<Promise>
 TelephonyCall::Answer(ErrorResult& aRv)
 {
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
   if (mCallState != nsITelephonyService::CALL_STATE_INCOMING) {
-    NS_WARNING("Answer on non-incoming call ignored!");
-    return;
+    NS_WARNING("Answer on non-incoming call is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
-  nsresult rv = mTelephony->Service()->AnswerCall(mServiceId, mCallIndex);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return;
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = mTelephony->Service()->AnswerCall(mServiceId, mCallIndex, callback);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
+  ChangeStateInternal(nsITelephonyService::CALL_STATE_CONNECTING, true);
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+TelephonyCall::HangUp(ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  ChangeStateInternal(nsITelephonyService::CALL_STATE_CONNECTING, true);
-}
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
 
-void
-TelephonyCall::HangUp(ErrorResult& aRv)
-{
   if (mCallState == nsITelephonyService::CALL_STATE_DISCONNECTING ||
       mCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) {
-    NS_WARNING("HangUp on previously disconnected call ignored!");
-    return;
+    NS_WARNING("HangUp on previously disconnected call is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
-  nsresult rv = mCallState == nsITelephonyService::CALL_STATE_INCOMING ?
-                mTelephony->Service()->RejectCall(mServiceId, mCallIndex) :
-                mTelephony->Service()->HangUp(mServiceId, mCallIndex);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return;
-  }
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = mCallState == nsITelephonyService::CALL_STATE_INCOMING ?
+    mTelephony->Service()->RejectCall(mServiceId, mCallIndex, callback) :
+    mTelephony->Service()->HangUpCall(mServiceId, mCallIndex, callback);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
 
   ChangeStateInternal(nsITelephonyService::CALL_STATE_DISCONNECTING, true);
+  return promise.forget();
 }
 
-void
+already_AddRefed<Promise>
 TelephonyCall::Hold(ErrorResult& aRv)
 {
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
   if (mCallState != nsITelephonyService::CALL_STATE_CONNECTED) {
-    NS_WARNING("Hold non-connected call ignored!");
-    return;
+    NS_WARNING("Hold non-connected call is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
   if (mGroup) {
-    NS_WARNING("Hold a call in conference ignored!");
-    return;
+    NS_WARNING("Hold a call in conference is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
   if (!mSwitchable) {
-    NS_WARNING("Hold a non-switchable call ignored!");
-    return;
+    NS_WARNING("Hold a non-switchable call is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
-  nsresult rv = mTelephony->Service()->HoldCall(mServiceId, mCallIndex);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return;
-  }
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = mTelephony->Service()->HoldCall(mServiceId, mCallIndex, callback);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
 
   if (mSecondId) {
     // No state transition when we switch two numbers within one TelephonyCall
     // object. Otherwise, the state here will be inconsistent with the backend
     // RIL and will never be right.
-    return;
+    return promise.forget();
   }
 
   ChangeStateInternal(nsITelephonyService::CALL_STATE_HOLDING, true);
+  return promise.forget();
 }
 
-void
+already_AddRefed<Promise>
 TelephonyCall::Resume(ErrorResult& aRv)
 {
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
   if (mCallState != nsITelephonyService::CALL_STATE_HELD) {
-    NS_WARNING("Resume non-held call ignored!");
-    return;
+    NS_WARNING("Resume non-held call is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
   if (mGroup) {
-    NS_WARNING("Resume a call in conference ignored!");
-    return;
+    NS_WARNING("Resume a call in conference is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
   if (!mSwitchable) {
-    NS_WARNING("Resume a non-switchable call ignored!");
-    return;
+    NS_WARNING("Resume a non-switchable call is rejected!");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return promise.forget();
   }
 
-  nsresult rv = mTelephony->Service()->ResumeCall(mServiceId, mCallIndex);
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
-    return;
-  }
+  nsCOMPtr<nsITelephonyCallback> callback = new TelephonyCallback(promise);
+  aRv = mTelephony->Service()->ResumeCall(mServiceId, mCallIndex, callback);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
 
   ChangeStateInternal(nsITelephonyService::CALL_STATE_RESUMING, true);
+  return promise.forget();
 }
--- a/dom/telephony/TelephonyCall.h
+++ b/dom/telephony/TelephonyCall.h
@@ -2,22 +2,21 @@
 /* vim: set ts=2 et sw=2 tw=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_telephony_telephonycall_h__
 #define mozilla_dom_telephony_telephonycall_h__
 
+#include "mozilla/dom/DOMError.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/TelephonyCallId.h"
 #include "mozilla/dom/telephony/TelephonyCommon.h"
 
-#include "mozilla/dom/DOMError.h"
-
-#include "TelephonyCallId.h"
-
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class TelephonyCall MOZ_FINAL : public DOMEventTargetHelper
 {
   nsRefPtr<Telephony> mTelephony;
@@ -86,26 +85,26 @@ public:
   }
 
   already_AddRefed<DOMError>
   GetError() const;
 
   already_AddRefed<TelephonyCallGroup>
   GetGroup() const;
 
-  void
+  already_AddRefed<Promise>
   Answer(ErrorResult& aRv);
 
-  void
+  already_AddRefed<Promise>
   HangUp(ErrorResult& aRv);
 
-  void
+  already_AddRefed<Promise>
   Hold(ErrorResult& aRv);
 
-  void
+  already_AddRefed<Promise>
   Resume(ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(statechange)
   IMPL_EVENT_HANDLER(dialing)
   IMPL_EVENT_HANDLER(alerting)
   IMPL_EVENT_HANDLER(connecting)
   IMPL_EVENT_HANDLER(connected)
   IMPL_EVENT_HANDLER(disconnecting)
--- a/dom/telephony/gonk/TelephonyService.js
+++ b/dom/telephony/gonk/TelephonyService.js
@@ -492,17 +492,17 @@ TelephonyService.prototype = {
         }
       };
 
       if (aNumber === "0") {
         this._sendToRilWorker(aClientId, "hangUpBackground", null, mmiCallback);
       } else if (aNumber === "1") {
         this._sendToRilWorker(aClientId, "hangUpForeground", null, mmiCallback);
       } else if (aNumber[0] === "1" && aNumber.length === 2) {
-        this._sendToRilWorker(aClientId, "hangUp",
+        this._sendToRilWorker(aClientId, "hangUpCall",
                               { callIndex: parseInt(aNumber[1]) }, mmiCallback);
       } else if (aNumber === "2") {
         this._sendToRilWorker(aClientId, "switchActiveCall", null, mmiCallback);
       } else if (aNumber[0] === "2" && aNumber.length === 2) {
         this._sendToRilWorker(aClientId, "separateCall",
                               { callIndex: parseInt(aNumber[1]) }, mmiCallback);
       } else if (aNumber === "3") {
         this._sendToRilWorker(aClientId, "conferenceCall", null, mmiCallback);
@@ -584,17 +584,19 @@ TelephonyService.prototype = {
         clientId: aClientId,
         options: aOptions,
         callback: aCallback
       };
 
       if (activeCall.isConference) {
         this.holdConference(aClientId);
       } else {
-        this.holdCall(aClientId, activeCall.callIndex);
+        this.holdCall(aClientId, activeCall.callIndex,
+                      { notifySuccess: function () {},
+                        notifyError: function (errorMsg) {} });
       }
     }
   },
 
   _sendDialCallRequest: function(aClientId, aOptions, aCallback) {
     this._isDialing = true;
 
     this._sendToRilWorker(aClientId, "dial", aOptions, response => {
@@ -874,63 +876,82 @@ TelephonyService.prototype = {
         return RIL.MMI_KS_SC_CALL_WAITING;
       case RIL.MMI_SC_CHANGE_PASSWORD:
         return RIL.MMI_KS_SC_CHANGE_PASSWORD;
       default:
         return RIL.MMI_KS_SC_USSD;
     }
   },
 
-  hangUp: function(aClientId, aCallIndex) {
-    let parentId = this._currentCalls[aClientId][aCallIndex].parentId;
-    if (parentId) {
-      // Should release both, child and parent, together. Since RIL holds only
-      // the parent call, we send 'parentId' to RIL.
-      this.hangUp(aClientId, parentId);
+  /**
+   * The default callback handler for call operations.
+   *
+   * @param aCallback
+   *        An callback object including notifySuccess() and notifyError(aMsg)
+   * @param aResponse
+   *        The response from ril_worker.
+   */
+  _defaultCallbackHandler: function(aCallback, aResponse) {
+    if (!aResponse.success) {
+      aCallback.notifyError(aResponse.errorMsg);
     } else {
-      this._sendToRilWorker(aClientId, "hangUp", { callIndex: aCallIndex });
+      aCallback.notifySuccess();
     }
   },
 
   startTone: function(aClientId, aDtmfChar) {
     this._sendToRilWorker(aClientId, "startTone", { dtmfChar: aDtmfChar });
   },
 
   stopTone: function(aClientId) {
     this._sendToRilWorker(aClientId, "stopTone");
   },
 
-  answerCall: function(aClientId, aCallIndex) {
-    this._sendToRilWorker(aClientId, "answerCall", { callIndex: aCallIndex });
+  answerCall: function(aClientId, aCallIndex, aCallback) {
+    this._sendToRilWorker(aClientId, "answerCall", { callIndex: aCallIndex },
+                          this._defaultCallbackHandler.bind(this, aCallback));
+  },
+
+  rejectCall: function(aClientId, aCallIndex, aCallback) {
+    this._sendToRilWorker(aClientId, "rejectCall", { callIndex: aCallIndex },
+                          this._defaultCallbackHandler.bind(this, aCallback));
   },
 
-  rejectCall: function(aClientId, aCallIndex) {
-    this._sendToRilWorker(aClientId, "rejectCall", { callIndex: aCallIndex });
+  hangUpCall: function(aClientId, aCallIndex, aCallback) {
+    let parentId = this._currentCalls[aClientId][aCallIndex].parentId;
+    if (parentId) {
+      // Should release both, child and parent, together. Since RIL holds only
+      // the parent call, we send 'parentId' to RIL.
+      this.hangUpCall(aClientId, parentId, aCallback);
+    } else {
+      this._sendToRilWorker(aClientId, "hangUpCall", { callIndex: aCallIndex },
+                            this._defaultCallbackHandler.bind(this, aCallback));
+    }
   },
 
-  holdCall: function(aClientId, aCallIndex) {
+  holdCall: function(aClientId, aCallIndex, aCallback) {
     let call = this._currentCalls[aClientId][aCallIndex];
     if (!call || !call.isSwitchable) {
-      // TODO: Bug 975949 - [B2G] Telephony should throw exceptions when some
-      // operations aren't allowed instead of simply ignoring them.
+      aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
       return;
     }
 
-    this._sendToRilWorker(aClientId, "holdCall", { callIndex: aCallIndex });
+    this._sendToRilWorker(aClientId, "holdCall", { callIndex: aCallIndex },
+                          this._defaultCallbackHandler.bind(this, aCallback));
   },
 
-  resumeCall: function(aClientId, aCallIndex) {
+  resumeCall: function(aClientId, aCallIndex, aCallback) {
     let call = this._currentCalls[aClientId][aCallIndex];
     if (!call || !call.isSwitchable) {
-      // TODO: Bug 975949 - [B2G] Telephony should throw exceptions when some
-      // operations aren't allowed instead of simply ignoring them.
+      aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
       return;
     }
 
-    this._sendToRilWorker(aClientId, "resumeCall", { callIndex: aCallIndex });
+    this._sendToRilWorker(aClientId, "resumeCall", { callIndex: aCallIndex },
+                          this._defaultCallbackHandler.bind(this, aCallback));
   },
 
   conferenceCall: function(aClientId) {
     let indexes = Object.keys(this._currentCalls[aClientId]);
     if (indexes.length < 2) {
       // TODO: Bug 975949 - [B2G] Telephony should throw exceptions when some
       // operations aren't allowed instead of simply ignoring them.
       return;
--- a/dom/telephony/ipc/PTelephony.ipdl
+++ b/dom/telephony/ipc/PTelephony.ipdl
@@ -30,22 +30,57 @@ struct USSDRequest
   nsString ussd;
 };
 
 struct HangUpConferenceRequest
 {
   uint32_t clientId;
 };
 
+struct AnswerCallRequest
+{
+  uint32_t clientId;
+  uint32_t callIndex;
+};
+
+struct HangUpCallRequest
+{
+  uint32_t clientId;
+  uint32_t callIndex;
+};
+
+struct RejectCallRequest
+{
+  uint32_t clientId;
+  uint32_t callIndex;
+};
+
+struct HoldCallRequest
+{
+  uint32_t clientId;
+  uint32_t callIndex;
+};
+
+struct ResumeCallRequest
+{
+  uint32_t clientId;
+  uint32_t callIndex;
+};
+
 union IPCTelephonyRequest
 {
   EnumerateCallsRequest;
   DialRequest;
   USSDRequest;
   HangUpConferenceRequest;
+  AnswerCallRequest;
+  HangUpCallRequest;
+  RejectCallRequest;
+  HoldCallRequest;
+  ResumeCallRequest;
 };
 
 sync protocol PTelephony {
   manager PContent;
   manages PTelephonyRequest;
 
 child:
   NotifyCallError(uint32_t aClientId, int32_t aCallIndex, nsString aError);
@@ -71,26 +106,16 @@ parent:
    * Sent when the child makes an asynchronous request to the parent.
    */
   PTelephonyRequest(IPCTelephonyRequest request);
 
   RegisterListener();
 
   UnregisterListener();
 
-  HangUpCall(uint32_t aClientId, uint32_t aCallIndex);
-
-  AnswerCall(uint32_t aClientId, uint32_t aCallIndex);
-
-  RejectCall(uint32_t aClientId, uint32_t aCallIndex);
-
-  HoldCall(uint32_t aClientId, uint32_t aCallIndex);
-
-  ResumeCall(uint32_t aClientId, uint32_t aCallIndex);
-
   ConferenceCall(uint32_t aClientId);
 
   SeparateCall(uint32_t aClientId, uint32_t aCallIndex);
 
   HoldConference(uint32_t aClientId);
 
   ResumeConference(uint32_t aClientId);
 
--- a/dom/telephony/ipc/TelephonyIPCService.cpp
+++ b/dom/telephony/ipc/TelephonyIPCService.cpp
@@ -166,73 +166,73 @@ TelephonyIPCService::Dial(uint32_t aClie
                           nsITelephonyDialCallback *aCallback)
 {
   nsCOMPtr<nsITelephonyCallback> callback = do_QueryInterface(aCallback);
   return SendRequest(nullptr, callback,
                      DialRequest(aClientId, nsString(aNumber), aIsEmergency));
 }
 
 NS_IMETHODIMP
-TelephonyIPCService::HangUp(uint32_t aClientId, uint32_t aCallIndex)
+TelephonyIPCService::AnswerCall(uint32_t aClientId, uint32_t aCallIndex,
+                                nsITelephonyCallback *aCallback)
 {
   if (!mPTelephonyChild) {
     NS_WARNING("TelephonyService used after shutdown has begun!");
     return NS_ERROR_FAILURE;
   }
 
-  mPTelephonyChild->SendHangUpCall(aClientId, aCallIndex);
-  return NS_OK;
+  return SendRequest(nullptr, aCallback, AnswerCallRequest(aClientId, aCallIndex));
 }
 
 NS_IMETHODIMP
-TelephonyIPCService::AnswerCall(uint32_t aClientId, uint32_t aCallIndex)
+TelephonyIPCService::HangUpCall(uint32_t aClientId, uint32_t aCallIndex,
+                                nsITelephonyCallback *aCallback)
 {
   if (!mPTelephonyChild) {
     NS_WARNING("TelephonyService used after shutdown has begun!");
     return NS_ERROR_FAILURE;
   }
 
-  mPTelephonyChild->SendAnswerCall(aClientId, aCallIndex);
-  return NS_OK;
+  return SendRequest(nullptr, aCallback, HangUpCallRequest(aClientId, aCallIndex));
 }
 
 NS_IMETHODIMP
-TelephonyIPCService::RejectCall(uint32_t aClientId, uint32_t aCallIndex)
+TelephonyIPCService::RejectCall(uint32_t aClientId, uint32_t aCallIndex,
+                                nsITelephonyCallback *aCallback)
 {
   if (!mPTelephonyChild) {
     NS_WARNING("TelephonyService used after shutdown has begun!");
     return NS_ERROR_FAILURE;
   }
 
-  mPTelephonyChild->SendRejectCall(aClientId, aCallIndex);
-  return NS_OK;
+  return SendRequest(nullptr, aCallback, RejectCallRequest(aClientId, aCallIndex));
 }
 
 NS_IMETHODIMP
-TelephonyIPCService::HoldCall(uint32_t aClientId, uint32_t aCallIndex)
+TelephonyIPCService::HoldCall(uint32_t aClientId, uint32_t aCallIndex,
+                              nsITelephonyCallback *aCallback)
 {
   if (!mPTelephonyChild) {
     NS_WARNING("TelephonyService used after shutdown has begun!");
     return NS_ERROR_FAILURE;
   }
 
-  mPTelephonyChild->SendHoldCall(aClientId, aCallIndex);
-  return NS_OK;
+  return SendRequest(nullptr, aCallback, HoldCallRequest(aClientId, aCallIndex));
 }
 
 NS_IMETHODIMP
-TelephonyIPCService::ResumeCall(uint32_t aClientId, uint32_t aCallIndex)
+TelephonyIPCService::ResumeCall(uint32_t aClientId, uint32_t aCallIndex,
+                                nsITelephonyCallback *aCallback)
 {
   if (!mPTelephonyChild) {
     NS_WARNING("TelephonyService used after shutdown has begun!");
     return NS_ERROR_FAILURE;
   }
 
-  mPTelephonyChild->SendResumeCall(aClientId, aCallIndex);
-  return NS_OK;
+  return SendRequest(nullptr, aCallback, ResumeCallRequest(aClientId, aCallIndex));
 }
 
 NS_IMETHODIMP
 TelephonyIPCService::ConferenceCall(uint32_t aClientId)
 {
   if (!mPTelephonyChild) {
     NS_WARNING("TelephonyService used after shutdown has begun!");
     return NS_ERROR_FAILURE;
--- a/dom/telephony/ipc/TelephonyParent.cpp
+++ b/dom/telephony/ipc/TelephonyParent.cpp
@@ -32,26 +32,81 @@ TelephonyParent::ActorDestroy(ActorDestr
   RecvUnregisterListener();
 }
 
 bool
 TelephonyParent::RecvPTelephonyRequestConstructor(PTelephonyRequestParent* aActor,
                                                   const IPCTelephonyRequest& aRequest)
 {
   TelephonyRequestParent* actor = static_cast<TelephonyRequestParent*>(aActor);
+  nsCOMPtr<nsITelephonyService> service = do_GetService(TELEPHONY_SERVICE_CONTRACTID);
+
+  if (!service) {
+    return NS_SUCCEEDED(actor->NotifyError(NS_LITERAL_STRING("InvalidStateError")));
+  }
 
   switch (aRequest.type()) {
-    case IPCTelephonyRequest::TEnumerateCallsRequest:
-      return actor->DoRequest(aRequest.get_EnumerateCallsRequest());
-    case IPCTelephonyRequest::TDialRequest:
-      return actor->DoRequest(aRequest.get_DialRequest());
-    case IPCTelephonyRequest::TUSSDRequest:
-      return actor->DoRequest(aRequest.get_USSDRequest());
-    case IPCTelephonyRequest::THangUpConferenceRequest:
-      return actor->DoRequest(aRequest.get_HangUpConferenceRequest());
+    case IPCTelephonyRequest::TEnumerateCallsRequest: {
+      nsresult rv = service->EnumerateCalls(actor);
+      if (NS_FAILED(rv)) {
+        return NS_SUCCEEDED(EnumerateCallStateComplete());
+      } else {
+        return true;
+      }
+    }
+
+    case IPCTelephonyRequest::TDialRequest: {
+      const DialRequest& request = aRequest.get_DialRequest();
+      service->Dial(request.clientId(), request.number(),
+                    request.isEmergency(), actor);
+      return true;
+    }
+
+    case IPCTelephonyRequest::TUSSDRequest: {
+      const USSDRequest& request = aRequest.get_USSDRequest();
+      service->SendUSSD(request.clientId(), request.ussd(), actor);
+      return true;
+    }
+
+    case IPCTelephonyRequest::THangUpConferenceRequest: {
+      const HangUpConferenceRequest& request = aRequest.get_HangUpConferenceRequest();
+      service->HangUpConference(request.clientId(), actor);
+      return true;
+    }
+
+    case IPCTelephonyRequest::TAnswerCallRequest: {
+      const AnswerCallRequest& request = aRequest.get_AnswerCallRequest();
+      service->AnswerCall(request.clientId(), request.callIndex(), actor);
+      return true;
+    }
+
+    case IPCTelephonyRequest::THangUpCallRequest: {
+      const HangUpCallRequest& request = aRequest.get_HangUpCallRequest();
+      service->HangUpCall(request.clientId(), request.callIndex(), actor);
+      return true;
+    }
+
+    case IPCTelephonyRequest::TRejectCallRequest: {
+      const RejectCallRequest& request = aRequest.get_RejectCallRequest();
+      service->RejectCall(request.clientId(), request.callIndex(), actor);
+      return true;
+    }
+
+    case IPCTelephonyRequest::THoldCallRequest: {
+      const HoldCallRequest& request = aRequest.get_HoldCallRequest();
+      service->HoldCall(request.clientId(), request.callIndex(), actor);
+      return true;
+    }
+
+    case IPCTelephonyRequest::TResumeCallRequest: {
+      const ResumeCallRequest& request = aRequest.get_ResumeCallRequest();
+      service->ResumeCall(request.clientId(), request.callIndex(), actor);
+      return true;
+    }
+
     default:
       MOZ_CRASH("Unknown type!");
   }
 
   return false;
 }
 
 PTelephonyRequestParent*
@@ -101,76 +156,16 @@ TelephonyParent::RecvUnregisterListener(
     do_GetService(TELEPHONY_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(service, true);
 
   mRegistered = !NS_SUCCEEDED(service->UnregisterListener(this));
   return true;
 }
 
 bool
-TelephonyParent::RecvHangUpCall(const uint32_t& aClientId,
-                                const uint32_t& aCallIndex)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(service, true);
-
-  service->HangUp(aClientId, aCallIndex);
-  return true;
-}
-
-bool
-TelephonyParent::RecvAnswerCall(const uint32_t& aClientId,
-                                const uint32_t& aCallIndex)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(service, true);
-
-  service->AnswerCall(aClientId, aCallIndex);
-  return true;
-}
-
-bool
-TelephonyParent::RecvRejectCall(const uint32_t& aClientId,
-                                const uint32_t& aCallIndex)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(service, true);
-
-  service->RejectCall(aClientId, aCallIndex);
-  return true;
-}
-
-bool
-TelephonyParent::RecvHoldCall(const uint32_t& aClientId,
-                              const uint32_t& aCallIndex)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(service, true);
-
-  service->HoldCall(aClientId, aCallIndex);
-  return true;
-}
-
-bool
-TelephonyParent::RecvResumeCall(const uint32_t& aClientId,
-                                const uint32_t& aCallIndex)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(service, true);
-
-  service->ResumeCall(aClientId, aCallIndex);
-  return true;
-}
-
-bool
 TelephonyParent::RecvConferenceCall(const uint32_t& aClientId)
 {
   nsCOMPtr<nsITelephonyService> service =
     do_GetService(TELEPHONY_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(service, true);
 
   service->ConferenceCall(aClientId);
   return true;
@@ -401,77 +396,16 @@ void
 TelephonyRequestParent::ActorDestroy(ActorDestroyReason why)
 {
   // The child process could die before this asynchronous notification, in which
   // case ActorDestroy() was called and mActorDestroyed is set to true. Return
   // an error here to avoid sending a message to the dead process.
   mActorDestroyed = true;
 }
 
-bool
-TelephonyRequestParent::DoRequest(const EnumerateCallsRequest& aRequest)
-{
-  nsresult rv = NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  if (service) {
-    rv = service->EnumerateCalls(this);
-  }
-
-  if (NS_FAILED(rv)) {
-    return NS_SUCCEEDED(EnumerateCallStateComplete());
-  }
-
-  return true;
-}
-
-bool
-TelephonyRequestParent::DoRequest(const DialRequest& aRequest)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  if (service) {
-    service->Dial(aRequest.clientId(), aRequest.number(),
-                  aRequest.isEmergency(), this);
-  } else {
-    return NS_SUCCEEDED(NotifyError(NS_LITERAL_STRING("InvalidStateError")));
-  }
-
-  return true;
-}
-
-bool
-TelephonyRequestParent::DoRequest(const USSDRequest& aRequest)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  if (service) {
-    service->SendUSSD(aRequest.clientId(), aRequest.ussd(), this);
-  } else {
-    return NS_SUCCEEDED(NotifyError(NS_LITERAL_STRING("InvalidStateError")));
-  }
-
-  return true;
-}
-
-bool
-TelephonyRequestParent::DoRequest(const HangUpConferenceRequest& aRequest)
-{
-  nsCOMPtr<nsITelephonyService> service =
-    do_GetService(TELEPHONY_SERVICE_CONTRACTID);
-  if (service) {
-    service->HangUpConference(aRequest.clientId(), this);
-  } else {
-    return NS_SUCCEEDED(NotifyError(NS_LITERAL_STRING("InvalidStateError")));
-  }
-
-  return true;
-}
-
 nsresult
 TelephonyRequestParent::SendResponse(const IPCTelephonyResponse& aResponse)
 {
   NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_FAILURE);
 
   return Send__delete__(this, aResponse) ? NS_OK : NS_ERROR_FAILURE;
 }
 
--- a/dom/telephony/ipc/TelephonyParent.h
+++ b/dom/telephony/ipc/TelephonyParent.h
@@ -42,31 +42,16 @@ protected:
 
   virtual bool
   RecvRegisterListener() MOZ_OVERRIDE;
 
   virtual bool
   RecvUnregisterListener() MOZ_OVERRIDE;
 
   virtual bool
-  RecvHangUpCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
-
-  virtual bool
-  RecvAnswerCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
-
-  virtual bool
-  RecvRejectCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
-
-  virtual bool
-  RecvHoldCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
-
-  virtual bool
-  RecvResumeCall(const uint32_t& aClientId, const uint32_t& aCallIndex) MOZ_OVERRIDE;
-
-  virtual bool
   RecvConferenceCall(const uint32_t& aClientId) MOZ_OVERRIDE;
 
   virtual bool
   RecvSeparateCall(const uint32_t& aClientId, const uint32_t& callIndex) MOZ_OVERRIDE;
 
   virtual bool
   RecvHoldConference(const uint32_t& aClientId) MOZ_OVERRIDE;
 
@@ -115,25 +100,13 @@ protected:
   virtual void
   ActorDestroy(ActorDestroyReason why);
 
   nsresult
   SendResponse(const IPCTelephonyResponse& aResponse);
 
 private:
   bool mActorDestroyed;
-
-  bool
-  DoRequest(const EnumerateCallsRequest& aRequest);
-
-  bool
-  DoRequest(const DialRequest& aRequest);
-
-  bool
-  DoRequest(const USSDRequest& aRequest);
-
-  bool
-  DoRequest(const HangUpConferenceRequest& aRequest);
 };
 
 END_TELEPHONY_NAMESPACE
 
 #endif /* mozilla_dom_telephony_TelephonyParent_h */
--- a/dom/telephony/nsIGonkTelephonyService.idl
+++ b/dom/telephony/nsIGonkTelephonyService.idl
@@ -5,17 +5,17 @@
 
 #include "nsITelephonyService.idl"
 
 %{C++
 #define GONK_TELEPHONY_SERVICE_CONTRACTID \
         "@mozilla.org/telephony/gonktelephonyservice;1"
 %}
 
-[scriptable, uuid(cbbe66d8-865b-11e4-94f1-ab441e55905b)]
+[scriptable, uuid(aec05f05-0ca5-470b-8230-cdee0209eafd)]
 interface nsIGonkTelephonyService : nsITelephonyService
 {
   void notifyAudioStateChanged(in unsigned long clientId, in short state);
 
   void notifyCallDisconnected(in unsigned long clientId, in jsval call);
 
   void notifyCallRing();
 
--- a/dom/telephony/nsITelephonyService.idl
+++ b/dom/telephony/nsITelephonyService.idl
@@ -246,17 +246,17 @@ interface nsITelephonyDialCallback : nsI
 #define TELEPHONY_SERVICE_CONTRACTID \
   "@mozilla.org/telephony/telephonyservice;1"
 %}
 
 /**
  * XPCOM component (in the content process) that provides the telephony
  * information.
  */
-[scriptable, uuid(6fa2d94b-80ee-4085-b6a0-535811ba9bb6)]
+[scriptable, uuid(fd797bcc-54e2-4e4a-9ec7-3b72862d0d78)]
 interface nsITelephonyService : nsISupports
 {
   const unsigned short CALL_STATE_UNKNOWN = 0;
   const unsigned short CALL_STATE_DIALING = 1;
   const unsigned short CALL_STATE_ALERTING = 2;
   const unsigned short CALL_STATE_CONNECTING = 3;
   const unsigned short CALL_STATE_CONNECTED = 4;
   const unsigned short CALL_STATE_HOLDING = 5;
@@ -290,25 +290,35 @@ interface nsITelephonyService : nsISuppo
    */
   void enumerateCalls(in nsITelephonyListener listener);
 
   /**
    * Functionality for making and managing phone calls.
    */
   void dial(in unsigned long clientId, in DOMString number,
             in boolean isEmergency, in nsITelephonyDialCallback callback);
-  void hangUp(in unsigned long clientId, in unsigned long callIndex);
 
   void startTone(in unsigned long clientId, in DOMString dtmfChar);
   void stopTone(in unsigned long clientId);
 
-  void answerCall(in unsigned long clientId, in unsigned long callIndex);
-  void rejectCall(in unsigned long clientId, in unsigned long callIndex);
-  void holdCall(in unsigned long clientId, in unsigned long callIndex);
-  void resumeCall(in unsigned long clientId, in unsigned long callIndex);
+  void answerCall(in unsigned long clientId,
+                  in unsigned long callIndex,
+                  in nsITelephonyCallback callback);
+  void rejectCall(in unsigned long clientId,
+                  in unsigned long callIndex,
+                  in nsITelephonyCallback callback);
+  void hangUpCall(in unsigned long clientId,
+                  in unsigned long callIndex,
+                  in nsITelephonyCallback callback);
+  void holdCall(in unsigned long clientId,
+                in unsigned long callIndex,
+                in nsITelephonyCallback callback);
+  void resumeCall(in unsigned long clientId,
+                  in unsigned long callIndex,
+                  in nsITelephonyCallback callback);
 
   void conferenceCall(in unsigned long clientId);
   void separateCall(in unsigned long clientId, in unsigned long callIndex);
   void hangUpConference(in unsigned long clientId,
                         in nsITelephonyCallback callback);
   void holdConference(in unsigned long clientId);
   void resumeConference(in unsigned long clientId);
 
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -515,73 +515,86 @@ let emulator = (function() {
           if (typeof conferenceStateChangeCallback === "function") {
             conferenceStateChangeCallback();
           }
         });
 
       promises.push(promise);
     }
 
-    call.answer();
+    promise = call.answer();
+    promises.push(promise);
 
     return Promise.all(promises).then(() => call);
   }
 
   /**
    * Hold a call.
    *
    * @param call
    *        A TelephonyCall object.
    * @return Promise<TelephonyCall>
    */
   function hold(call) {
     log("Putting the call on hold.");
 
+    let promises = [];
+
     let promise = waitForNamedStateEvent(call, "holding")
       .then(() => waitForNamedStateEvent(call, "held"));
+    promises.push(promise);
 
-    call.hold();
+    promise = call.hold();
+    promises.push(promise);
 
-    return promise;
+    return Promise.all(promises).then(() => call);
   }
 
   /**
    * Resume a call.
    *
    * @param call
    *        A TelephonyCall object.
    * @return Promise<TelephonyCall>
    */
   function resume(call) {
     log("Resuming the held call.");
 
+    let promises = [];
+
     let promise = waitForNamedStateEvent(call, "resuming")
       .then(() => waitForNamedStateEvent(call, "connected"));
+    promises.push(promise);
 
-    call.resume();
+    promise = call.resume();
+    promises.push(promise);
 
-    return promise;
+    return Promise.all(promises).then(() => call);
   }
 
   /**
    * Locally hang up a call.
    *
    * @param call
    *        A TelephonyCall object.
    * @return Promise<TelephonyCall>
    */
   function hangUp(call) {
     log("Local hanging up the call: " + call.id.number);
 
+    let promises = [];
+
     let promise = waitForNamedStateEvent(call, "disconnecting")
       .then(() => waitForNamedStateEvent(call, "disconnected"));
+    promises.push(promise);
 
-    call.hangUp();
+    promise = call.hangUp();
+    promises.push(promise);
 
-    return promise;
+    return Promise.all(promises).then(() => call);
   }
 
   /**
    * Simulate an incoming call.
    *
    * @param number
    *        A string.
    * @param numberPresentation [optional]
--- a/dom/telephony/test/marionette/test_incoming_connecting_hangup.js
+++ b/dom/telephony/test/marionette/test_incoming_connecting_hangup.js
@@ -10,19 +10,21 @@ let inCall;
 
 function incoming() {
   return gRemoteDial(inNumber)
     .then(call => inCall = call)
     .then(() => gCheckAll(null, [inCall], "", [], [inInfo.incoming]));
 }
 
 function connecting() {
-  let promise = gWaitForNamedStateEvent(inCall, "connecting");
-  inCall.answer();
-  return promise;
+  let promises = [
+    gWaitForNamedStateEvent(inCall, "connecting"),
+    inCall.answer()
+  ];
+  return Promise.all(promises).then(() => inCall);
 }
 
 function hangUp() {
   return gHangUp(inCall)
     .then(() => gCheckAll(null, [], "", [], []));
 }
 
 function remoteHangUp() {
--- a/dom/telephony/test/marionette/test_redundant_operations.js
+++ b/dom/telephony/test/marionette/test_redundant_operations.js
@@ -13,22 +13,23 @@ function error(event, action) {
 }
 
 function checkUnexpected(msg, call, event1, event2, actionCallback) {
   let error1 = error.bind(this, event1, msg);
   let error2 = error.bind(this, event2, msg);
 
   call.addEventListener(event1, error1);
   call.addEventListener(event2, error2);
-  actionCallback();
 
-  return gDelay(2000).then(() => {
-    call.removeEventListener(event1, error1);
-    call.removeEventListener(event2, error2);
-  });
+  return actionCallback().then(
+    () => ok(false, msg + "should be rejected."),
+    () => gDelay(2000).then(() => {
+      call.removeEventListener(event1, error1);
+      call.removeEventListener(event2, error2);
+    }));
 }
 
 startTest(function() {
   gRemoteDial(inNumber)
     .then(call => inCall = call)
     .then(() => gAnswer(inCall))
     .then(() => checkUnexpected("answered an active call", inCall,
                                 "connecting", "connected",
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -4,16 +4,17 @@ support-files =
 
 [test_bug900724.html]
 [test_bug1017896.html]
 [test_content_element.html]
 [test_custom_element_adopt_callbacks.html]
 [test_custom_element_callback_innerhtml.html]
 [test_custom_element_clone_callbacks.html]
 [test_custom_element_clone_callbacks_extended.html]
+[test_custom_element_import_node_created_callback.html]
 [test_nested_content_element.html]
 [test_dest_insertion_points.html]
 [test_dest_insertion_points_shadow.html]
 [test_fallback_dest_insertion_points.html]
 [test_detached_style.html]
 [test_dynamic_content_element_matching.html]
 [test_document_register.html]
 [test_document_register_base_queue.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_import_node_created_callback.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1093680
+-->
+<head>
+  <title>Test created callback order for imported custom element.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<template id="template"><x-foo><span></span></x-foo></template>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1093680">Bug 1093680</a>
+<script>
+
+var fooProtoCreatedCallbackCalled = false;
+var fooProto = Object.create(HTMLElement.prototype);
+fooProto.createdCallback = function() {
+  ok(this.firstElementChild, "When the created callback is called, the element should already have a child because the callback should only be called after cloning all the contents.");
+  fooProtoCreatedCallbackCalled = true;
+};
+
+document.registerElement("x-foo", { prototype: fooProto });
+
+var template = document.getElementById("template");
+
+// Importing node will implicityly clone the conent in the main document.
+var adoptedFoo = document.importNode(template.content, true);
+
+ok(fooProtoCreatedCallbackCalled, "Created callback should be called after importing custom element into document");
+
+</script>
+</body>
+</html>
--- a/dom/webidl/HTMLAppletElement.webidl
+++ b/dom/webidl/HTMLAppletElement.webidl
@@ -7,17 +7,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#the-applet-element
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-applet-element
-[NeedResolve]
+[NeedResolve, UnsafeInPrerendering]
 interface HTMLAppletElement : HTMLElement {
   [Pure, SetterThrows]
            attribute DOMString align;
   [Pure, SetterThrows]
            attribute DOMString alt;
   [Pure, SetterThrows]
            attribute DOMString archive;
   [Pure, SetterThrows]
--- a/dom/webidl/HTMLObjectElement.webidl
+++ b/dom/webidl/HTMLObjectElement.webidl
@@ -8,17 +8,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#HTMLObjectElement-partial
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-object-element
-[NeedResolve]
+[NeedResolve, UnsafeInPrerendering]
 interface HTMLObjectElement : HTMLElement {
   [Pure, SetterThrows]
            attribute DOMString data;
   [Pure, SetterThrows]
            attribute DOMString type;
   [Pure, SetterThrows]
            attribute boolean typeMustMatch;
   [Pure, SetterThrows]
--- a/dom/webidl/MozIcc.webidl
+++ b/dom/webidl/MozIcc.webidl
@@ -77,16 +77,23 @@ enum IccLockType
 
 enum IccContactType
 {
   "adn", // Abbreviated Dialling Number.
   "fdn", // Fixed Dialling Number.
   "sdn"  // Service Dialling Number.
 };
 
+enum IccMvnoType
+{
+  "imsi",
+  "spn",
+  "gid"
+};
+
 dictionary IccUnlockCardLockOptions
 {
   required IccLockType lockType;
 
   DOMString? pin = null; // Necessary for lock types: "pin", "pin2", "nck",
                          // "nck1", "nck2", "hnck", "cck", "spck", "rcck",
                          // "rspck".
 
@@ -310,22 +317,18 @@ interface MozIcc : EventTarget
   // Integrated Circuit Card Helpers.
 
   /**
    * Verify whether the passed data (matchData) matches with some ICC's field
    * according to the mvno type (mvnoType).
    *
    * @param mvnoType
    *        Mvno type to use to compare the match data.
-   *        Currently, we only support 'imsi'.
    * @param matchData
    *        Data to be compared with ICC's field.
    *
    * @return a DOMRequest.
    *         The request's result will be a boolean indicating the matching
    *         result.
-   *
-   * TODO: change param mvnoType to WebIDL enum after Bug 864489 -
-   *       B2G RIL: use ipdl as IPC in MozIccManager
    */
   [Throws]
-  DOMRequest matchMvno(DOMString mvnoType, DOMString matchData);
+  DOMRequest matchMvno(IccMvnoType mvnoType, DOMString matchData);
 };
--- a/dom/webidl/MozNFC.webidl
+++ b/dom/webidl/MozNFC.webidl
@@ -68,17 +68,18 @@ interface MozNFCManager {
   [CheckPermissions="nfc-manager", AvailableIn=CertifiedApps]
   Promise<void> powerOff();
 };
 
 [JSImplementation="@mozilla.org/nfc/manager;1",
  NavigatorProperty="mozNfc",
  Func="Navigator::HasNFCSupport",
  CheckPermissions="nfc nfc-share",
- AvailableIn="PrivilegedApps"]
+ AvailableIn="PrivilegedApps",
+ UnsafeInPrerendering]
 interface MozNFC : EventTarget {
   /**
    * Indicate if NFC is enabled.
    */
   readonly attribute boolean enabled;
 
   /**
    * This event will be fired when another NFCPeer is detected, and user confirms
--- a/dom/webidl/MozNFCPeer.webidl
+++ b/dom/webidl/MozNFCPeer.webidl
@@ -6,16 +6,21 @@
  * http://w3c.github.io/nfc/proposals/common/nfc.html#idl-def-NFCPeer
  *
  * Copyright © 2013 Deutsche Telekom, Inc.
  */
 
 [JSImplementation="@mozilla.org/nfc/peer;1", AvailableIn="PrivilegedApps"]
 interface MozNFCPeer {
   /**
+   * Indicate if this peer is already lost.
+   */
+  readonly attribute boolean isLost;
+
+  /**
    * Send NDEF data to peer device.
    */
   [Throws]
   Promise<void> sendNDEF(sequence<MozNDEFRecord> records);
 
   /**
    * Send file to peer device.
    */
@@ -23,13 +28,11 @@ interface MozNFCPeer {
   Promise<void> sendFile(Blob blob);
 };
 
 // Mozilla Only
 partial interface MozNFCPeer {
   [ChromeOnly]
   attribute DOMString session;
 
-  /**
-   * Indicate if this peer is already lost.
-   */
-  readonly attribute boolean isLost;
+  [ChromeOnly]
+  void notifyLost();
 };
--- a/dom/webidl/MozNFCTag.webidl
+++ b/dom/webidl/MozNFCTag.webidl
@@ -3,38 +3,41 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * Part of this idl is from:
  * http://w3c.github.io/nfc/proposals/common/nfc.html#nfctag-interface
  *
  * Copyright © 2013 Deutsche Telekom, Inc.
  */
 
+/**
+ * The enumeration of NFC Tag technologies.
+ */
 enum NFCTechType {
-  "NFC_A",
-  "NFC_B",
-  "NFC_F",
-  "NFC_V",
-  "NFC_ISO_DEP",
-  "MIFARE_CLASSIC",
-  "MIFARE_ULTRALIGHT",
-  "NFC_BARCODE"
+  "NFC-A",  // NFCForum-TS-DigitalProtocol-1.1 NFC-A.
+  "NFC-B",  // NFCForum-TS-DigitalProtocol-1.1 NFC-B.
+  "NFC-F",  // NFCForum-TS-DigitalProtocol-1.1 NFC-F.
+  "NFC-V",  // ISO 15693.
+  "ISO-DEP",  // NFCForum-TS-DigitalProtocol-1.1 ISO-DEP.
+  "MIFARE-Classic",  // MIFARE Classic from NXP.
+  "MIFARE-Ultralight",  // MIFARE Ultralight from NXP.
+  "NFC-Barcode" // NFC Barcode from Kovio.
 };
 
 /**
  * The enumeration of the types of the tag, the type of a tag could be either
- * one of those types defined in NFC Forum (type1 ~ type 4), or it could be a
- * NXP-specific tag, like Mifare Classic.
+ * one of those types defined in NFC Forum Tag Types (Type1 ~ Type 4), or it
+ * could be a NXP-specific tag, like MIFARE Classic.
  */
 enum NFCTagType {
-  "type1",
-  "type2",
-  "type3",
-  "type4",
-  "mifare_classic"
+  "Type1",
+  "Type2",
+  "Type3",
+  "Type4",
+  "MIFARE-Classic"
 };
 
 [JSImplementation="@mozilla.org/nfc/tag;1", AvailableIn="PrivilegedApps"]
 interface MozNFCTag {
   /**
    * The supported technologies of this tag, null if unknown.
    */
   [Cached, Pure] readonly attribute sequence<NFCTechType>? techList;
@@ -65,16 +68,21 @@ interface MozNFCTag {
   readonly attribute boolean? isFormatable;
 
   /**
    * Indicate if this tag could be made Read-Only, null if unknown.
    */
   readonly attribute boolean? canBeMadeReadOnly;
 
   /**
+   * Indicate if this tag is already lost.
+   */
+  readonly attribute boolean isLost;
+
+  /**
    * Read current NDEF data on the tag.
    */
   [Throws]
   Promise<sequence<MozNDEFRecord>> readNDEF();
 
   /**
    * Write NDEF data to the tag.
    */
@@ -94,13 +102,11 @@ interface MozNFCTag {
   Promise<void> format();
 };
 
 // Mozilla Only
 partial interface MozNFCTag {
   [ChromeOnly]
   attribute DOMString session;
 
-  /**
-   * Indicate if this tag is already lost.
-   */
-  readonly attribute boolean isLost;
+  [ChromeOnly]
+  void notifyLost();
 };
--- a/dom/webidl/MozWifiManager.webidl
+++ b/dom/webidl/MozWifiManager.webidl
@@ -121,17 +121,18 @@ dictionary IPConfiguration {
   short maskLength;
   DOMString gateway;
   DOMString dns1;
   DOMString dns2;
 };
 
 [JSImplementation="@mozilla.org/wifimanager;1",
  NavigatorProperty="mozWifiManager",
- Func="Navigator::HasWifiManagerSupport"]
+ Func="Navigator::HasWifiManagerSupport",
+ UnsafeInPrerendering]
 interface MozWifiManager : EventTarget {
   /**
    * Turn on/off wifi functionality.
    * @param enable true for enable, false for disable.
    * onsuccess: Wifi enable/disable successfully, including no status change.
    * onerror: Wifi enable/disable failed or prohibited.
    */
   DOMRequest setWifiEnabled(boolean enabled);
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -188,17 +188,17 @@ partial interface Navigator {
   // WebKit/Blink supports this (hardcoded ""); Trident/Presto do not.
   readonly attribute DOMString vendorSub;
   // WebKit/Blink supports this (hardcoded "20030107"); Trident/Presto don't
   readonly attribute DOMString productSub;
   // WebKit/Blink/Trident/Presto support this.
   readonly attribute boolean cookieEnabled;
   [Throws]
   readonly attribute DOMString buildID;
-  [Throws, CheckPermissions="power"]
+  [Throws, CheckPermissions="power", UnsafeInPrerendering]
   readonly attribute MozPowerManager mozPower;
 
   // WebKit/Blink/Trident/Presto support this.
   [Throws]
   boolean javaEnabled();
 
   /**
    * Navigator requests to add an idle observer to the existing window.
@@ -235,17 +235,17 @@ partial interface Navigator {
    * all locks on the topic have been released.
    *
    * The returned MozWakeLock object is a token of the lock.  You can
    * unlock the lock via the object's |unlock| method.  The lock is released
    * automatically when its associated window is unloaded.
    *
    * @param aTopic resource name
    */
-  [Throws, Pref="dom.wakelock.enabled", Func="Navigator::HasWakeLockSupport"]
+  [Throws, Pref="dom.wakelock.enabled", Func="Navigator::HasWakeLockSupport", UnsafeInPrerendering]
   MozWakeLock requestWakeLock(DOMString aTopic);
 };
 
 // nsIDOMNavigatorDeviceStorage
 partial interface Navigator {
   [Throws, Pref="device.storage.enabled"]
   DeviceStorage? getDeviceStorage(DOMString type);
   [Throws, Pref="device.storage.enabled"]
@@ -339,17 +339,17 @@ partial interface Navigator {
   [Throws, CheckPermissions="fmradio", UnsafeInPrerendering]
   readonly attribute FMRadio mozFMRadio;
 };
 #endif // MOZ_B2G_FM
 
 #ifdef MOZ_TIME_MANAGER
 // nsIDOMMozNavigatorTime
 partial interface Navigator {
-  [Throws, CheckPermissions="time"]
+  [Throws, CheckPermissions="time", UnsafeInPrerendering]
   readonly attribute MozTimeManager mozTime;
 };
 #endif // MOZ_TIME_MANAGER
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 // nsIMozNavigatorAudioChannelManager
 partial interface Navigator {
   [Throws]
--- a/dom/webidl/TelephonyCall.webidl
+++ b/dom/webidl/TelephonyCall.webidl
@@ -28,24 +28,24 @@ interface TelephonyCall : EventTarget {
 
   // Indicate whether the call can be added into TelephonyCallGroup.
   readonly attribute boolean mergeable;
 
   readonly attribute DOMError? error;
 
   readonly attribute TelephonyCallGroup? group;
 
-  [Throws]
-  void answer();
-  [Throws]
-  void hangUp();
-  [Throws]
-  void hold();
-  [Throws]
-  void resume();
+  [NewObject, Throws]
+  Promise<void> answer();
+  [NewObject, Throws]
+  Promise<void> hangUp();
+  [NewObject, Throws]
+  Promise<void> hold();
+  [NewObject, Throws]
+  Promise<void> resume();
 
   attribute EventHandler onstatechange;
   attribute EventHandler ondialing;
   attribute EventHandler onalerting;
   attribute EventHandler onconnecting;
   attribute EventHandler onconnected;
   attribute EventHandler ondisconnecting;
   attribute EventHandler ondisconnected;
--- a/dom/webidl/XULElement.webidl
+++ b/dom/webidl/XULElement.webidl
@@ -117,16 +117,19 @@ interface XULElement : Element {
 };
 
 // And the things from nsIFrameLoaderOwner
 [NoInterfaceObject]
 interface MozFrameLoaderOwner {
   [ChromeOnly]
   readonly attribute MozFrameLoader? frameLoader;
 
+  [ChromeOnly]
+  void setIsPrerendered();
+
   [ChromeOnly, Throws]
   void swapFrameLoaders(XULElement aOtherOwner);
 };
 
 XULElement implements GlobalEventHandlers;
 XULElement implements TouchEventHandlers;
 XULElement implements MozFrameLoaderOwner;
 XULElement implements OnErrorEventHandlerForNodes;
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -8,17 +8,16 @@
 #include <cutils/properties.h>
 #include "prinit.h"
 #include "js/CharacterEncoding.h"
 
 using namespace mozilla::dom;
 
 #define BUFFER_SIZE        4096
 #define COMMAND_SIZE       256
-#define PROPERTY_VALUE_MAX 80
 
 // Intentionally not trying to dlclose() this handle. That's playing
 // Russian roulette with security bugs.
 static void* sWifiLib;
 static PRCallOnceType sInitWifiLib;
 
 static PRStatus
 InitWifiLib()
@@ -38,45 +37,45 @@ GetSharedLibrary()
 static bool
 GetWifiP2pSupported()
 {
   char propP2pSupported[PROPERTY_VALUE_MAX];
   property_get("ro.moz.wifi.p2p_supported", propP2pSupported, "0");
   return (0 == strcmp(propP2pSupported, "1"));
 }
 
-int
+static int
 hex2num(char c)
 {
   if (c >= '0' && c <= '9')
     return c - '0';
   if (c >= 'a' && c <= 'f')
     return c - 'a' + 10;
   if (c >= 'A' && c <= 'F')
     return c - 'A' + 10;
   return -1;
 }
 
-int
+static int
 hex2byte(const char* hex)
 {
   int a, b;
   a = hex2num(*hex++);
   if (a < 0)
     return -1;
   b = hex2num(*hex++);
   if (b < 0)
     return -1;
   return (a << 4) | b;
 }
 
 // This function is equivalent to printf_decode() at src/utils/common.c in
 // the supplicant.
 
-uint32_t
+static uint32_t
 convertToBytes(char* buf, uint32_t maxlen, const char* str)
 {
   const char *pos = str;
   uint32_t len = 0;
   int val;
 
   while (*pos) {
     if (len == maxlen)
@@ -151,17 +150,18 @@ convertToBytes(char* buf, uint32_t maxle
 }
 
 // This is the same algorithm as in InflateUTF8StringToBuffer with Copy and
 // while ignoring invalids.
 // https://mxr.mozilla.org/mozilla-central/source/js/src/vm/CharacterEncoding.cpp#231
 
 static const uint32_t REPLACE_UTF8 = 0xFFFD;
 
-void LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aOut)
+static void
+LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aOut)
 {
   JS::UTF8Chars src(aInput, aLength);
 
   char16_t dst[aLength]; // Allocating for worst case.
 
   // Count how many char16_t characters are needed in the inflated string.
   // |i| is the index into |src|, and |j| is the the index into |dst|.
   size_t srclen = src.length();
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -5697,23 +5697,17 @@ WorkerPrivate::SetTimeout(JSContext* aCx
       extraArgVals.AppendElement(aArguments[index]);
     }
     newInfo->mExtraArgVals.SwapElements(extraArgVals);
   }
 
   newInfo->mTargetTime = TimeStamp::Now() + newInfo->mInterval;
 
   if (!newInfo->mTimeoutString.IsEmpty()) {
-    const char* filenameChars;
-    uint32_t lineNumber;
-    if (nsJSUtils::GetCallingLocation(aCx, &filenameChars, &lineNumber)) {
-      newInfo->mFilename = filenameChars;
-      newInfo->mLineNumber = lineNumber;
-    }
-    else {
+    if (!nsJSUtils::GetCallingLocation(aCx, newInfo->mFilename, &newInfo->mLineNumber)) {
       NS_WARNING("Failed to get calling location!");
     }
   }
 
   nsAutoPtr<TimeoutInfo>* insertedInfo =
     mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts));
 
   // If the timeout we just made is set to fire next then we need to update the
--- a/dom/xslt/xpath/txXPathOptimizer.cpp
+++ b/dom/xslt/xpath/txXPathOptimizer.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/Assertions.h"
 #include "txXPathOptimizer.h"
 #include "txExprResult.h"
 #include "nsIAtom.h"
 #include "nsGkAtoms.h"
 #include "txXPathNode.h"
 #include "txExpr.h"
 #include "txIXPathContext.h"
 
@@ -18,54 +19,44 @@ public:
         : mRecycler(aRecycler)
     {
     }
 
     // txIEvalContext
     nsresult getVariable(int32_t aNamespace, nsIAtom* aLName,
                          txAExprResult*& aResult)
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return NS_ERROR_FAILURE;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     bool isStripSpaceAllowed(const txXPathNode& aNode)
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return false;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     void* getPrivateContext()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return nullptr;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     txResultRecycler* recycler()
     {
         return mRecycler;
     }
     void receiveError(const nsAString& aMsg, nsresult aRes)
     {
     }
     const txXPathNode& getContextNode()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-
-        // This will return an invalid node, but we should never
-        // get here so that's fine.
-
-        return *static_cast<txXPathNode*>(nullptr);
+        MOZ_CRASH("shouldn't depend on this context");
     }
     uint32_t size()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return 1;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     uint32_t position()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return 1;
+        MOZ_CRASH("shouldn't depend on this context");
     }
 
 private:
     txResultRecycler* mRecycler;
 };
 
 
 nsresult
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1598,16 +1598,22 @@ nsXULElement::LoadSrc()
     }
     nsXULSlots* slots = static_cast<nsXULSlots*>(Slots());
     if (!slots->mFrameLoader) {
         // false as the last parameter so that xul:iframe/browser/editor
         // session history handling works like dynamic html:iframes.
         // Usually xul elements are used in chrome, which doesn't have
         // session history at all.
         slots->mFrameLoader = nsFrameLoader::Create(this, false);
+        if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::prerendered,
+                        NS_LITERAL_STRING("true"), eIgnoreCase)) {
+            nsresult rv = slots->mFrameLoader->SetIsPrerendered();
+            NS_ENSURE_SUCCESS(rv,rv);
+        }
+
         NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
     }
 
     return slots->mFrameLoader->LoadFrame();
 }
 
 nsresult
 nsXULElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
@@ -1623,16 +1629,23 @@ nsXULElement::GetFrameLoader()
     if (!slots)
         return nullptr;
 
     nsRefPtr<nsFrameLoader> loader = slots->mFrameLoader;
     return loader.forget();
 }
 
 nsresult
+nsXULElement::SetIsPrerendered()
+{
+  return SetAttr(kNameSpaceID_None, nsGkAtoms::prerendered, nullptr,
+                 NS_LITERAL_STRING("true"), true);
+}
+
+nsresult
 nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
 {
     nsCOMPtr<nsIContent> otherContent(do_QueryInterface(aOtherOwner));
     NS_ENSURE_TRUE(otherContent, NS_ERROR_NOT_IMPLEMENTED);
 
     nsXULElement* otherEl = FromContent(otherContent);
     NS_ENSURE_TRUE(otherEl, NS_ERROR_NOT_IMPLEMENTED);
 
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -435,16 +435,17 @@ public:
 
     // nsIDOMXULElement
     NS_DECL_NSIDOMXULELEMENT
 
     virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
     virtual mozilla::EventStates IntrinsicState() const MOZ_OVERRIDE;
 
     nsresult GetFrameLoader(nsIFrameLoader** aFrameLoader);
+    nsresult SetIsPrerendered();
     nsresult SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner);
 
     virtual void RecompileScriptEventListeners() MOZ_OVERRIDE;
 
     // This function should ONLY be used by BindToTree implementations.
     // The function exists solely because XUL elements store the binding
     // parent as a member instead of in the slots, as Element does.
     void SetXULBindingParent(nsIContent* aBindingParent)
new file mode 100644
--- /dev/null
+++ b/dom/xul/test/1061864.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<script>
+</script>
+<iframe id="childiframe" src="data:text/html,Test">
+</iframe>
+</body>
+</html>
--- a/dom/xul/test/chrome.ini
+++ b/dom/xul/test/chrome.ini
@@ -2,16 +2,17 @@
 support-files =
   398289-resource.xul
   bug497875-iframe.xul
   file_bug236853.rdf
   overlay1_bug335375.xul
   overlay2_bug335375.xul
   window_bug583948.xul
   window_bug757137.xul
+  1061864.html
 
 [test_bug199692.xul]
 [test_bug233643.xul]
 [test_bug236853.xul]
 [test_bug311681.xul]
 [test_bug335375.xul]
 [test_bug391002.xul]
 [test_bug398289.html]
@@ -21,10 +22,12 @@ support-files =
 [test_bug445177.xul]
 [test_bug449457.xul]
 [test_bug468176.xul]
 [test_bug497875.xul]
 [test_bug583948.xul]
 [test_bug640158_overlay_persist.xul]
 [test_bug757137.xul]
 [test_bug775972.xul]
+[test_bug1061864_1.xul]
+[test_bug1061864_2.xul]
 [test_bug1070049_throw_from_script.xul]
 [test_import_xul_to_content.xul]
new file mode 100644
--- /dev/null
+++ b/dom/xul/test/test_bug1061864_1.xul
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1061864
+-->
+<window title="Mozilla Bug 1061864"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="RunTest();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+  /** Test for Bug 1061864 **/
+  SimpleTest.waitForExplicitFinish();
+
+  function RunTest()
+  {
+    // Test that the docshell belonging to a prerendered frame loader will
+    // be created with the correct prerendered flag.
+    test(false, function() {
+      test(true, function() {
+        SimpleTest.finish();
+      });
+    });
+  }
+
+  function test(prerendered, callback) {
+    var parentIframe = document.createElement("iframe");
+    if (prerendered) {
+      parentIframe.setIsPrerendered();
+    }
+    parentIframe.onload = function() {
+      var docShell = parentIframe.frameLoader.docShell;
+      is(docShell.isPrerendered, prerendered, "The docshell is" + (prerendered ? "" : " not") + " prerendered");
+      callback();
+    }
+    document.documentElement.appendChild(parentIframe);
+  }
+  ]]>
+  </script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061864"
+     target="_blank">Mozilla Bug 1061864</a>
+  </body>
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/xul/test/test_bug1061864_2.xul
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1061864
+-->
+<window title="Mozilla Bug 1061864"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="RunTest();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+  /** Test for Bug 1061864 **/
+  SimpleTest.waitForExplicitFinish();
+
+  function RunTest()
+  {
+    // Test that the docshell prerendered flag will be correctly inherited in
+    // prerendered documents.
+    test(false, function() {
+      test(true, function() {
+        SimpleTest.finish();
+      });
+    });
+  }
+
+  function test(prerendered, callback) {
+    var parentIframe = document.createElement("iframe");
+    if (prerendered) {
+      parentIframe.setIsPrerendered();
+    }
+    parentIframe.setAttribute("src", "1061864.html");
+    parentIframe.onload = function() {
+      var childIframe = parentIframe.contentDocument.getElementById("childiframe");
+      var childDocShell = childIframe.frameLoader.docShell;
+      is(childDocShell.isPrerendered, prerendered, "The docshell is" + (prerendered ? "" : " not") + " prerendered");
+      callback();
+    }
+    document.documentElement.appendChild(parentIframe);
+  }
+  ]]>
+  </script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061864"
+     target="_blank">Mozilla Bug 1061864</a>
+  </body>
+</window>
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -520,21 +520,28 @@ GLScreenBuffer::Readback(SharedSurface* 
 
   bool needsSwap = src != SharedSurf();
   if (needsSwap) {
       SharedSurf()->UnlockProd();
       src->LockProd();
   }
 
   {
+      // Even though we're reading. We're doing it on
+      // the producer side. So we call ProducerAcquire
+      // instead of ConsumerAcquire.
+      src->ProducerAcquire();
+
       UniquePtr<ReadBuffer> buffer = CreateRead(src);
       MOZ_ASSERT(buffer);
 
       ScopedBindFramebuffer autoFB(mGL, buffer->mFB);
       ReadPixelsIntoDataSurface(mGL, dest);
+
+      src->ProducerRelease();
   }
 
   if (needsSwap) {
       src->UnlockProd();
       SharedSurf()->LockProd();
   }
 }
 
--- a/gfx/gl/SharedSurfaceIO.cpp
+++ b/gfx/gl/SharedSurfaceIO.cpp
@@ -97,50 +97,29 @@ SharedSurface_IOSurface::SharedSurface_I
                                                  const gfx::IntSize& size,
                                                  bool hasAlpha)
   : SharedSurface(SharedSurfaceType::IOSurface,
                   AttachmentType::GLTexture,
                   gl,
                   size,
                   hasAlpha)
   , mIOSurf(ioSurf)
-  , mCurConsGL(nullptr)
-  , mConsTex(0)
 {
     gl->MakeCurrent();
     mProdTex = 0;
     gl->fGenTextures(1, &mProdTex);
     BackTextureWithIOSurf(gl, mProdTex, mIOSurf);
 }
 
-GLuint
-SharedSurface_IOSurface::ConsTexture(GLContext* consGL)
-{
-    if (!mCurConsGL) {
-        mCurConsGL = consGL;
-    }
-    MOZ_ASSERT(consGL == mCurConsGL);
-
-    if (!mConsTex) {
-        consGL->MakeCurrent();
-        mConsTex = 0;
-        consGL->fGenTextures(1, &mConsTex);
-        BackTextureWithIOSurf(consGL, mConsTex, mIOSurf);
-    }
-
-    return mConsTex;
-}
-
 SharedSurface_IOSurface::~SharedSurface_IOSurface()
 {
     if (mProdTex) {
         DebugOnly<bool> success = mGL->MakeCurrent();
         MOZ_ASSERT(success);
         mGL->fDeleteTextures(1, &mProdTex);
-        mGL->fDeleteTextures(1, &mConsTex); // This will work if we're shared.
     }
 }
 
 ////////////////////////////////////////////////////////////////////////
 // SurfaceFactory_IOSurface
 
 /*static*/ UniquePtr<SurfaceFactory_IOSurface>
 SurfaceFactory_IOSurface::Create(GLContext* gl,
--- a/gfx/gl/SharedSurfaceIO.h
+++ b/gfx/gl/SharedSurfaceIO.h
@@ -41,39 +41,31 @@ public:
         return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
     }
 
     static SharedSurface_IOSurface* Cast(SharedSurface *surf) {
         MOZ_ASSERT(surf->mType == SharedSurfaceType::IOSurface);
         return static_cast<SharedSurface_IOSurface*>(surf);
     }
 
-    GLuint ConsTexture(GLContext* consGL);
-
-    GLenum ConsTextureTarget() const {
-        return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
-    }
-
     MacIOSurface* GetIOSurface() const {
         return mIOSurf;
     }
 
     virtual bool NeedsIndirectReads() const MOZ_OVERRIDE {
         return true;
     }
 
 private:
     SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
                             GLContext* gl, const gfx::IntSize& size,
                             bool hasAlpha);
 
     RefPtr<MacIOSurface> mIOSurf;
     GLuint mProdTex;
-    const GLContext* mCurConsGL;
-    GLuint mConsTex;
 };
 
 class SurfaceFactory_IOSurface : public SurfaceFactory
 {
 public:
     // Infallible.
     static UniquePtr<SurfaceFactory_IOSurface> Create(GLContext* gl,
                                                       const SurfaceCaps& caps);
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -160,18 +160,16 @@ enum SurfaceInitMode
  *  for each quad to be composited:
  *    call MakeCurrent if necessary (not necessary if no other context has been
  *      made current),
  *    take care of any texture upload required to composite the quad, this step
  *      is backend-dependent,
  *    construct an EffectChain for the quad,
  *    call DrawQuad,
  *  call EndFrame.
- * If the user has to stop compositing at any point before EndFrame, call
- * AbortFrame.
  * If the compositor is usually used for compositing but compositing is
  * temporarily done without the compositor, call EndFrameForExternalComposition
  * after compositing each frame so the compositor can remain internally
  * consistent.
  *
  * By default, the compositor will render to the screen, to render to a target,
  * call SetTargetContext or SetRenderTarget, the latter with a target created
  * by CreateRenderTarget or CreateRenderTargetFromSource.
@@ -351,21 +349,16 @@ public:
   /**
    * Post-rendering stuff if the rendering is done outside of this Compositor
    * e.g., by Composer2D.
    * aTransform is the transform from user space to window space.
    */
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) = 0;
 
   /**
-   * Tidy up if BeginFrame has been called, but EndFrame won't be.
-   */
-  virtual void AbortFrame() = 0;
-
-  /**
    * Setup the viewport and projection matrix for rendering to a target of the
    * given dimensions. The size and transform here will override those set in
    * BeginFrame. BeginFrame sets a size and transform for the default render
    * target, usually the screen. Calling this method prepares the compositor to
    * render using a different viewport (that is, size and transform), usually
    * associated with a new render target.
    */
   virtual void PrepareViewport(const gfx::IntSize& aSize) = 0;
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -496,19 +496,10 @@ BasicCompositor::EndFrame()
   if (!mTarget) {
     mWidget->EndRemoteDrawing();
   }
 
   mDrawTarget = nullptr;
   mRenderTarget = nullptr;
 }
 
-void
-BasicCompositor::AbortFrame()
-{
-  mRenderTarget->mDrawTarget->PopClip();
-  mRenderTarget->mDrawTarget->PopClip();
-  mDrawTarget = nullptr;
-  mRenderTarget = nullptr;
-}
-
 }
 }
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -95,17 +95,16 @@ public:
                           const gfx::Rect& aRenderBounds,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE;
   virtual void EndFrame() MOZ_OVERRIDE;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE
   {
     NS_RUNTIMEABORT("We shouldn't ever hit this");
   }
-  virtual void AbortFrame() MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE { return true; }
   virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE { return INT32_MAX; }
   virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE { }
   
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE {
   }
old mode 100644
new mode 100755
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -287,25 +287,29 @@ ContainerPrepare(ContainerT* aContainer,
   }
 
   CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer());
 
   /**
    * Setup our temporary surface for rendering the contents of this container.
    */
 
+  gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
+  if (surfaceRect.IsEmpty()) {
+    return;
+  }
+
   bool surfaceCopyNeeded;
   // DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
   aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
   if (aContainer->UseIntermediateSurface()) {
     if (!surfaceCopyNeeded) {
       RefPtr<CompositingRenderTarget> surface = nullptr;
 
       RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
-      gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
       if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
         surface = lastSurf;
       }
 
       if (!surface) {
         // If we don't need a copy we can render to the intermediate now to avoid
         // unecessary render target switching. This brings a big perf boost on mobile gpus.
         surface = CreateOrRecycleTarget(aContainer, aManager);
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -299,16 +299,18 @@ ImageLayerD3D10::RenderLayer()
 
     effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector(
       ShaderConstantRectD3D10(
         (float)yuvImage->GetData()->mPicX / yuvImage->GetData()->mYSize.width,
         (float)yuvImage->GetData()->mPicY / yuvImage->GetData()->mYSize.height,
         (float)yuvImage->GetData()->mPicSize.width / yuvImage->GetData()->mYSize.width,
         (float)yuvImage->GetData()->mPicSize.height / yuvImage->GetData()->mYSize.height)
        );
+  } else {
+    MOZ_CRASH("unexpected image format");
   }
 
   bool resetTexCoords = image->GetFormat() == ImageFormat::PLANAR_YCBCR;
   image = nullptr;
   autoLock.Unlock();
 
   technique->GetPassByIndex(0)->Apply(0);
   device()->Draw(4, 0);
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -120,21 +120,16 @@ public:
 
   /**
    * Post rendering stuff if the rendering is outside of this Compositor
    * e.g., by Composer2D
    */
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE {}
 
   /**
-   * Tidy up if BeginFrame has been called, but EndFrame won't be
-   */
-  virtual void AbortFrame() MOZ_OVERRIDE {}
-
-  /**
    * Setup the viewport and projection matrix for rendering
    * to a window of the given dimensions.
    */
   virtual void PrepareViewport(const gfx::IntSize& aSize) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
 
 #ifdef MOZ_DUMP_PAINTING
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -64,18 +64,16 @@ public:
                           const gfx::Rect& aRenderBounds,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE;
 
   virtual void EndFrame() MOZ_OVERRIDE;
 
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE {}
 
-  virtual void AbortFrame() MOZ_OVERRIDE {}
-
   virtual void PrepareViewport(const gfx::IntSize& aSize) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE{ return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D9"; }
 #endif
 
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -194,16 +194,17 @@ static Thread* CompositorThread() {
 static void SetThreadPriority()
 {
   hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
 }
 
 CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget)
   : mNeedsComposite(false)
   , mIsObservingVsync(false)
+  , mVsyncNotificationsSkipped(0)
   , mCompositorParent(aCompositorParent)
   , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
   , mCurrentCompositeTask(nullptr)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWidget != nullptr);
   mCompositorVsyncDispatcher = aWidget->GetCompositorVsyncDispatcher();
 #ifdef MOZ_WIDGET_GONK
@@ -280,16 +281,19 @@ CompositorVsyncObserver::Composite(TimeS
   {
     MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
     mCurrentCompositeTask = nullptr;
   }
 
   if (mNeedsComposite && mCompositorParent) {
     mNeedsComposite = false;
     mCompositorParent->CompositeCallback(aVsyncTimestamp);
+    mVsyncNotificationsSkipped = 0;
+  } else if (mVsyncNotificationsSkipped++ > gfxPrefs::CompositorUnobserveCount()) {
+    UnobserveVsync();
   }
 
   DispatchTouchEvents(aVsyncTimestamp);
 }
 
 bool
 CompositorVsyncObserver::NeedsComposite()
 {
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -112,16 +112,17 @@ private:
   void Composite(TimeStamp aVsyncTimestamp);
   void NotifyCompositeTaskExecuted();
   void ObserveVsync();
   void UnobserveVsync();
   void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
 
   bool mNeedsComposite;
   bool mIsObservingVsync;
+  int32_t mVsyncNotificationsSkipped;
   nsRefPtr<CompositorParent> mCompositorParent;
   nsRefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
 
   mozilla::Monitor mCurrentCompositeTaskMonitor;
   CancelableTask* mCurrentCompositeTask;
 };
 
 class CompositorParent MOZ_FINAL : public PCompositorParent,
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -571,17 +571,17 @@ CompositorOGL::BeginFrame(const nsIntReg
                           const Rect *aClipRectIn,
                           const Rect& aRenderBounds,
                           Rect *aClipRectOut,
                           Rect *aRenderBoundsOut)
 {
   PROFILER_LABEL("CompositorOGL", "BeginFrame",
     js::ProfileEntry::Category::GRAPHICS);
 
-  MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
+  MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
 
   mFrameInProgress = true;
   gfx::Rect rect;
   if (mUseExternalSurfaceSize) {
     rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
   } else {
     rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
   }
@@ -1318,28 +1318,16 @@ CompositorOGL::EndFrameForExternalCompos
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   }
   if (mTexturePool) {
     mTexturePool->EndFrame();
   }
 }
 
 void
-CompositorOGL::AbortFrame()
-{
-  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
-  mFrameInProgress = false;
-  mCurrentRenderTarget = nullptr;
-
-  if (mTexturePool) {
-    mTexturePool->EndFrame();
-  }
-}
-
-void
 CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
 {
   mSurfaceSize.width = aSize.width;
   mSurfaceSize.height = aSize.height;
 }
 
 void
 CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform)
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -234,17 +234,16 @@ public:
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE;
 
   virtual void EndFrame() MOZ_OVERRIDE;
   virtual void SetFBAcquireFence(Layer* aLayer) MOZ_OVERRIDE;
   virtual FenceHandle GetReleaseFence() MOZ_OVERRIDE;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE;
-  virtual void AbortFrame() MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE;
 
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE
   {
     if (!mGLContext)
       return false;
     int32_t maxSize = GetMaxTextureSize();
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -14,16 +14,17 @@
 #include "nsCoord.h"                    // for nscoord
 #include "nsError.h"                    // for nsresult
 #include "nsPoint.h"                    // for nsIntPoint, nsPoint
 #include "nsRect.h"                     // for nsIntRect, nsRect
 #include "nsMargin.h"                   // for nsIntMargin
 #include "nsStringGlue.h"               // for nsCString
 #include "xpcom-config.h"               // for CPP_THROW_NEW
 #include "mozilla/TypedEnum.h"          // for the VisitEdges typed enum
+#include "mozilla/Move.h"               // for mozilla::Move
 
 class nsIntRegion;
 class gfx3DMatrix;
 
 #include "pixman.h"
 
 /* For information on the internal representation look at pixman-region.c
  *
@@ -56,16 +57,23 @@ class nsRegion
 public:
   nsRegion () { pixman_region32_init(&mImpl); }
   MOZ_IMPLICIT nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
                                                                           aRect.x,
                                                                           aRect.y,
                                                                           aRect.width,
                                                                           aRect.height); }
   nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
+  nsRegion (nsRegion&& aRegion) { mImpl = aRegion.mImpl; pixman_region32_init(&aRegion.mImpl); }
+  nsRegion& operator = (nsRegion&& aRegion) {
+      pixman_region32_fini(&mImpl);
+      mImpl = aRegion.mImpl;
+      pixman_region32_init(&aRegion.mImpl);
+      return *this;
+  }
  ~nsRegion () { pixman_region32_fini(&mImpl); }
   nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
   nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
   bool operator==(const nsRegion& aRgn) const
   {
     return IsEqual(aRgn);
   }
   bool operator!=(const nsRegion& aRgn) const
@@ -456,18 +464,20 @@ class NS_GFX nsIntRegion
 {
   friend class nsIntRegionRectIterator;
   friend class nsRegion;
 
 public:
   nsIntRegion () {}
   MOZ_IMPLICIT nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
   nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
+  nsIntRegion (nsIntRegion&& aRegion) : mImpl (mozilla::Move(aRegion.mImpl)) {}
   nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
   nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
+  nsIntRegion& operator = (nsIntRegion&& aRegion) { mImpl = mozilla::Move(aRegion.mImpl); return *this; }
 
   bool operator==(const nsIntRegion& aRgn) const
   {
     return IsEqual(aRgn);
   }
   bool operator!=(const nsIntRegion& aRgn) const
   {
     return !(*this == aRgn);
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -214,16 +214,19 @@ private:
   DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled",             PerfWarnings, bool, false);
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
 
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
 
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled",            HardwareVsyncEnabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.vsync.compositor",                  VsyncAlignedCompositor, bool, false);
+  // On b2g, in really bad cases, I've seen up to 80 ms delays between touch events and the main thread
+  // processing them. So 80 ms / 16 = 5 vsync events. Double it up just to be on the safe side, so 10.
+  DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count",  CompositorUnobserveCount, int32_t, 10);
   DECL_GFX_PREF(Once, "gfx.touch.resample",                    TouchResampling, bool, false);
   // These times should be in milliseconds
   DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict",        TouchResampleMaxPredict, int32_t, 8);
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5);
   DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold",    TouchResampleVsyncDelayThreshold, int32_t, 20);
   DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
 
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
--- a/js/src/asmjs/AsmJSSignalHandlers.cpp
+++ b/js/src/asmjs/AsmJSSignalHandlers.cpp
@@ -433,46 +433,62 @@ HandleFault(PEXCEPTION_POINTERS exceptio
     EXCEPTION_RECORD *record = exception->ExceptionRecord;
     CONTEXT *context = exception->ContextRecord;
 
     if (record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
         return false;
 
     uint8_t **ppc = ContextToPC(context);
     uint8_t *pc = *ppc;
-    MOZ_ASSERT(pc == record->ExceptionAddress);
 
     if (record->NumberParameters < 2)
         return false;
 
     // Don't allow recursive handling of signals, see AutoSetHandlingSignal.
     JSRuntime *rt = RuntimeForCurrentThread();
     if (!rt || rt->handlingSignal)
         return false;
     AutoSetHandlingSignal handling(rt);
 
     AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
     if (!activation)
         return false;
 
+# if defined(JS_CODEGEN_X64)
     const AsmJSModule &module = activation->module();
-    if (!module.containsFunctionPC(pc))
-        return false;
 
-# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     void *faultingAddress = (void*)record->ExceptionInformation[1];
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
     {
         return false;
     }
 
+    if (!module.containsFunctionPC(pc)) {
+        // On Windows, it is possible for InterruptRunningCode to execute
+        // between a faulting heap access and the handling of the fault due
+        // to InterruptRunningCode's use of SuspendThread. When this happens,
+        // after ResumeThread, the exception handler is called with pc equal to
+        // module.interruptExit, which is logically wrong. The Right Thing would
+        // be for the OS to make fault-handling atomic (so that CONTEXT.pc was
+        // always the logically-faulting pc). Fortunately, we can detect this
+        // case and silence the exception ourselves (the exception will
+        // retrigger after the interrupt jumps back to resumePC).
+        if (pc == module.interruptExit() &&
+            module.containsFunctionPC(activation->resumePC()) &&
+            module.lookupHeapAccess(activation->resumePC()))
+        {
+            return true;
+        }
+        return false;
+    }
+
     const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
     if (!heapAccess)
         return false;
 
     // Also not necessary, but, since we can, do.
     if (heapAccess->isLoad() != !record->ExceptionInformation[0])
         return false;
 
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1,12 +1,53 @@
 /* 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/. */
 
+// ES6 draft rev30 (2014/12/24) 22.2.3.7 %TypedArray%.prototype.every(callbackfn[, thisArg]).
+function TypedArrayEvery(callbackfn, thisArg = undefined) {
+    // This function is not generic.
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
+                            "TypedArrayEvery");
+    }
+
+    // Steps 1-2.
+    var O = this;
+
+    // Steps 3-5.
+    var len = TypedArrayLength(O);
+
+    // Step 6.
+    if (arguments.length === 0)
+        ThrowError(JSMSG_MISSING_FUN_ARG, 0, "%TypedArray%.prototype.every");
+    if (!IsCallable(callbackfn))
+        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+
+    // Step 7.
+    var T = thisArg;
+
+    // Steps 8-9.
+    // Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
+    for (var k = 0; k < len; k++) {
+        // Steps 9.d.i-9.d.ii.
+        var kValue = O[k];
+
+        // Steps 9.d.iii-9.d.iv.
+        var testResult = callFunction(callbackfn, T, kValue, k, O);
+
+        // Step 9.d.v.
+        if (!testResult)
+            return false;
+    }
+
+    // Step 10.
+    return true;
+}
+
 // ES6 draft rev29 (2014/12/06) 22.2.3.8 %TypedArray%.prototype.fill(value [, start [, end ]])
 function TypedArrayFill(value, start = 0, end = undefined) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, value, start, end,
                             "TypedArrayFill");
     }
 
@@ -278,16 +319,57 @@ function TypedArrayReverse() {
         O[lower] = upperValue;
         O[upper] = lowerValue;
     }
 
     // Step 9.
     return O;
 }
 
+// ES6 draft rev30 (2014/12/24) 22.2.3.25 %TypedArray%.prototype.some(callbackfn[, thisArg]).
+function TypedArraySome(callbackfn, thisArg = undefined) {
+    // This function is not generic.
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
+                            "TypedArraySome");
+    }
+
+    // Steps 1-2.
+    var O = this;
+
+    // Steps 3-5.
+    var len = TypedArrayLength(O);
+
+    // Step 6.
+    if (arguments.length === 0)
+        ThrowError(JSMSG_MISSING_FUN_ARG, 0, "%TypedArray%.prototype.some");
+    if (!IsCallable(callbackfn))
+        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+
+    // Step 7.
+    var T = thisArg;
+
+    // Steps 8-9.
+    // Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
+    for (var k = 0; k < len; k++) {
+        // Steps 9.d.i-9.d.ii.
+        var kValue = O[k];
+
+        // Steps 9.d.iii-9.d.iv.
+        var testResult = callFunction(callbackfn, T, kValue, k, O);
+
+        // Step 9.d.v.
+        if (testResult)
+            return true;
+    }
+
+    // Step 10.
+    return false;
+}
+
 // Proposed for ES7:
 // https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
 function TypedArrayIncludes(searchElement, fromIndex = 0) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, searchElement,
                             fromIndex, "TypedArrayIncludes");
     }
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -115,21 +115,23 @@ MarkExactStackRootsAcrossTypes(T context
     MarkExactStackRootList<Value, MarkValueRoot>(trc, context, "exact-value");
     MarkExactStackRootList<types::Type, MarkTypeRoot>(trc, context, "types::Type");
     MarkExactStackRootList<Bindings, MarkBindingsRoot>(trc, context, "Bindings");
     MarkExactStackRootList<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(
         trc, context, "JSPropertyDescriptor");
     MarkExactStackRootList<PropDesc, MarkPropDescRoot>(trc, context, "PropDesc");
 }
 
+#ifdef JSGC_FJGENERATIONAL
 static void
 MarkExactStackRoots(ThreadSafeContext* cx, JSTracer *trc)
 {
     MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx, trc);
 }
+#endif
 
 static void
 MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
 {
     for (ContextIter cx(rt); !cx.done(); cx.next())
         MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx.get(), trc);
     MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
 }
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -292,17 +292,17 @@ static const size_t PHASE_DAG_NONE = 0;
 // read-only memory anyway.)
 struct ExtraPhaseInfo
 {
     // Depth in the tree of each phase type
     size_t depth;
 
     // Index into the set of parallel arrays of timing data, for parents with
     // at least one multi-parented child
-    int dagSlot;
+    size_t dagSlot;
 };
 
 static const Phase PHASE_NO_PARENT = PHASE_LIMIT;
 
 struct DagChildEdge {
     Phase parent;
     Phase child;
 } dagChildEdges[] = {
@@ -377,17 +377,17 @@ static const PhaseInfo phases[] = {
         { PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS },
         { PHASE_MARK_ROOTERS, "Mark Rooters", PHASE_MARK_ROOTS },
         { PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS },
         { PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS },
         { PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS },
     { PHASE_LIMIT, nullptr, PHASE_NO_PARENT }
 };
 
-ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
+static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
 
 // Mapping from all nodes with a multi-parented child to a Vector of all
 // multi-parented children and their descendants. (Single-parented children will
 // not show up in this list.)
 static mozilla::Vector<Phase> dagDescendants[Statistics::MAX_MULTIPARENT_PHASES + 1];
 
 struct AllPhaseIterator {
     int current;
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -77,17 +77,17 @@ static const int kWordRanges[] = {
 static const int kWordRangeCount = ArrayLength(kWordRanges);
 static const int kDigitRanges[] = { '0', '9' + 1, 0x10000 };
 static const int kDigitRangeCount = ArrayLength(kDigitRanges);
 static const int kSurrogateRanges[] = { 0xd800, 0xe000, 0x10000 };
 static const int kSurrogateRangeCount = ArrayLength(kSurrogateRanges);
 static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E,
     0x2028, 0x202A, 0x10000 };
 static const int kLineTerminatorRangeCount = ArrayLength(kLineTerminatorRanges);
-static const unsigned kMaxOneByteCharCode = 0xff;
+static const int kMaxOneByteCharCode = 0xff;
 static const int kMaxUtf16CodeUnit = 0xffff;
 
 static char16_t
 MaximumCharacter(bool ascii)
 {
     return ascii ? kMaxOneByteCharCode : kMaxUtf16CodeUnit;
 }
 
@@ -3175,17 +3175,17 @@ SplitSearchSpace(RangeBoundaryVector &ra
     // 128-character space can take up a lot of space in the ranges array if,
     // for example, we only want to match every second character (eg. the lower
     // case characters on some Unicode pages).
     int binary_chop_index = (end_index + start_index) / 2;
     // The first test ensures that we get to the code that handles the ASCII
     // range with a single not-taken branch, speeding up this important
     // character range (even non-ASCII charset-based text has spaces and
     // punctuation).
-    if (*border - 1 > (int) kMaxOneByteCharCode &&  // ASCII case.
+    if (*border - 1 > kMaxOneByteCharCode &&  // ASCII case.
         end_index - start_index > (*new_start_index - start_index) * 2 &&
         last - first > kSize * 2 &&
         binary_chop_index > *new_start_index &&
         ranges[binary_chop_index] >= first + 2 * kSize)
     {
         int scan_forward_for_section_border = binary_chop_index;;
         int new_border = (ranges[binary_chop_index] | kMask) + 1;
 
--- a/js/src/irregexp/RegExpParser.cpp
+++ b/js/src/irregexp/RegExpParser.cpp
@@ -513,17 +513,17 @@ RegExpParser<CharT>::ScanForCaptures()
     widechar n;
     while ((n = current()) != kEndMarker) {
         Advance();
         switch (n) {
           case '\\':
             Advance();
             break;
           case '[': {
-            int c;
+            widechar c;
             while ((c = current()) != kEndMarker) {
                 Advance();
                 if (c == '\\') {
                     Advance();
                 } else {
                     if (c == ']') break;
                 }
             }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug1117235.js
@@ -0,0 +1,8 @@
+load(libdir + "asserts.js");
+
+if (helperThreadCount() === 0)
+  quit(0);
+
+options('werror');
+offThreadCompileScript("function f() {'use asm'}");
+assertThrowsInstanceOf(()=>runOffThreadScript(), TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug1117255.js
@@ -0,0 +1,14 @@
+function f(stdlib, foreign, buffer) {
+    "use asm";
+    var i32 = new stdlib.Int32Array(buffer);
+    function g(i) {
+        i=i|0;
+        var j=0;
+        for (; (j>>>0) < 100000; j=(j+1)|0)
+            i32[i>>2] = j;
+    }
+    return g
+}
+var g = f(this, null, new ArrayBuffer(1<<16));
+timeout(.1, function cb() { return true });
+g(1<<16);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/iterator-noSuchMethod.js
@@ -0,0 +1,24 @@
+// __noSuchMethod__ is totally non-standard and evil, but in this one weird case
+// below we don't actually use it.  So this test is bog-standard ES6, not
+// SpiderMonkey-specific.
+//
+// In ES6:
+//   Accessing 1[Symbol.iterator]() throws a TypeError calling |undefined|.
+// In SpiderMonkey:
+//   Accessing 1[Symbol.iterator]() does *not* invoke __noSuchMethod__ looked up
+//   on 1 (or on an implicitly boxed 1), because 1 is a primitive value.
+//   SpiderMonkey then does exactly the ES6 thing here and throws a TypeError
+//   calling |undefined|.
+
+Object.prototype.__noSuchMethod__ = {};
+
+try
+{
+  var [x] = 1;
+  throw new Error("didn't throw");
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true,
+           "expected TypeError, got " + e);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1116103.js
@@ -0,0 +1,11 @@
+// |jit-test| error: ReferenceError
+
+evaluate(`
+    var g = newGlobal();
+    g.parent = this;
+    g.eval('new Debugger(parent).onExceptionUnwind = function() {};');
+`)
+{
+    while (x && 0) {}
+    let x
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1113139.js
@@ -0,0 +1,9 @@
+var lfcode = new Array();
+lfcode.push = function(x) { eval("(function() { " + x + " })();"); };
+lfcode.push("\
+function error(str) { try { eval(str); } catch (e) { return e; } }\
+const YIELD_PAREN = error('(function*(){(for (y of (yield 1, 2)) y)})').message;\
+const GENEXP_YIELD = error('(function*(){(for (x of yield 1) x)})').message;\
+const GENERIC = error('(for)').message;\
+const eval = [];\
+");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js
@@ -0,0 +1,14 @@
+load(libdir + "asserts.js");
+
+// Make sure that a proxy only has a [[Construct]] if the target does
+
+var handler = {};
+var p = new Proxy(Math.sin, handler);
+var r = Proxy.revocable(Math.sin, handler).proxy;
+
+assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
+assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
+// Better throw regardless of whether we have a handler trap.
+handler.construct = (() => ({}));
+assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
+assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -200,31 +200,30 @@ CollectJitStackScripts(JSContext *cx, co
                 // it points into the debug mode OSR handler and cannot be
                 // used to look up a corresponding ICEntry.
                 //
                 // See cases F and G in PatchBaselineFramesForDebugMode.
                 if (!entries.append(DebugModeOSREntry(script, info)))
                     return false;
             } else {
                 uint8_t *retAddr = iter.returnAddressToFp();
-                ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr);
-                if (icEntry) {
-                    // Normally, the frame is settled on a pc with an ICEntry.
-                    if (!entries.append(DebugModeOSREntry(script, *icEntry)))
+                if (iter.baselineFrame()->isDebuggerHandlingException()) {
+                    // We are in the middle of handling an exception. This
+                    // happens since we could have bailed out in place from
+                    // Ion after a throw, settling on the pc which may have no
+                    // ICEntry (e.g., Ion is free to insert resume points
+                    // after non-effectful ops for better register
+                    // allocation).
+                    jsbytecode *pc = script->baselineScript()->pcForNativeAddress(script, retAddr);
+                    if (!entries.append(DebugModeOSREntry(script, script->pcToOffset(pc))))
                         return false;
                 } else {
-                    // Otherwise, we are in the middle of handling an
-                    // exception. This happens since we could have bailed out
-                    // in place from Ion after a throw, settling on the pc
-                    // which may have no ICEntry (e.g., Ion is free to insert
-                    // resume points after non-effectful ops for better
-                    // register allocation).
-                    MOZ_ASSERT(iter.baselineFrame()->isDebuggerHandlingException());
-                    jsbytecode *pc = script->baselineScript()->pcForNativeAddress(script, retAddr);
-                    if (!entries.append(DebugModeOSREntry(script, script->pcToOffset(pc))))
+                    // Normally, the frame is settled on a pc with an ICEntry.
+                    ICEntry &icEntry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
+                    if (!entries.append(DebugModeOSREntry(script, icEntry)))
                         return false;
                 }
             }
 
             if (entries.back().needsRecompileInfo()) {
                 if (!entries.back().allocateRecompileInfo(cx))
                     return false;
 
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1064,17 +1064,17 @@ TypeAnalyzer::adjustPhiInputs(MPhi *phi)
         if (in->type() == MIRType_Value)
             continue;
 
         if (in->isUnbox() && phi->typeIncludes(in->toUnbox()->input())) {
             // The input is being explicitly unboxed, so sneak past and grab
             // the original box.
             phi->replaceOperand(i, in->toUnbox()->input());
         } else {
-            MDefinition *box = BoxInputsPolicy::alwaysBoxAt(alloc(), in->block()->lastIns(), in);
+            MDefinition *box = AlwaysBoxAt(alloc(), in->block()->lastIns(), in);
             phi->replaceOperand(i, box);
         }
     }
 }
 
 bool
 TypeAnalyzer::adjustInputs(MDefinition *def)
 {
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -4384,37 +4384,38 @@ NameIC::update(JSContext *cx, size_t cac
     cache.getScriptedLocation(&script, &pc);
 
     RootedObject obj(cx);
     RootedObject holder(cx);
     RootedShape shape(cx);
     if (!LookupName(cx, name, scopeChain, &obj, &holder, &shape))
         return false;
 
+    // Look first. Don't generate cache entries if the lookup fails.
+    if (cache.isTypeOf()) {
+        if (!FetchName<true>(cx, obj, holder, name, shape, vp))
+            return false;
+    } else {
+        if (!FetchName<false>(cx, obj, holder, name, shape, vp))
+            return false;
+    }
+
     if (cache.canAttachStub()) {
         if (IsCacheableNameReadSlot(scopeChain, obj, holder, shape, pc, cache.outputReg())) {
             if (!cache.attachReadSlot(cx, outerScript, ion, scopeChain, obj,
                                       holder.as<NativeObject>(), shape))
             {
                 return false;
             }
         } else if (IsCacheableNameCallGetter(scopeChain, obj, holder, shape)) {
             if (!cache.attachCallGetter(cx, outerScript, ion, scopeChain, obj, holder, shape, returnAddr))
                 return false;
         }
     }
 
-    if (cache.isTypeOf()) {
-        if (!FetchName<true>(cx, obj, holder, name, shape, vp))
-            return false;
-    } else {
-        if (!FetchName<false>(cx, obj, holder, name, shape, vp))
-            return false;
-    }
-
     // Monitor changes to cache entry.
     types::TypeScript::Monitor(cx, script, pc, vp);
 
     return true;
 }
 
 bool
 CallsiteCloneIC::attach(JSContext *cx, HandleScript outerScript, IonScript *ion,
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -974,17 +974,19 @@ class MAryInstruction : public MInstruct
     explicit MAryInstruction(const MAryInstruction<Arity> &other)
       : MInstruction(other)
     {
         for (int i = 0; i < (int) Arity; i++) // N.B. use |int| to avoid warnings when Arity == 0
             operands_[i].init(other.operands_[i].producer(), this);
     }
 };
 
-class MNullaryInstruction : public MAryInstruction<0>
+class MNullaryInstruction
+  : public MAryInstruction<0>,
+    public NoTypePolicy::Data
 { };
 
 class MUnaryInstruction : public MAryInstruction<1>
 {
   protected:
     explicit MUnaryInstruction(MDefinition *ins)
     {
         initOperand(0, ins);
@@ -1310,17 +1312,19 @@ class MConstant : public MNullaryInstruc
     void truncate();
 
     bool canProduceFloat32() const;
 
     ALLOW_CLONE(MConstant)
 };
 
 // Generic constructor of SIMD valuesX4.
-class MSimdValueX4 : public MQuaternaryInstruction
+class MSimdValueX4
+  : public MQuaternaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     MSimdValueX4(MIRType type, MDefinition *x, MDefinition *y, MDefinition *z, MDefinition *w)
       : MQuaternaryInstruction(x, y, z, w)
     {
         MOZ_ASSERT(IsSimdType(type));
         MOZ_ASSERT(SimdTypeToLength(type) == 4);
         mozilla::DebugOnly<MIRType> scalarType = SimdTypeToScalarType(type);
@@ -1355,17 +1359,19 @@ class MSimdValueX4 : public MQuaternaryI
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
 
     ALLOW_CLONE(MSimdValueX4)
 };
 
 // Generic constructor of SIMD valuesX4.
-class MSimdSplatX4 : public MUnaryInstruction
+class MSimdSplatX4
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     MSimdSplatX4(MIRType type, MDefinition *v)
       : MUnaryInstruction(v)
     {
         MOZ_ASSERT(IsSimdType(type));
         mozilla::DebugOnly<MIRType> scalarType = SimdTypeToScalarType(type);
         MOZ_ASSERT(scalarType == v->type());
@@ -1395,17 +1401,18 @@ class MSimdSplatX4 : public MUnaryInstru
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
 
     ALLOW_CLONE(MSimdSplatX4)
 };
 
 // A constant SIMD value.
-class MSimdConstant : public MNullaryInstruction
+class MSimdConstant
+  : public MNullaryInstruction
 {
     SimdConstant value_;
 
   protected:
     MSimdConstant(const SimdConstant &v, MIRType type) : value_(v) {
         MOZ_ASSERT(IsSimdType(type));
         setResultType(type);
         setMovable();
@@ -1430,17 +1437,19 @@ class MSimdConstant : public MNullaryIns
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     ALLOW_CLONE(MSimdConstant)
 };
 
 // Converts all lanes of a given vector into the type of another vector
-class MSimdConvert : public MUnaryInstruction
+class MSimdConvert
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MSimdConvert(MDefinition *obj, MIRType fromType, MIRType toType)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
         MOZ_ASSERT(IsSimdType(toType));
         setResultType(toType);
     }
@@ -1458,17 +1467,19 @@ class MSimdConvert : public MUnaryInstru
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     ALLOW_CLONE(MSimdConvert)
 };
 
 // Casts bits of a vector input to another SIMD type (doesn't generate code).
-class MSimdReinterpretCast : public MUnaryInstruction
+class MSimdReinterpretCast
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MSimdReinterpretCast(MDefinition *obj, MIRType fromType, MIRType toType)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
         MOZ_ASSERT(IsSimdType(toType));
         setResultType(toType);
     }
@@ -1486,17 +1497,19 @@ class MSimdReinterpretCast : public MUna
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     ALLOW_CLONE(MSimdReinterpretCast)
 };
 
 // Extracts a lane element from a given vector type, given by its lane symbol.
-class MSimdExtractElement : public MUnaryInstruction
+class MSimdExtractElement
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     SimdLane lane_;
 
     MSimdExtractElement(MDefinition *obj, MIRType type, SimdLane lane)
       : MUnaryInstruction(obj), lane_(lane)
     {
         MOZ_ASSERT(IsSimdType(obj->type()));
@@ -1528,17 +1541,19 @@ class MSimdExtractElement : public MUnar
         if (other->lane_ != lane_)
             return false;
         return congruentIfOperandsEqual(other);
     }
     ALLOW_CLONE(MSimdExtractElement)
 };
 
 // Replaces the datum in the given lane by a scalar value of the same type.
-class MSimdInsertElement : public MBinaryInstruction
+class MSimdInsertElement
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     SimdLane lane_;
 
     MSimdInsertElement(MDefinition *vec, MDefinition *val, MIRType type, SimdLane lane)
       : MBinaryInstruction(vec, val), lane_(lane)
     {
         MOZ_ASSERT(IsSimdType(type) && vec->type() == type);
@@ -1578,17 +1593,19 @@ class MSimdInsertElement : public MBinar
     bool congruentTo(const MDefinition *ins) const {
         return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
     }
 
     ALLOW_CLONE(MSimdInsertElement)
 };
 
 // Extracts the sign bits from a given vector, returning an MIRType_Int32.
-class MSimdSignMask : public MUnaryInstruction
+class MSimdSignMask
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     explicit MSimdSignMask(MDefinition *obj)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(obj->type()));
         setResultType(MIRType_Int32);
         setMovable();
@@ -1646,17 +1663,20 @@ class MSimdShuffleBase
     bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
         return ((x << 0) | (y << 3) | (z << 6) | (w << 9)) == laneMask_;
     }
 };
 
 // Applies a shuffle operation to the input, putting the input lanes as
 // indicated in the output register's lanes. This implements the SIMD.js
 // "shuffle" function, that takes one vector and one mask.
-class MSimdSwizzle : public MUnaryInstruction, public MSimdShuffleBase
+class MSimdSwizzle
+  : public MUnaryInstruction,
+    public MSimdShuffleBase,
+    public NoTypePolicy::Data
 {
   protected:
     MSimdSwizzle(MDefinition *obj, MIRType type,
                  uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
       : MUnaryInstruction(obj), MSimdShuffleBase(laneX, laneY, laneZ, laneW, type)
     {
         MOZ_ASSERT(laneX < 4 && laneY < 4 && laneZ < 4 && laneW < 4);
         MOZ_ASSERT(IsSimdType(obj->type()));
@@ -1689,17 +1709,20 @@ class MSimdSwizzle : public MUnaryInstru
     MDefinition *foldsTo(TempAllocator &alloc);
 
     ALLOW_CLONE(MSimdSwizzle)
 };
 
 // Applies a shuffle operation to the inputs, selecting the 2 first lanes of the
 // output from lanes of the first input, and the 2 last lanes of the output from
 // lanes of the second input.
-class MSimdShuffle : public MBinaryInstruction, public MSimdShuffleBase
+class MSimdShuffle
+  : public MBinaryInstruction,
+    public MSimdShuffleBase,
+    public NoTypePolicy::Data
 {
     MSimdShuffle(MDefinition *lhs, MDefinition *rhs, MIRType type,
                  uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
       : MBinaryInstruction(lhs, rhs), MSimdShuffleBase(laneX, laneY, laneZ, laneW, lhs->type())
     {
         MOZ_ASSERT(laneX < 8 && laneY < 8 && laneZ < 8 && laneW < 8);
         MOZ_ASSERT(IsSimdType(lhs->type()));
         MOZ_ASSERT(IsSimdType(rhs->type()));
@@ -1745,17 +1768,19 @@ class MSimdShuffle : public MBinaryInstr
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     ALLOW_CLONE(MSimdShuffle)
 };
 
-class MSimdUnaryArith : public MUnaryInstruction
+class MSimdUnaryArith
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         abs,
         neg,
         not_,
         reciprocal,
         reciprocalSqrt,
@@ -1794,17 +1819,19 @@ class MSimdUnaryArith : public MUnaryIns
     }
 
     ALLOW_CLONE(MSimdUnaryArith);
 };
 
 // Compares each value of a SIMD vector to each corresponding lane's value of
 // another SIMD vector, and returns a int32x4 vector containing the results of
 // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
-class MSimdBinaryComp : public MBinaryInstruction
+class MSimdBinaryComp
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         greaterThan,
         greaterThanOrEqual,
         lessThan,
         lessThanOrEqual,
         equal,
@@ -1873,17 +1900,19 @@ class MSimdBinaryComp : public MBinaryIn
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryComp()->operation();
     }
 
     ALLOW_CLONE(MSimdBinaryComp)
 };
 
-class MSimdBinaryArith : public MBinaryInstruction
+class MSimdBinaryArith
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         Add,
         Sub,
         Mul,
         Div,
         Min,
@@ -1940,17 +1969,19 @@ class MSimdBinaryArith : public MBinaryI
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryArith()->operation();
     }
 
     ALLOW_CLONE(MSimdBinaryArith)
 };
 
-class MSimdBinaryBitwise : public MBinaryInstruction
+class MSimdBinaryBitwise
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         and_,
         or_,
         xor_
     };
 
@@ -1986,17 +2017,19 @@ class MSimdBinaryBitwise : public MBinar
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryBitwise()->operation();
     }
 
     ALLOW_CLONE(MSimdBinaryBitwise)
 };
 
-class MSimdShift : public MBinaryInstruction
+class MSimdShift
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         lsh,
         rsh,
         ursh
     };
 
@@ -2029,17 +2062,19 @@ class MSimdShift : public MBinaryInstruc
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdShift()->operation();
     }
 
     ALLOW_CLONE(MSimdShift)
 };
 
-class MSimdSelect : public MTernaryInstruction
+class MSimdSelect
+  : public MTernaryInstruction,
+    public NoTypePolicy::Data
 {
     bool isElementWise_;
 
     MSimdSelect(MDefinition *mask, MDefinition *lhs, MDefinition *rhs, MIRType type,
                 bool isElementWise)
       : MTernaryInstruction(mask, lhs, rhs), isElementWise_(isElementWise)
     {
         MOZ_ASSERT(IsSimdType(type));
@@ -2367,17 +2402,19 @@ class MAryControlInstruction : public MC
         return successors_[i];
     }
     void replaceSuccessor(size_t i, MBasicBlock *succ) MOZ_FINAL MOZ_OVERRIDE {
         successors_[i] = succ;
     }
 };
 
 // Jump to the start of another basic block.
-class MGoto : public MAryControlInstruction<0, 1>
+class MGoto
+  : public MAryControlInstruction<0, 1>,
+    public NoTypePolicy::Data
 {
     explicit MGoto(MBasicBlock *target) {
         setSuccessor(0, target);
     }
 
   public:
     INSTRUCTION_HEADER(Goto)
     static MGoto *New(TempAllocator &alloc, MBasicBlock *target);
@@ -2461,17 +2498,18 @@ class MTest
     }
 #endif
 };
 
 // Equivalent to MTest(true, successor, fake), except without the foldsTo
 // method. This allows IonBuilder to insert fake CFG edges to magically protect
 // control flow for try-catch blocks.
 class MGotoWithFake
-  : public MAryControlInstruction<0, 2>
+  : public MAryControlInstruction<0, 2>,
+    public NoTypePolicy::Data
 {
     MGotoWithFake(MBasicBlock *successor, MBasicBlock *fake)
     {
         setSuccessor(0, successor);
         setSuccessor(1, fake);
     }
 
   public:
@@ -2574,17 +2612,19 @@ class AlwaysTenured
 
 typedef AlwaysTenured<JSObject*> AlwaysTenuredObject;
 typedef AlwaysTenured<NativeObject*> AlwaysTenuredNativeObject;
 typedef AlwaysTenured<JSFunction*> AlwaysTenuredFunction;
 typedef AlwaysTenured<JSScript*> AlwaysTenuredScript;
 typedef AlwaysTenured<PropertyName*> AlwaysTenuredPropertyName;
 typedef AlwaysTenured<Shape*> AlwaysTenuredShape;
 
-class MNewArray : public MUnaryInstruction
+class MNewArray
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     // Number of space to allocate for the array.
     uint32_t count_;
 
     // Heap where the array should be allocated.
     gc::InitialHeap initialHeap_;
     // Allocate space at initialization or not
@@ -2729,17 +2769,19 @@ class MNewArrayDynamicLength
         return initialHeap_;
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MNewObject : public MUnaryInstruction
+class MNewObject
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     gc::InitialHeap initialHeap_;
     bool templateObjectIsClassPrototype_;
 
     MNewObject(types::CompilerConstraintList *constraints, MConstant *templateConst,
                gc::InitialHeap initialHeap, bool templateObjectIsClassPrototype)
       : MUnaryInstruction(templateConst),
         initialHeap_(initialHeap),
@@ -2790,17 +2832,19 @@ class MNewObject : public MUnaryInstruct
     bool canRecoverOnBailout() const {
         // The template object can safely be used in the recover instruction
         // because it can never be mutated by any other function execution.
         return true;
     }
 };
 
 // Could be allocating either a new array or a new object.
-class MNewPar : public MUnaryInstruction
+class MNewPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenuredNativeObject templateObject_;
 
     MNewPar(MDefinition *cx, NativeObject *templateObject)
       : MUnaryInstruction(cx),
         templateObject_(templateObject)
     {
         setResultType(MIRType_Object);
@@ -3499,31 +3543,35 @@ class MBail : public MNullaryInstruction
         return AliasSet::None();
     }
 
     BailoutKind bailoutKind() const {
         return bailoutKind_;
     }
 };
 
-class MUnreachable : public MAryControlInstruction<0, 0>
+class MUnreachable
+  : public MAryControlInstruction<0, 0>,
+    public NoTypePolicy::Data
 {
   public:
     INSTRUCTION_HEADER(Unreachable)
 
     static MUnreachable *New(TempAllocator &alloc) {
         return new(alloc) MUnreachable();
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MAssertFloat32 : public MUnaryInstruction
+class MAssertFloat32
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     bool mustBeFloat32_;
 
     MAssertFloat32(MDefinition *value, bool mustBeFloat32)
       : MUnaryInstruction(value), mustBeFloat32_(mustBeFloat32)
     {
     }
@@ -3821,17 +3869,19 @@ class MCompare
         if (!binaryCongruentTo(ins))
             return false;
         return compareType() == ins->toCompare()->compareType() &&
                jsop() == ins->toCompare()->jsop();
     }
 };
 
 // Takes a typed value and returns an untyped value.
-class MBox : public MUnaryInstruction
+class MBox
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MBox(TempAllocator &alloc, MDefinition *ins)
       : MUnaryInstruction(ins)
     {
         setResultType(MIRType_Value);
         if (ins->resultTypeSet()) {
             setResultTypeSet(ins->resultTypeSet());
         } else if (ins->type() != MIRType_Value) {
@@ -3977,17 +4027,19 @@ class MUnbox MOZ_FINAL : public MUnaryIn
         // Should only be called if we're already Infallible or TypeBarrier
         MOZ_ASSERT(mode() != Fallible);
         mode_ = Infallible;
     }
 
     ALLOW_CLONE(MUnbox)
 };
 
-class MGuardObject : public MUnaryInstruction, public SingleObjectPolicy::Data
+class MGuardObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
 {
     explicit MGuardObject(MDefinition *ins)
       : MUnaryInstruction(ins)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Object);
     }
@@ -4023,17 +4075,18 @@ class MGuardString
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MAssertRange
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     // This is the range checked by the assertion. Don't confuse this with the
     // range_ member or the range() accessor. Since MAssertRange doesn't return
     // a value, it doesn't use those.
     const Range *assertedRange_;
 
     MAssertRange(MDefinition *ins, const Range *assertedRange)
       : MUnaryInstruction(ins), assertedRange_(assertedRange)
@@ -4059,17 +4112,18 @@ class MAssertRange
     }
 
     void printOpcode(FILE *fp) const;
 };
 
 // Caller-side allocation of |this| for |new|:
 // Given a templateobject, construct |this| for JSOP_NEW
 class MCreateThisWithTemplate
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     gc::InitialHeap initialHeap_;
 
     MCreateThisWithTemplate(types::CompilerConstraintList *constraints, MConstant *templateConst,
                             gc::InitialHeap initialHeap)
       : MUnaryInstruction(templateConst),
         initialHeap_(initialHeap)
     {
@@ -4470,17 +4524,18 @@ class MToFloat32
         return true;
     }
 
     ALLOW_CLONE(MToFloat32)
 };
 
 // Converts a uint32 to a double (coming from asm.js).
 class MAsmJSUnsignedToDouble
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MAsmJSUnsignedToDouble(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Double);
         setMovable();
     }
 
@@ -4496,17 +4551,18 @@ class MAsmJSUnsignedToDouble
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Converts a uint32 to a float32 (coming from asm.js).
 class MAsmJSUnsignedToFloat32
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MAsmJSUnsignedToFloat32(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Float32);
         setMovable();
     }
 
@@ -6015,17 +6071,18 @@ class MConcat
     bool canRecoverOnBailout() const {
         return true;
     }
 
     ALLOW_CLONE(MConcat)
 };
 
 class MConcatPar
-  : public MTernaryInstruction
+  : public MTernaryInstruction,
+    public NoTypePolicy::Data
 {
     MConcatPar(MDefinition *cx, MDefinition *left, MDefinition *right)
       : MTernaryInstruction(cx, left, right)
     {
         // Type analysis has already run, before replacing with the parallel
         // variant.
         MOZ_ASSERT(left->type() == MIRType_String && right->type() == MIRType_String);
 
@@ -6227,17 +6284,20 @@ class MLoadArrowThis
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // An arrow function's lexical |this| value is immutable.
         return AliasSet::None();
     }
 };
 
-class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
+class MPhi MOZ_FINAL
+  : public MDefinition,
+    public InlineListNode<MPhi>,
+    public NoTypePolicy::Data
 {
     js::Vector<MUse, 2, JitAllocPolicy> inputs_;
 
     TruncateKind truncateKind_;
     bool hasBackedgeType_;
     bool triedToSpecialize_;
     bool isIterator_;
     bool canProduceFloat32_;
@@ -6410,17 +6470,19 @@ class MPhi MOZ_FINAL : public MDefinitio
 
     TruncateKind operandTruncateKind(size_t index) const;
     bool needTruncation(TruncateKind kind);
     void truncate();
 };
 
 // The goal of a Beta node is to split a def at a conditionally taken
 // branch, so that uses dominated by it have a different name.
-class MBeta : public MUnaryInstruction
+class MBeta
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     // This is the range induced by a comparison and branch in a preceding
     // block. Note that this does not reflect any range constraints from
     // the input value itself, so this value may differ from the range()
     // range after it is computed.
     const Range *comparison_;
 
@@ -6444,17 +6506,19 @@ class MBeta : public MUnaryInstruction
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator &alloc);
 };
 
 // MIR representation of a Value on the OSR BaselineFrame.
 // The Value is indexed off of OsrFrameReg.
-class MOsrValue : public MUnaryInstruction
+class MOsrValue
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     ptrdiff_t frameOffset_;
 
     MOsrValue(MOsrEntry *entry, ptrdiff_t frameOffset)
       : MUnaryInstruction(entry),
         frameOffset_(frameOffset)
     {
@@ -6477,17 +6541,19 @@ class MOsrValue : public MUnaryInstructi
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
 // The pointer is indexed off of OsrFrameReg.
-class MOsrScopeChain : public MUnaryInstruction
+class MOsrScopeChain
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     explicit MOsrScopeChain(MOsrEntry *entry)
       : MUnaryInstruction(entry)
     {
         setResultType(MIRType_Object);
     }
 
@@ -6499,17 +6565,19 @@ class MOsrScopeChain : public MUnaryInst
 
     MOsrEntry *entry() {
         return getOperand(0)->toOsrEntry();
     }
 };
 
 // MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
 // The pointer is indexed off of OsrFrameReg.
-class MOsrArgumentsObject : public MUnaryInstruction
+class MOsrArgumentsObject
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     explicit MOsrArgumentsObject(MOsrEntry *entry)
       : MUnaryInstruction(entry)
     {
         setResultType(MIRType_Object);
     }
 
@@ -6521,17 +6589,19 @@ class MOsrArgumentsObject : public MUnar
 
     MOsrEntry *entry() {
         return getOperand(0)->toOsrEntry();
     }
 };
 
 // MIR representation of the return value on the OSR BaselineFrame.
 // The Value is indexed off of OsrFrameReg.
-class MOsrReturnValue : public MUnaryInstruction
+class MOsrReturnValue
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     explicit MOsrReturnValue(MOsrEntry *entry)
       : MUnaryInstruction(entry)
     {
         setResultType(MIRType_Value);
     }
 
@@ -6542,29 +6612,32 @@ class MOsrReturnValue : public MUnaryIns
     }
 
     MOsrEntry *entry() {
         return getOperand(0)->toOsrEntry();
     }
 };
 
 // Check the current frame for over-recursion past the global stack limit.
-class MCheckOverRecursed : public MNullaryInstruction
+class MCheckOverRecursed
+  : public MNullaryInstruction
 {
   public:
     INSTRUCTION_HEADER(CheckOverRecursed)
 
     static MCheckOverRecursed *New(TempAllocator &alloc) {
         return new(alloc) MCheckOverRecursed();
     }
 };
 
 // Check the current frame for over-recursion past the global stack limit.
 // Uses the per-thread recursion limit.
-class MCheckOverRecursedPar : public MUnaryInstruction
+class MCheckOverRecursedPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MCheckOverRecursedPar(MDefinition *cx)
       : MUnaryInstruction(cx)
     {
         setResultType(MIRType_None);
         setGuard();
         setMovable();
     }
@@ -6577,17 +6650,19 @@ class MCheckOverRecursedPar : public MUn
     }
 
     MDefinition *forkJoinContext() const {
         return getOperand(0);
     }
 };
 
 // Check for an interrupt (or rendezvous) in parallel mode.
-class MInterruptCheckPar : public MUnaryInstruction
+class MInterruptCheckPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MInterruptCheckPar(MDefinition *cx)
       : MUnaryInstruction(cx)
     {
         setResultType(MIRType_None);
         setGuard();
     }
 
@@ -6622,17 +6697,18 @@ class MInterruptCheck : public MNullaryI
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Check whether we need to fire the interrupt handler at loop headers and
 // function prologues in asm.js. Generated only if we can't use implicit
 // interrupt checks with signal handlers.
-class MAsmJSInterruptCheck : public MNullaryInstruction
+class MAsmJSInterruptCheck
+  : public MNullaryInstruction
 {
     Label *interruptExit_;
     CallSiteDesc funcDesc_;
 
     MAsmJSInterruptCheck(Label *interruptExit, const CallSiteDesc &funcDesc)
       : interruptExit_(interruptExit), funcDesc_(funcDesc)
     {}
 
@@ -6697,17 +6773,19 @@ class MThrowUninitializedLexical : publi
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // If not defined, set a global variable to |undefined|.
-class MDefVar : public MUnaryInstruction
+class MDefVar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenuredPropertyName name_; // Target name to be defined.
     unsigned attrs_; // Attributes to be set.
 
   private:
     MDefVar(PropertyName *name, unsigned attrs, MDefinition *scopeChain)
       : MUnaryInstruction(scopeChain),
         name_(name),
@@ -6733,17 +6811,19 @@ class MDefVar : public MUnaryInstruction
     MDefinition *scopeChain() const {
         return getOperand(0);
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
-class MDefFun : public MUnaryInstruction
+class MDefFun
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenuredFunction fun_;
 
   private:
     MDefFun(JSFunction *fun, MDefinition *scopeChain)
       : MUnaryInstruction(scopeChain),
         fun_(fun)
     {}
@@ -6972,17 +7052,17 @@ class MStringReplace
         if (pattern()->isRegExp())
             return !pattern()->toRegExp()->source()->global();
         return false;
     }
 };
 
 class MSubstr
   : public MTernaryInstruction,
-    public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>
+    public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
 {
   private:
 
     MSubstr(MDefinition *string, MDefinition *begin, MDefinition *length)
       : MTernaryInstruction(string, begin, length)
     {
         setResultType(MIRType_String);
     }
@@ -7254,17 +7334,18 @@ class MConstantElements : public MNullar
         return AliasSet::None();
     }
 
     ALLOW_CLONE(MConstantElements)
 };
 
 // Passes through an object's elements, after ensuring it is entirely doubles.
 class MConvertElementsToDoubles
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MConvertElementsToDoubles(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Elements);
     }
@@ -7368,17 +7449,18 @@ class MMaybeCopyElementsForWrite
         return false;
     }
 #endif
 
 };
 
 // Load the initialized length from an elements header.
 class MInitializedLength
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MInitializedLength(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
@@ -7402,17 +7484,18 @@ class MInitializedLength
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MInitializedLength)
 };
 
 // Store to the initialized length in an elements header. Note the input is an
 // *index*, one less than the desired length.
 class MSetInitializedLength
-  : public MAryInstruction<2>
+  : public MAryInstruction<2>,
+    public NoTypePolicy::Data
 {
     MSetInitializedLength(MDefinition *elements, MDefinition *index) {
         initOperand(0, elements);
         initOperand(1, index);
     }
 
   public:
     INSTRUCTION_HEADER(SetInitializedLength)
@@ -7431,17 +7514,18 @@ class MSetInitializedLength
         return AliasSet::Store(AliasSet::ObjectFields);
     }
 
     ALLOW_CLONE(MSetInitializedLength)
 };
 
 // Load the array length from an elements header.
 class MArrayLength
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MArrayLength(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
@@ -7465,17 +7549,18 @@ class MArrayLength
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MArrayLength)
 };
 
 // Store to the length in an elements header. Note the input is an *index*, one
 // less than the desired length.
 class MSetArrayLength
-  : public MAryInstruction<2>
+  : public MAryInstruction<2>,
+    public NoTypePolicy::Data
 {
     MSetArrayLength(MDefinition *elements, MDefinition *index) {
         initOperand(0, elements);
         initOperand(1, index);
     }
 
   public:
     INSTRUCTION_HEADER(SetArrayLength)
@@ -7601,17 +7686,18 @@ class MTypedObjectElements
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Inlined version of the js::SetTypedObjectOffset() intrinsic.
 class MSetTypedObjectOffset
-  : public MBinaryInstruction
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     MSetTypedObjectOffset(MDefinition *object, MDefinition *offset)
       : MBinaryInstruction(object, offset)
     {
         MOZ_ASSERT(object->type() == MIRType_Object);
         MOZ_ASSERT(offset->type() == MIRType_Int32);
         setResultType(MIRType_None);
@@ -7704,17 +7790,18 @@ class MNot
         return true;
     }
 };
 
 // Bailout if index + minimum < 0 or index + maximum >= length. The length used
 // in a bounds check must not be negative, or the wrong result may be computed
 // (unsigned comparisons may be used).
 class MBoundsCheck
-  : public MBinaryInstruction
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
     // Range over which to perform the bounds check, may be modified by GVN.
     int32_t minimum_;
     int32_t maximum_;
 
     MBoundsCheck(MDefinition *index, MDefinition *length)
       : MBinaryInstruction(index, length), minimum_(0), maximum_(0)
     {
@@ -7765,17 +7852,18 @@ class MBoundsCheck
     }
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MBoundsCheck)
 };
 
 // Bailout if index < minimum.
 class MBoundsCheckLower
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     int32_t minimum_;
     bool fallible_;
 
     explicit MBoundsCheckLower(MDefinition *index)
       : MUnaryInstruction(index), minimum_(0), fallible_(true)
     {
         setGuard();
@@ -8899,17 +8987,19 @@ class MStoreTypedArrayElementStatic :
     bool canConsumeFloat32(MUse *use) const {
         return use == getUseFor(1) && viewType() == Scalar::Float32;
     }
     void collectRangeInfoPreTrunc();
 };
 
 // Compute an "effective address", i.e., a compound computation of the form:
 //   base + index * scale + displacement
-class MEffectiveAddress : public MBinaryInstruction
+class MEffectiveAddress
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
     MEffectiveAddress(MDefinition *base, MDefinition *index, Scale scale, int32_t displacement)
       : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement)
     {
         MOZ_ASSERT(base->type() == MIRType_Int32);
         MOZ_ASSERT(index->type() == MIRType_Int32);
         setMovable();
         setResultType(MIRType_Int32);
@@ -9939,17 +10029,18 @@ class MForkJoinContext
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Calls the ForkJoinGetSlice stub, used for inlining the eponymous intrinsic.
 // Only applicable in ParallelExecution.
 class MForkJoinGetSlice
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MForkJoinGetSlice(MDefinition *cx)
       : MUnaryInstruction(cx)
     {
         setResultType(MIRType_Int32);
     }
 
   public:
@@ -10886,17 +10977,18 @@ class MIteratorMore
     }
 
     MDefinition *iterator() const {
         return getOperand(0);
     }
 };
 
 class MIsNoIter
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MIsNoIter(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Boolean);
         setMovable();
     }
 
@@ -11392,17 +11484,19 @@ class MTypeBarrier
     }
 
     ALLOW_CLONE(MTypeBarrier)
 };
 
 // Like MTypeBarrier, guard that the value is in the given type set. This is
 // used before property writes to ensure the value being written is represented
 // in the property types for the object.
-class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy::Data
+class MMonitorTypes
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
 {
     const types::TemporaryTypeSet *typeSet_;
     BarrierKind barrierKind_;
 
     MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types, BarrierKind kind)
       : MUnaryInstruction(def),
         typeSet_(types),
         barrierKind_(kind)
@@ -11547,17 +11641,19 @@ class MNewRunOnceCallObject : public MNe
 
     static MNewRunOnceCallObject *
     New(TempAllocator &alloc, CallObject *templateObj)
     {
         return new(alloc) MNewRunOnceCallObject(templateObj);
     }
 };
 
-class MNewCallObjectPar : public MUnaryInstruction
+class MNewCallObjectPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenured<CallObject*> templateObj_;
 
     MNewCallObjectPar(MDefinition *cx, CallObject *templateObj)
         : MUnaryInstruction(cx),
           templateObj_(templateObj)
     {
         setResultType(MIRType_Object);
@@ -11666,17 +11762,19 @@ class MEnclosingScope : public MLoadFixe
         // ScopeObject reserved slots are immutable.
         return AliasSet::None();
     }
 };
 
 // Creates a dense array of the given length.
 //
 // Note: the template object should be an *empty* dense array!
-class MNewDenseArrayPar : public MBinaryInstruction
+class MNewDenseArrayPar
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenured<ArrayObject*> templateObject_;
 
     MNewDenseArrayPar(MDefinition *cx, MDefinition *length, ArrayObject *templateObject)
       : MBinaryInstruction(cx, length),
         templateObject_(templateObject)
     {
         MOZ_ASSERT(length->type() == MIRType_Int32);
@@ -12077,17 +12175,17 @@ class MMemoryBarrier
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::TypedArrayElement);
     }
 };
 
 class MCompareExchangeTypedArrayElement
   : public MAryInstruction<4>,
-    public MixPolicy< MixPolicy<ObjectPolicy<0>, IntPolicy<1> >, MixPolicy<IntPolicy<2>, IntPolicy<3> > >
+    public Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>::Data
 {
     Scalar::Type arrayType_;
 
     explicit MCompareExchangeTypedArrayElement(MDefinition *elements, MDefinition *index,
                                                Scalar::Type arrayType, MDefinition *oldval,
                                                MDefinition *newval)
       : arrayType_(arrayType)
     {
@@ -12132,17 +12230,17 @@ class MCompareExchangeTypedArrayElement
     }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::TypedArrayElement);
     }
 };
 
 class MAtomicTypedArrayElementBinop
     : public MAryInstruction<3>,
-      public Mix3Policy< ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >
+      public Mix3Policy< ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data
 {
   private:
     AtomicOp op_;
     Scalar::Type arrayType_;
 
   protected:
     explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition *elements, MDefinition *index,
                                            Scalar::Type arrayType, MDefinition *value)
@@ -12195,17 +12293,19 @@ class MDebugger : public MNullaryInstruc
   public:
     INSTRUCTION_HEADER(Debugger);
 
     static MDebugger *New(TempAllocator &alloc) {
         return new(alloc) MDebugger();
     }
 };
 
-class MAsmJSNeg : public MUnaryInstruction
+class MAsmJSNeg
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSNeg(MDefinition *op, MIRType type)
       : MUnaryInstruction(op)
     {
         setResultType(type);
         setMovable();
     }
 
@@ -12226,17 +12326,20 @@ class MAsmJSHeapAccess
       : viewType_(vt), needsBoundsCheck_(needsBoundsCheck)
     {}
 
     Scalar::Type viewType() const { return viewType_; }
     bool needsBoundsCheck() const { return needsBoundsCheck_; }
     void removeBoundsCheck() { needsBoundsCheck_ = false; }
 };
 
-class MAsmJSLoadHeap : public MUnaryInstruction, public MAsmJSHeapAccess
+class MAsmJSLoadHeap
+  : public MUnaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     MemoryBarrierBits barrierBefore_;
     MemoryBarrierBits barrierAfter_;
 
     MAsmJSLoadHeap(Scalar::Type vt, MDefinition *ptr, bool needsBoundsCheck,
                    MemoryBarrierBits before, MemoryBarrierBits after)
       : MUnaryInstruction(ptr),
         MAsmJSHeapAccess(vt, needsBoundsCheck),
@@ -12292,17 +12395,20 @@ class MAsmJSLoadHeap : public MUnaryInst
 
     bool congruentTo(const MDefinition *ins) const;
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::AsmJSHeap);
     }
     bool mightAlias(const MDefinition *def) const;
 };
 
-class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
+class MAsmJSStoreHeap
+  : public MBinaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     MemoryBarrierBits barrierBefore_;
     MemoryBarrierBits barrierAfter_;
 
     MAsmJSStoreHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *v, bool needsBoundsCheck,
                     MemoryBarrierBits before, MemoryBarrierBits after)
       : MBinaryInstruction(ptr, v),
         MAsmJSHeapAccess(vt, needsBoundsCheck),
@@ -12330,17 +12436,20 @@ class MAsmJSStoreHeap : public MBinaryIn
     MemoryBarrierBits barrierBefore() const { return barrierBefore_; }
     MemoryBarrierBits barrierAfter() const { return barrierAfter_; }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::AsmJSHeap);
     }
 };
 
-class MAsmJSCompareExchangeHeap : public MTernaryInstruction, public MAsmJSHeapAccess
+class MAsmJSCompareExchangeHeap
+  : public MTernaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     MAsmJSCompareExchangeHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *oldv, MDefinition *newv,
                               bool needsBoundsCheck)
         : MTernaryInstruction(ptr, oldv, newv),
           MAsmJSHeapAccess(vt, needsBoundsCheck)
     {
         setGuard();             // Not removable
         setResultType(MIRType_Int32);
@@ -12360,17 +12469,20 @@ class MAsmJSCompareExchangeHeap : public
     MDefinition *oldValue() const { return getOperand(1); }
     MDefinition *newValue() const { return getOperand(2); }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::AsmJSHeap);
     }
 };
 
-class MAsmJSAtomicBinopHeap : public MBinaryInstruction, public MAsmJSHeapAccess
+class MAsmJSAtomicBinopHeap
+  : public MBinaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     AtomicOp op_;
 
     MAsmJSAtomicBinopHeap(AtomicOp op, Scalar::Type vt, MDefinition *ptr, MDefinition *v,
                           bool needsBoundsCheck)
         : MBinaryInstruction(ptr, v),
           MAsmJSHeapAccess(vt, needsBoundsCheck),
           op_(op)
@@ -12427,17 +12539,19 @@ class MAsmJSLoadGlobalVar : public MNull
 
     AliasSet getAliasSet() const {
         return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar);
     }
 
     bool mightAlias(const MDefinition *def) const;
 };
 
-class MAsmJSStoreGlobalVar : public MUnaryInstruction
+class MAsmJSStoreGlobalVar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSStoreGlobalVar(unsigned globalDataOffset, MDefinition *v)
       : MUnaryInstruction(v), globalDataOffset_(globalDataOffset)
     {}
 
     unsigned globalDataOffset_;
 
   public:
@@ -12450,17 +12564,19 @@ class MAsmJSStoreGlobalVar : public MUna
     unsigned globalDataOffset() const { return globalDataOffset_; }
     MDefinition *value() const { return getOperand(0); }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::AsmJSGlobalVar);
     }
 };
 
-class MAsmJSLoadFuncPtr : public MUnaryInstruction
+class MAsmJSLoadFuncPtr
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSLoadFuncPtr(unsigned globalDataOffset, MDefinition *index)
       : MUnaryInstruction(index), globalDataOffset_(globalDataOffset)
     {
         setResultType(MIRType_Pointer);
     }
 
     unsigned globalDataOffset_;
@@ -12520,39 +12636,45 @@ class MAsmJSParameter : public MNullaryI
 
     static MAsmJSParameter *New(TempAllocator &alloc, ABIArg abi, MIRType mirType) {
         return new(alloc) MAsmJSParameter(abi, mirType);
     }
 
     ABIArg abi() const { return abi_; }
 };
 
-class MAsmJSReturn : public MAryControlInstruction<1, 0>
+class MAsmJSReturn
+  : public MAryControlInstruction<1, 0>,
+    public NoTypePolicy::Data
 {
     explicit MAsmJSReturn(MDefinition *ins) {
         initOperand(0, ins);
     }
 
   public:
     INSTRUCTION_HEADER(AsmJSReturn);
     static MAsmJSReturn *New(TempAllocator &alloc, MDefinition *ins) {
         return new(alloc) MAsmJSReturn(ins);
     }
 };
 
-class MAsmJSVoidReturn : public MAryControlInstruction<0, 0>
+class MAsmJSVoidReturn
+  : public MAryControlInstruction<0, 0>,
+    public NoTypePolicy::Data
 {
   public:
     INSTRUCTION_HEADER(AsmJSVoidReturn);
     static MAsmJSVoidReturn *New(TempAllocator &alloc) {
         return new(alloc) MAsmJSVoidReturn();
     }
 };
 
-class MAsmJSPassStackArg : public MUnaryInstruction
+class MAsmJSPassStackArg
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSPassStackArg(uint32_t spOffset, MDefinition *ins)
       : MUnaryInstruction(ins),
         spOffset_(spOffset)
     {}
 
     uint32_t spOffset_;
 
@@ -12567,17 +12689,19 @@ class MAsmJSPassStackArg : public MUnary
     void incrementOffset(uint32_t inc) {
         spOffset_ += inc;
     }
     MDefinition *arg() const {
         return getOperand(0);
     }
 };
 
-class MAsmJSCall MOZ_FINAL : public MVariadicInstruction
+class MAsmJSCall MOZ_FINAL
+  : public MVariadicInstruction,
+    public NoTypePolicy::Data
 {
   public:
     class Callee {
       public:
         enum Which { Internal, Dynamic, Builtin };
       private:
         Which which_;
         union {
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -22,56 +22,56 @@ EnsureOperandNotFloat32(TempAllocator &a
     if (in->type() == MIRType_Float32) {
         MToDouble *replace = MToDouble::New(alloc, in);
         def->block()->insertBefore(def, replace);
         def->replaceOperand(op, replace);
     }
 }
 
 MDefinition *
-BoxInputsPolicy::boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
-{
-    if (operand->isUnbox())
-        return operand->toUnbox()->input();
-    return alwaysBoxAt(alloc, at, operand);
-}
-
-MDefinition *
-BoxInputsPolicy::alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
+js::jit::AlwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
 {
     MDefinition *boxedOperand = operand;
     // Replace Float32 by double
     if (operand->type() == MIRType_Float32) {
         MInstruction *replace = MToDouble::New(alloc, operand);
         at->block()->insertBefore(at, replace);
         boxedOperand = replace;
     }
     MBox *box = MBox::New(alloc, boxedOperand);
     at->block()->insertBefore(at, box);
     return box;
 }
 
+static MDefinition *
+BoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
+{
+    if (operand->isUnbox())
+        return operand->toUnbox()->input();
+    return AlwaysBoxAt(alloc, at, operand);
+}
+
 bool
-BoxInputsPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
+BoxInputsPolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == MIRType_Value)
             continue;
-        ins->replaceOperand(i, boxAt(alloc, ins, in));
+        ins->replaceOperand(i, BoxAt(alloc, ins, in));
     }
     return true;
 }
 
 bool
 ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MIRType specialization = ins->typePolicySpecialization();
     if (specialization == MIRType_None)
-        return BoxInputsPolicy::adjustInputs(alloc, ins);
+        return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
 
     MOZ_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32);
 
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == ins->type())
             continue;
 
@@ -109,17 +109,17 @@ ComparePolicy::adjustInputs(TempAllocato
             def->replaceOperand(i, replace);
         }
     }
 
     // Box inputs to get value
     if (compare->compareType() == MCompare::Compare_Unknown ||
         compare->compareType() == MCompare::Compare_Value)
     {
-        return BoxInputsPolicy::adjustInputs(alloc, def);
+        return BoxInputsPolicy::staticAdjustInputs(alloc, def);
     }
 
     // Compare_Boolean specialization is done for "Anything === Bool"
     // If the LHS is boolean, we set the specialization to Compare_Int32.
     // This matches other comparisons of the form bool === bool and
     // generated code of Compare_Int32 is more efficient.
     if (compare->compareType() == MCompare::Compare_Boolean &&
         def->getOperand(0)->type() == MIRType_Boolean)
@@ -250,24 +250,24 @@ TypeBarrierPolicy::adjustInputs(TempAllo
     if (inputType == outputType)
         return true;
 
     // Output is a value, currently box the input.
     if (outputType == MIRType_Value) {
         // XXX: Possible optimization: decrease resultTypeSet to only include
         // the inputType. This will remove the need for boxing.
         MOZ_ASSERT(inputType != MIRType_Value);
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
         return true;
     }
 
     // Box input if needed.
     if (inputType != MIRType_Value) {
         MOZ_ASSERT(ins->alwaysBails());
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
     }
 
     // We can't unbox a value to null/undefined/lazyargs. So keep output
     // also a value.
     // Note: Using setResultType shouldn't be done in TypePolicies,
     //       Here it is fine, since the type barrier has no uses.
     if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
         MOZ_ASSERT(!ins->hasDefUses());
@@ -314,28 +314,28 @@ TestPolicy::adjustInputs(TempAllocator &
       {
         MStringLength *length = MStringLength::New(alloc, op);
         ins->block()->insertBefore(ins, length);
         ins->replaceOperand(0, length);
         break;
       }
 
       default:
-        ins->replaceOperand(0, boxAt(alloc, ins, op));
+        ins->replaceOperand(0, BoxAt(alloc, ins, op));
         break;
     }
     return true;
 }
 
 bool
 BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MIRType specialization = ins->typePolicySpecialization();
     if (specialization == MIRType_None)
-        return BoxInputsPolicy::adjustInputs(alloc, ins);
+        return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
 
     MOZ_ASSERT(ins->type() == specialization);
     MOZ_ASSERT(specialization == MIRType_Int32 || specialization == MIRType_Double);
 
     // This policy works for both unary and binary bitwise operations.
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == MIRType_Int32)
@@ -523,17 +523,17 @@ template bool NoFloatPolicyAfter<2>::adj
 template <unsigned Op>
 bool
 BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MDefinition *in = ins->getOperand(Op);
     if (in->type() == MIRType_Value)
         return true;
 
-    ins->replaceOperand(Op, boxAt(alloc, ins, in));
+    ins->replaceOperand(Op, BoxAt(alloc, ins, in));
     return true;
 }
 
 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 
 template <unsigned Op, MIRType Type>
@@ -589,17 +589,17 @@ ToDoublePolicy::staticAdjustInputs(TempA
       case MIRType_String:
       case MIRType_Symbol:
         // Objects might be effectful. Symbols give TypeError.
         break;
       default:
         break;
     }
 
-    in = boxAt(alloc, ins, in);
+    in = BoxAt(alloc, ins, in);
     ins->replaceOperand(0, in);
     return true;
 }
 
 bool
 ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MOZ_ASSERT(ins->isToInt32() || ins->isTruncateToInt32());
@@ -637,29 +637,29 @@ ToInt32Policy::staticAdjustInputs(TempAl
       case MIRType_String:
       case MIRType_Symbol:
         // Objects might be effectful. Symbols give TypeError.
         break;
       default:
         break;
     }
 
-    in = boxAt(alloc, ins, in);
+    in = BoxAt(alloc, ins, in);
     ins->replaceOperand(0, in);
     return true;
 }
 
 bool
 ToStringPolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MOZ_ASSERT(ins->isToString());
 
     MIRType type = ins->getOperand(0)->type();
     if (type == MIRType_Object || type == MIRType_Symbol) {
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
         return true;
     }
 
     // TODO remove the following line once 966957 has landed
     EnsureOperandNotFloat32(alloc, ins, 0);
 
     return true;
 }
@@ -707,24 +707,24 @@ CallPolicy::adjustInputs(TempAllocator &
 
     return true;
 }
 
 bool
 CallSetElementPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     // The first operand should be an object.
-    SingleObjectPolicy::adjustInputs(alloc, ins);
+    SingleObjectPolicy::staticAdjustInputs(alloc, ins);
 
     // Box the index and value operands.
     for (size_t i = 1, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == MIRType_Value)
             continue;
-        ins->replaceOperand(i, boxAt(alloc, ins, in));
+        ins->replaceOperand(i, BoxAt(alloc, ins, in));
     }
     return true;
 }
 
 bool
 InstanceOfPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
 {
     // Box first operand if it isn't object
@@ -756,17 +756,17 @@ StoreTypedArrayPolicy::adjustValueInput(
       case MIRType_Undefined:
         value->setImplicitlyUsedUnchecked();
         value = MConstant::New(alloc, DoubleNaNValue());
         ins->block()->insertBefore(ins, value->toInstruction());
         break;
       case MIRType_Object:
       case MIRType_String:
       case MIRType_Symbol:
-        value = boxAt(alloc, ins, value);
+        value = BoxAt(alloc, ins, value);
         break;
       default:
         MOZ_CRASH("Unexpected type");
     }
 
     if (value != curValue) {
         ins->replaceOperand(valueOperand, value);
         curValue = value;
@@ -831,26 +831,26 @@ StoreTypedArrayPolicy::adjustInputs(Temp
 bool
 StoreTypedArrayHolePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MStoreTypedArrayElementHole *store = ins->toStoreTypedArrayElementHole();
     MOZ_ASSERT(store->elements()->type() == MIRType_Elements);
     MOZ_ASSERT(store->index()->type() == MIRType_Int32);
     MOZ_ASSERT(store->length()->type() == MIRType_Int32);
 
-    return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3);
+    return StoreTypedArrayPolicy::adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3);
 }
 
 bool
 StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MStoreTypedArrayElementStatic *store = ins->toStoreTypedArrayElementStatic();
 
     return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) &&
-        adjustValueInput(alloc, ins, store->viewType(), store->value(), 1);
+        StoreTypedArrayPolicy::adjustValueInput(alloc, ins, store->viewType(), store->value(), 1);
 }
 
 bool
 StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     SingleObjectPolicy::staticAdjustInputs(alloc, ins);
 
     // Change the value input to a ToObjectOrNull instruction if it might be
@@ -889,17 +889,17 @@ ClampPolicy::adjustInputs(TempAllocator 
     MDefinition *in = ins->toClampToUint8()->input();
 
     switch (in->type()) {
       case MIRType_Int32:
       case MIRType_Double:
       case MIRType_Value:
         break;
       default:
-          ins->replaceOperand(0, boxAt(alloc, ins, in));
+          ins->replaceOperand(0, BoxAt(alloc, ins, in));
         break;
     }
 
     return true;
 }
 
 bool
 FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
@@ -910,29 +910,29 @@ FilterTypeSetPolicy::adjustInputs(TempAl
 
     // Input and output type are already in accordance.
     if (inputType == outputType)
         return true;
 
     // Output is a value, box the input.
     if (outputType == MIRType_Value) {
         MOZ_ASSERT(inputType != MIRType_Value);
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
         return true;
     }
 
     // The outputType should be a subset of the inputType else we are in code
     // that has never executed yet. Bail to see the new type (if that hasn't
     // happened yet).
     if (inputType != MIRType_Value) {
         MBail *bail = MBail::New(alloc);
         ins->block()->insertBefore(ins, bail);
         bail->setDependency(ins->dependency());
         ins->setDependency(bail);
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
     }
 
     // We can't unbox a value to null/undefined/lazyargs. So keep output
     // also a value.
     // Note: Using setResultType shouldn't be done in TypePolicies,
     //       Here it is fine, since the type barrier has no uses.
     if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
         MOZ_ASSERT(!ins->hasDefUses());
@@ -988,18 +988,20 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(IntPolicy<0>)                                                     \
     _(IntPolicy<1>)                                                     \
     _(Mix3Policy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType_String>, BoxPolicy<2> >) \
     _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >)      \
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >)      \
+    _(Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>)          \
     _(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >)   \
     _(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >)   \
+    _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \
     _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >)                        \
     _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >)   \
     _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >)            \
     _(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >)                     \
     _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >)            \
     _(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >)                    \
@@ -1041,49 +1043,48 @@ namespace jit {
     TEMPLATE_TYPE_POLICY_LIST(template<> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
 
 }
 }
 
 namespace {
 
-// Default function visited by the C++ lookup rules, if the MIR Instruction does
-// not inherit from a TypePolicy::Data type.
-static TypePolicy *
-thisTypePolicy() {
-    return nullptr;
-}
+// For extra-good measure in case an unqualified use is ever introduced.  (The
+// main use in the macro below is explicitly qualified so as not to consult
+// this scope and find this function.)
+inline TypePolicy *
+thisTypePolicy() MOZ_DELETE;
 
 static MIRType
-thisTypeSpecialization() {
+thisTypeSpecialization()
+{
     MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
 }
 
 }
 
 TypePolicy *
 MGetElementCache::thisTypePolicy()
 {
     if (type() == MIRType_Value)
         return PolicyV.thisTypePolicy();
     return PolicyT.thisTypePolicy();
 }
 
 // For each MIR Instruction, this macro define the |typePolicy| method which is
-// using the |thisTypePolicy| function.  We use the C++ lookup rules to select
-// the right |thisTypePolicy| member.  The |thisTypePolicy| function can either
-// be a member of the MIR Instruction, such as done for MGetElementCache, or a
-// member inherited from the TypePolicy::Data structure, or at last the global
-// with the same name if the instruction has no TypePolicy.
+// using the |thisTypePolicy| method.  The |thisTypePolicy| method is either a
+// member of the MIR Instruction, such as with MGetElementCache, a member
+// inherited from the TypePolicy::Data structure, or a member inherited from
+// NoTypePolicy if the MIR instruction has no type policy.
 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op)      \
     TypePolicy *                                \
     js::jit::M##op::typePolicy()                \
     {                                           \
-        return thisTypePolicy();                \
+        return M##op::thisTypePolicy();         \
     }                                           \
                                                 \
     MIRType                                     \
     js::jit::M##op::typePolicySpecialization()  \
     {                                           \
         return thisTypeSpecialization();        \
     }
 
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -11,16 +11,19 @@
 #include "jit/JitAllocPolicy.h"
 
 namespace js {
 namespace jit {
 
 class MInstruction;
 class MDefinition;
 
+extern MDefinition *
+AlwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
+
 // A type policy directs the type analysis phases, which insert conversion,
 // boxing, unboxing, and type changes as necessary.
 class TypePolicy
 {
   public:
     // Analyze the inputs of the instruction and perform one of the following
     // actions for each input:
     //  * Nothing; the input already type-checks.
@@ -57,154 +60,164 @@ struct TypeSpecializationData
 #define INHERIT_DATA_(DATA_TYPE)                        \
     struct Data : public DATA_TYPE                      \
     {                                                   \
         static TypePolicy *thisTypePolicy();            \
     }
 
 #define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
 
-class BoxInputsPolicy : public TypePolicy
+class NoTypePolicy
 {
-  protected:
-    static MDefinition *boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
-
   public:
-    EMPTY_DATA_;
-    static MDefinition *alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
-    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    struct Data
+    {
+        static TypePolicy *thisTypePolicy() {
+            return nullptr;
+        }