Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 05 Jun 2014 15:14:29 +0200
changeset 194312 413ea58159cf6b333798351ba1824122d98eb5cc
parent 194311 65b0d08a49ac78eb5e729a69a4e8812231ab5593 (current diff)
parent 194157 219b3ed1b9968ea9d6eea0bfc21dc73107821b1a (diff)
child 194313 275b8b4d30ec268c77a0dbe35710673fb34a53ee
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-esr52@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.0a1
Merge mozilla-central to fx-team
content/base/test/csp/file_CSP_bug916446.html
content/base/test/csp/file_CSP_bug916446.html^headers^
content/base/test/csp/file_CSP_evalscript_main.html
content/base/test/csp/file_CSP_evalscript_main.html^headers^
content/base/test/csp/file_CSP_evalscript_main_spec_compliant.html
content/base/test/csp/file_CSP_evalscript_main_spec_compliant.html^headers^
content/base/test/csp/file_CSP_evalscript_main_spec_compliant_allowed.html
content/base/test/csp/file_CSP_evalscript_main_spec_compliant_allowed.html^headers^
content/base/test/csp/file_CSP_evalscript_main_spec_compliant_allowed_getCRMFRequest.html
content/base/test/csp/file_CSP_evalscript_main_spec_compliant_allowed_getCRMFRequest.html^headers^
content/base/test/csp/file_CSP_evalscript_main_spec_compliant_getCRMFRequest.html
content/base/test/csp/file_CSP_evalscript_main_spec_compliant_getCRMFRequest.html^headers^
content/base/test/csp/file_CSP_frameancestors.sjs
content/base/test/csp/file_CSP_frameancestors_main.html
content/base/test/csp/file_CSP_frameancestors_main.js
content/base/test/csp/file_CSP_frameancestors_main_spec_compliant.html
content/base/test/csp/file_CSP_frameancestors_main_spec_compliant.js
content/base/test/csp/file_CSP_frameancestors_spec_compliant.sjs
content/base/test/csp/file_CSP_inlinescript_main.html
content/base/test/csp/file_CSP_inlinescript_main.html^headers^
content/base/test/csp/file_CSP_inlinescript_main_spec_compliant.html
content/base/test/csp/file_CSP_inlinescript_main_spec_compliant.html^headers^
content/base/test/csp/file_CSP_inlinescript_main_spec_compliant_allowed.html
content/base/test/csp/file_CSP_inlinescript_main_spec_compliant_allowed.html^headers^
content/base/test/csp/file_CSP_inlinestyle_main.html
content/base/test/csp/file_CSP_inlinestyle_main.html^headers^
content/base/test/csp/file_CSP_inlinestyle_main_spec_compliant.html
content/base/test/csp/file_CSP_inlinestyle_main_spec_compliant.html^headers^
content/base/test/csp/file_CSP_inlinestyle_main_spec_compliant_allowed.html
content/base/test/csp/file_CSP_inlinestyle_main_spec_compliant_allowed.html^headers^
content/base/test/csp/file_CSP_main.html
content/base/test/csp/file_CSP_main.html^headers^
content/base/test/csp/file_CSP_main.js
content/base/test/csp/file_CSP_main_spec_compliant.html
content/base/test/csp/file_CSP_main_spec_compliant.html^headers^
content/base/test/csp/file_CSP_main_spec_compliant.js
content/base/test/csp/file_bothCSPheaders.html
content/base/test/csp/file_bothCSPheaders.html^headers^
content/base/test/csp/file_dual_headers_warning.html
content/base/test/csp/file_dual_headers_warning.html^headers^
content/base/test/csp/file_policyuri_async_fetch.html
content/base/test/csp/file_policyuri_async_fetch.html^headers^
content/base/test/csp/test_CSP_bug916446.html
content/base/test/csp/test_bothCSPheaders.html
content/base/test/csp/test_dual_headers_warning.html
content/base/test/csp/test_policyuri_async_fetch.html
dom/mobilemessage/tests/header_helpers.js
dom/mobilemessage/tests/mochitest.ini
dom/mobilemessage/tests/test_mms_pdu_helper.js
dom/mobilemessage/tests/test_mms_service.js
dom/mobilemessage/tests/test_sms_basics.html
dom/mobilemessage/tests/test_smsfilter.html
dom/mobilemessage/tests/test_smsservice_createsmsmessage.js
dom/mobilemessage/tests/test_wsp_pdu_helper.js
dom/mobilemessage/tests/xpcshell.ini
js/src/vm/PropDesc.h
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,10 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1014976 - Windows debug bustage from linking changes.
-
+Preemptive clobber for a vm/Xdr.h change to evade bug 1019955 (should it have otherwise arisen, which is unclear).
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8e4420c0c5c8e8c8e58a000278a7129403769f96"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9100fa82fc355f5201e23e400fc6b40e875304ed"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="6e2a3b589d1e8cc1d9df25f5e630ce30a0aa39f3">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="276ce45e78b09c4a4ee643646f691d22804754c1">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <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="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="8e4420c0c5c8e8c8e58a000278a7129403769f96"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9100fa82fc355f5201e23e400fc6b40e875304ed"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="6e2a3b589d1e8cc1d9df25f5e630ce30a0aa39f3">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "7f0af1e164a39efb732c0c341c2a8e51f681d913", 
+    "revision": "c3d40600c0090c5ca6ca4427f3a870ff443a109d", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <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="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- 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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <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="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <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,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="6e2a3b589d1e8cc1d9df25f5e630ce30a0aa39f3">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="d2cfef555dabab415085e548ed44c48a99be5c32"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="908f94fda04462001ece86e6b6c15ad8b05f7526"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="531cf670e485649c69746e46d567929fcd54cbc5"/>
   <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="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="994fa9a1f7ce0e63c880a48d571c3ab3e01884a3"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2880,42 +2880,65 @@
       <property name="textZoom"
                 onget="return this.mCurrentBrowser.textZoom;"
                 onset="this.mCurrentBrowser.textZoom = val;"/>
 
       <property name="isSyntheticDocument"
                 onget="return this.mCurrentBrowser.isSyntheticDocument;"
                 readonly="true"/>
 
-      <method name="_handleKeyEvent">
+      <method name="_handleKeyDownEvent">
         <parameter name="aEvent"/>
         <body><![CDATA[
           if (!aEvent.isTrusted) {
             // Don't let untrusted events mess with tabs.
             return;
           }
 
           if (aEvent.altKey)
             return;
 
+          // Don't check if the event was already consumed because tab
+          // navigation should always work for better user experience.
+
           if (aEvent.ctrlKey && aEvent.shiftKey && !aEvent.metaKey) {
             switch (aEvent.keyCode) {
               case aEvent.DOM_VK_PAGE_UP:
                 this.moveTabBackward();
-                aEvent.stopPropagation();
                 aEvent.preventDefault();
                 return;
               case aEvent.DOM_VK_PAGE_DOWN:
                 this.moveTabForward();
-                aEvent.stopPropagation();
                 aEvent.preventDefault();
                 return;
             }
           }
 
+#ifndef XP_MACOSX
+          if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
+              aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
+              !this.mCurrentTab.pinned) {
+            this.removeCurrentTab({animate: true});
+            aEvent.preventDefault();
+          }
+#endif
+        ]]></body>
+      </method>
+
+      <method name="_handleKeyPressEvent">
+        <parameter name="aEvent"/>
+        <body><![CDATA[
+          if (!aEvent.isTrusted) {
+            // Don't let untrusted events mess with tabs.
+            return;
+          }
+
+          if (aEvent.altKey)
+            return;
+
           // We need to take care of FAYT-watching as long as the findbar
           // isn't initialized.  The checks on aEvent are copied from
           // _shouldFastFind (see findbar.xml).
           if (!gFindBarInitialized &&
               !(aEvent.ctrlKey || aEvent.metaKey) &&
               !aEvent.defaultPrevented) {
             let charCode = aEvent.charCode;
             if (charCode) {
@@ -2935,27 +2958,18 @@
           var offset = 1;
           switch (aEvent.charCode) {
             case '}'.charCodeAt(0):
               offset = -1;
             case '{'.charCodeAt(0):
               if (window.getComputedStyle(this, null).direction == "ltr")
                 offset *= -1;
               this.tabContainer.advanceSelectedTab(offset, true);
-              aEvent.stopPropagation();
               aEvent.preventDefault();
           }
-#else
-          if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
-              aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
-              !this.mCurrentTab.pinned) {
-            this.removeCurrentTab({animate: true});
-            aEvent.stopPropagation();
-            aEvent.preventDefault();
-          }
 #endif
         ]]></body>
       </method>
 
       <property name="userTypedClear"
                 onget="return this.mCurrentBrowser.userTypedClear;"
                 onset="return this.mCurrentBrowser.userTypedClear = val;"/>
 
@@ -2977,18 +2991,21 @@
                                              tab.getAttribute("label"));
         ]]></body>
       </method>
 
       <method name="handleEvent">
         <parameter name="aEvent"/>
         <body><![CDATA[
           switch (aEvent.type) {
+            case "keydown":
+              this._handleKeyDownEvent(aEvent);
+              break;
             case "keypress":
-              this._handleKeyEvent(aEvent);
+              this._handleKeyPressEvent(aEvent);
               break;
             case "sizemodechange":
               if (aEvent.target == window) {
                 this.mCurrentBrowser.docShellIsActive =
                   (window.windowState != window.STATE_MINIMIZED);
               }
               break;
           }
@@ -3045,17 +3062,19 @@
       </method>
 
       <constructor>
         <![CDATA[
           let browserStack = document.getAnonymousElementByAttribute(this, "anonid", "browserStack");
           this.mCurrentBrowser = document.getAnonymousElementByAttribute(this, "anonid", "initialBrowser");
 
           this.mCurrentTab = this.tabContainer.firstChild;
-          document.addEventListener("keypress", this, false);
+          let els = Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService);
+          els.addSystemEventListener(document, "keydown", this, false);
+          els.addSystemEventListener(document, "keypress", this, false);
           window.addEventListener("sizemodechange", this, false);
 
           var uniqueId = this._generateUniquePanelID();
           this.mPanelContainer.childNodes[0].id = uniqueId;
           this.mCurrentTab.linkedPanel = uniqueId;
           this.mCurrentTab._tPos = 0;
           this.mCurrentTab._fullyOpen = true;
           this.mCurrentTab.linkedBrowser = this.mCurrentBrowser;
@@ -3123,17 +3142,19 @@
               delete browser.registeredOpenURI;
             }
             browser.webProgress.removeProgressListener(this.mTabFilters[i]);
             this.mTabFilters[i].removeProgressListener(this.mTabListeners[i]);
             this.mTabFilters[i] = null;
             this.mTabListeners[i].destroy();
             this.mTabListeners[i] = null;
           }
-          document.removeEventListener("keypress", this, false);
+          let els = Cc["@mozilla.org/eventlistenerservice;1"].getService(Ci.nsIEventListenerService);
+          els.removeSystemEventListener(document, "keydown", this, false);
+          els.removeSystemEventListener(document, "keypress", this, false);
           window.removeEventListener("sizemodechange", this, false);
 
           if (gMultiProcessBrowser) {
             messageManager.removeMessageListener("DOMTitleChanged", this);
             messageManager.removeMessageListener("contextmenu", this);
           }
         ]]>
       </destructor>
@@ -4242,25 +4263,28 @@
           BrowserOpenTab();
         } else {
           return;
         }
 
         event.stopPropagation();
       ]]></handler>
 
-      <handler event="keypress"><![CDATA[
+      <handler event="keydown" group="system"><![CDATA[
         if (event.altKey || event.shiftKey ||
 #ifdef XP_MACOSX
             !event.metaKey)
 #else
             !event.ctrlKey || event.metaKey)
 #endif
           return;
 
+        // Don't check if the event was already consumed because tab navigation
+        // should work always for better user experience.
+
         switch (event.keyCode) {
           case KeyEvent.DOM_VK_UP:
             this.tabbrowser.moveTabBackward();
             break;
           case KeyEvent.DOM_VK_DOWN:
             this.tabbrowser.moveTabForward();
             break;
           case KeyEvent.DOM_VK_RIGHT:
@@ -4269,21 +4293,20 @@
             break;
           case KeyEvent.DOM_VK_HOME:
             this.tabbrowser.moveTabToStart();
             break;
           case KeyEvent.DOM_VK_END:
             this.tabbrowser.moveTabToEnd();
             break;
           default:
-            // Stop the keypress event for the above keyboard
+            // Consume the keydown event for the above keyboard
             // shortcuts only.
             return;
         }
-        event.stopPropagation();
         event.preventDefault();
       ]]></handler>
 
       <handler event="dragstart"><![CDATA[
         var tab = this._getDragTargetTab(event);
         if (!tab || this._isCustomizing)
           return;
 
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -375,16 +375,17 @@ skip-if = e10s # Bug 918634 - swapFrameL
 [browser_tab_dragdrop.js]
 skip-if = e10s # Bug 918634 - swapFrameLoaders not implemented for e10s (test uses gBrowser.swapBrowsersAndCloseOther)
 [browser_tab_dragdrop2.js]
 [browser_tabbar_big_widgets.js]
 skip-if = os == "linux" || os == "mac" # No tabs in titlebar on linux
                                        # Disabled on OS X because of bug 967917
 [browser_tabfocus.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s (test calls getFocusedElementForWindow with a content window)
+[browser_tabkeynavigation.js]
 [browser_tabopen_reflows.js]
 skip-if = e10s # Bug ?????? - test needs to be updated for e10s (captures a stack that isn't correct in e10s)
 [browser_tabs_isActive.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (tries to get/set attributes directly on content docshell)
 [browser_tabs_owner.js]
 [browser_typeAheadFind.js]
 skip-if = e10s # Bug 921935 - focusmanager issues with e10s (test calls waitForFocus)
 [browser_unloaddialogs.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_tabkeynavigation.js
@@ -0,0 +1,214 @@
+/*
+ * This test checks that keyboard navigation for tabs isn't blocked by content
+ */
+
+function test() {
+  waitForExplicitFinish();
+
+  let testPage1 = "data:text/html,<html id='tab1'><body><button id='button1'>Tab 1</button></body></html>";
+  let testPage2 = "data:text/html,<html id='tab2'><body><button id='button2'>Tab 2</button><script>function preventDefault(event) { event.preventDefault(); event.stopImmediatePropagation(); } window.addEventListener('keydown', preventDefault, true); window.addEventListener('keypress', preventDefault, true);</script></body></html>";
+  let testPage3 = "data:text/html,<html id='tab3'><body><button id='button3'>Tab 3</button></body></html>";
+
+  let tab1 = gBrowser.addTab();
+  let browser1 = gBrowser.getBrowserForTab(tab1);
+
+  let tab2 = gBrowser.addTab();
+  let browser2 = gBrowser.getBrowserForTab(tab2);
+
+  let tab3 = gBrowser.addTab();
+  let browser3 = gBrowser.getBrowserForTab(tab3);
+
+  let loadCount = 0;
+  function check()
+  {
+    // wait for all tabs to load
+    if (++loadCount != 3) {
+      return;
+    }
+
+    browser1.removeEventListener("load", check, true);
+    browser2.removeEventListener("load", check, true);
+    browser3.removeEventListener("load", check, true);
+    executeSoon(_run_tab_keyboard_navigation_tests);
+  }
+
+  function _run_tab_keyboard_navigation_tests()
+  {
+    // Kill the animation for simpler test.
+    Services.prefs.setBoolPref("browser.tabs.animate", false);
+
+    gBrowser.selectedTab = tab1;
+    browser1.contentWindow.focus();
+
+    is(gBrowser.selectedTab, tab1,
+       "Tab1 should be activated");
+    EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true },
+                             browser1.contentWindow);
+    is(gBrowser.selectedTab, tab2,
+       "Tab2 should be activated by pressing Ctrl+Tab on Tab1");
+
+    EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true },
+                             browser2.contentWindow);
+    is(gBrowser.selectedTab, tab3,
+       "Tab3 should be activated by pressing Ctrl+Tab on Tab2");
+
+    EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true },
+                             browser3.contentWindow);
+    is(gBrowser.selectedTab, tab2,
+       "Tab2 should be activated by pressing Ctrl+Shift+Tab on Tab3");
+
+    EventUtils.synthesizeKey("VK_TAB", { ctrlKey: true, shiftKey: true },
+                             browser2.contentWindow);
+    is(gBrowser.selectedTab, tab1,
+       "Tab1 should be activated by pressing Ctrl+Shift+Tab on Tab2");
+
+    gBrowser.selectedTab = tab1;
+    browser1.contentWindow.focus();
+
+    is(gBrowser.selectedTab, tab1,
+       "Tab1 should be activated");
+    EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true },
+                             browser1.contentWindow);
+    is(gBrowser.selectedTab, tab2,
+       "Tab2 should be activated by pressing Ctrl+PageDown on Tab1");
+
+    EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true },
+                             browser2.contentWindow);
+    is(gBrowser.selectedTab, tab3,
+       "Tab3 should be activated by pressing Ctrl+PageDown on Tab2");
+
+    EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true },
+                             browser3.contentWindow);
+    is(gBrowser.selectedTab, tab2,
+       "Tab2 should be activated by pressing Ctrl+PageUp on Tab3");
+
+    EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true },
+                             browser2.contentWindow);
+    is(gBrowser.selectedTab, tab1,
+       "Tab1 should be activated by pressing Ctrl+PageUp on Tab2");
+
+    if (gBrowser.mTabBox._handleMetaAltArrows) {
+      gBrowser.selectedTab = tab1;
+      browser1.contentWindow.focus();
+
+      let ltr =
+        window.getComputedStyle(gBrowser.mTabBox, "").direction == "ltr";
+      let advanceKey = ltr ? "VK_RIGHT" : "VK_LEFT";
+      let reverseKey = ltr ? "VK_LEFT" : "VK_RIGHT";
+
+      is(gBrowser.selectedTab, tab1,
+         "Tab1 should be activated");
+      EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true },
+                               browser1.contentWindow);
+      is(gBrowser.selectedTab, tab2,
+         "Tab2 should be activated by pressing Ctrl+" + advanceKey + " on Tab1");
+
+      EventUtils.synthesizeKey(advanceKey, { altKey: true, metaKey: true },
+                               browser2.contentWindow);
+      is(gBrowser.selectedTab, tab3,
+         "Tab3 should be activated by pressing Ctrl+" + advanceKey + " on Tab2");
+
+      EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true },
+                               browser3.contentWindow);
+      is(gBrowser.selectedTab, tab2,
+         "Tab2 should be activated by pressing Ctrl+" + reverseKey + " on Tab3");
+
+      EventUtils.synthesizeKey(reverseKey, { altKey: true, metaKey: true },
+                               browser2.contentWindow);
+      is(gBrowser.selectedTab, tab1,
+         "Tab1 should be activated by pressing Ctrl+" + reverseKey + " on Tab2");
+    }
+
+    gBrowser.selectedTab = tab2;
+    is(gBrowser.selectedTab, tab2,
+       "Tab2 should be activated");
+    is(gBrowser.tabContainer.selectedIndex, 2,
+       "Tab2 index should be 2");
+
+    EventUtils.synthesizeKey("VK_PAGE_DOWN", { ctrlKey: true, shiftKey: true },
+                             browser2.contentWindow);
+    is(gBrowser.selectedTab, tab2,
+       "Tab2 should be activated after Ctrl+Shift+PageDown");
+    is(gBrowser.tabContainer.selectedIndex, 3,
+       "Tab2 index should be 1 after Ctrl+Shift+PageDown");
+
+    EventUtils.synthesizeKey("VK_PAGE_UP", { ctrlKey: true, shiftKey: true },
+                             browser2.contentWindow);
+    is(gBrowser.selectedTab, tab2,
+       "Tab2 should be activated after Ctrl+Shift+PageUp");
+    is(gBrowser.tabContainer.selectedIndex, 2,
+       "Tab2 index should be 2 after Ctrl+Shift+PageUp");
+
+    if (navigator.platform.indexOf("Mac") == 0) {
+      gBrowser.selectedTab = tab1;
+      browser1.contentWindow.focus();
+
+      // XXX Currently, Command + "{" and "}" don't work if keydown event is
+      //     consumed because following keypress event isn't fired.
+
+      let ltr =
+        window.getComputedStyle(gBrowser.mTabBox, "").direction == "ltr";
+      let advanceKey = ltr ? "}" : "{";
+      let reverseKey = ltr ? "{" : "}";
+
+      is(gBrowser.selectedTab, tab1,
+         "Tab1 should be activated");
+      EventUtils.synthesizeKey(advanceKey, { metaKey: true },
+                               browser1.contentWindow);
+      is(gBrowser.selectedTab, tab2,
+         "Tab2 should be activated by pressing Ctrl+" + advanceKey + " on Tab1");
+
+      EventUtils.synthesizeKey(advanceKey, { metaKey: true },
+                               browser2.contentWindow);
+      todo_is(gBrowser.selectedTab, tab3,
+              "Tab3 should be activated by pressing Ctrl+" + advanceKey + " on Tab2");
+
+      if (gBrowser.selectedTab != tab3) {
+        EventUtils.synthesizeKey(reverseKey, { metaKey: true },
+                                 browser3.contentWindow);
+        is(gBrowser.selectedTab, tab2,
+           "Tab2 should be activated by pressing Ctrl+" + reverseKey + " on Tab3");
+      }
+
+      EventUtils.synthesizeKey(reverseKey, { metaKey: true },
+                               browser2.contentWindow);
+      todo_is(gBrowser.selectedTab, tab1,
+              "Tab1 should be activated by pressing Ctrl+" + reverseKey + " on Tab2");
+    } else {
+      gBrowser.selectedTab = tab2;
+      EventUtils.synthesizeKey("VK_F4", { type: "keydown", ctrlKey: true },
+                               browser2.contentWindow);
+
+      isnot(gBrowser.selectedTab, tab2,
+            "Tab2 should be closed by pressing Ctrl+F4 on Tab2");
+      is(gBrowser.tabs.length, 3,
+         "The count of tabs should be 3 since tab2 should be closed");
+
+      let activeWindow =
+        gBrowser.getBrowserForTab(gBrowser.selectedTab).contentWindow;
+      // NOTE: keypress event shouldn't be fired since the keydown event should
+      //       be consumed by tab2.
+      EventUtils.synthesizeKey("VK_F4", { type: "keyup", ctrlKey: true },
+                               activeWindow);
+      is(gBrowser.tabs.length, 3,
+         "The count of tabs should be 3 since renaming key events shouldn't close other tabs");
+    }
+
+    gBrowser.selectedTab = tab3;
+    while (gBrowser.tabs.length > 1) {
+      gBrowser.removeCurrentTab();
+    }
+
+    Services.prefs.clearUserPref("browser.tabs.animate");
+
+    finish();
+  }
+
+  browser1.addEventListener("load", check, true);
+  browser2.addEventListener("load", check, true);
+  browser3.addEventListener("load", check, true);
+
+  browser1.contentWindow.location = testPage1;
+  browser2.contentWindow.location = testPage2;
+  browser3.contentWindow.location = testPage3;
+}
--- a/configure.in
+++ b/configure.in
@@ -9027,25 +9027,27 @@ HAVE_SYS_MOUNT_H
 "
 
 AC_SUBST(STLPORT_LIBS)
 
 dnl ========================================================
 dnl ICU Support
 dnl ========================================================
 
-if test "$MOZ_BUILD_APP" = "browser"; then
-    _INTL_API=yes
+# Internationalization isn't built or exposed by default in non-desktop
+# builds.  Bugs to enable:
+#
+#   Android:  bug 864843
+#   B2G:      bug 866301
+
+if test "$MOZ_WIDGET_TOOLKIT" = "android" ||
+   test "$MOZ_BUILD_APP" = "b2g"; then
+    _INTL_API=no
 else
-    # Internationalization isn't built or exposed by default in non-desktop
-    # builds.  Bugs to enable:
-    #
-    #   Android:  bug 864843
-    #   B2G:      bug 866301
-    _INTL_API=no
+    _INTL_API=yes
 fi
 
 MOZ_CONFIG_ICU()
 
 if test -n "$MOZ_NATIVE_ICU"; then
     MOZ_JS_STATIC_LIBS="$MOZ_JS_STATIC_LIBS $MOZ_ICU_LIBS"
 fi
 
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -2592,19 +2592,20 @@ Serialize(FragmentOrElement* aRoot, bool
 
       if ((next = current->GetNextSibling())) {
         current = next;
         break;
       }
 
       current = current->GetParentNode();
 
-      // Template case, if we are in a template's content, then the parent
-      // should be the host template element.
-      if (current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
+      // Handle template element. If the parent is a template's content,
+      // then adjust the parent to be the template element.
+      if (current != aRoot &&
+          current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
         DocumentFragment* frag = static_cast<DocumentFragment*>(current);
         nsIContent* fragHost = frag->GetHost();
         if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
           current = fragHost;
         }
       }
 
       if (aDescendentsOnly && current == aRoot) {
--- a/content/base/src/nsCSPParser.cpp
+++ b/content/base/src/nsCSPParser.cpp
@@ -226,18 +226,18 @@ nsCSPParser::port()
 
   // Port might be "*"
   if (accept(WILDCARD)) {
     return true;
   }
 
   // Port must start with a number
   if (!accept(isNumberToken)) {
-    const char16_t* params[] = { mCurValue.get() };
-    logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
+    const char16_t* params[] = { mCurToken.get() };
+    logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParsePort",
                              params, ArrayLength(params));
     return false;
   }
   // Consume more numbers and set parsed port to the nsCSPHost
   while (accept(isNumberToken)) { /* consume */ }
   return true;
 }
 
@@ -255,16 +255,24 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspH
 
   while (!atEnd() && !peek(DOT)) {
     ++charCounter;
     while (hostChar() || accept(UNDERLINE)) {
       /* consume */
       ++charCounter;
     }
     if (accept(SLASH)) {
+      // do not accept double slashes
+      // see http://tools.ietf.org/html/rfc3986#section-3.3
+      if (accept(SLASH)) {
+        const char16_t* params[] = { mCurToken.get() };
+        logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
+                                 params, ArrayLength(params));
+        return false;
+      }
       aCspHost->appendPath(mCurValue);
       // Resetting current value since we are appending parts of the path
       // to aCspHost, e.g; "http://www.example.com/path1/path2" then the
       // first part is "/path1", second part "/path2"
       resetCurValue();
     }
     if (charCounter > kSubHostPathCharacterCutoff) {
       return false;
@@ -284,22 +292,28 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost
 
   // Resetting current value and forgetting everything we have parsed so far
   // e.g. parsing "http://www.example.com/path1/path2", then
   // "http://www.example.com" has already been parsed so far
   // forget about it.
   resetCurValue();
 
   if (!accept(SLASH)) {
+    const char16_t* params[] = { mCurToken.get() };
+    logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
+                             params, ArrayLength(params));
     return false;
   }
   if (atEnd()) {
     return true;
   }
   if (!hostChar()) {
+    const char16_t* params[] = { mCurToken.get() };
+    logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
+                             params, ArrayLength(params));
     return false;
   }
   return subPath(aCspHost);
 }
 
 bool
 nsCSPParser::subHost()
 {
@@ -342,44 +356,44 @@ nsCSPParser::host()
   // "https://*", "*.example.com", "*:*", etc.
   if (accept(WILDCARD)) {
     // Might solely be the wildcard
     if (atEnd() || peek(COLON)) {
       return new nsCSPHostSrc(mCurValue);
     }
     // If the token is not only the "*", a "." must follow right after
     if (!accept(DOT)) {
-      const char16_t* params[] = { mCurValue.get() };
-      logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
+      const char16_t* params[] = { mCurToken.get() };
+      logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
                                params, ArrayLength(params));
       return nullptr;
     }
   }
 
   // Expecting at least one Character
   if (!accept(isCharacterToken)) {
-    const char16_t* params[] = { mCurValue.get() };
-    logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
+    const char16_t* params[] = { mCurToken.get() };
+    logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
                              params, ArrayLength(params));
     return nullptr;
   }
 
   // There might be several sub hosts defined.
   if (!subHost()) {
-    const char16_t* params[] = { mCurValue.get() };
-    logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
+    const char16_t* params[] = { mCurToken.get() };
+    logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidHost",
                              params, ArrayLength(params));
     return nullptr;
   }
 
   // HostName might match a keyword, log to the console.
   if (CSP_IsQuotelessKeyword(mCurValue)) {
     nsString keyword = mCurValue;
     ToLowerCase(keyword);
-    const char16_t* params[] = { mCurValue.get(), keyword.get() };
+    const char16_t* params[] = { mCurToken.get(), keyword.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "hostNameMightBeKeyword",
                              params, ArrayLength(params));
   }
 
   // Create a new nsCSPHostSrc with the parsed host.
   return new nsCSPHostSrc(mCurValue);
 }
 
@@ -390,18 +404,18 @@ nsCSPParser::appHost()
   CSPPARSERLOG(("nsCSPParser::appHost, mCurToken: %s, mCurValue: %s",
                NS_ConvertUTF16toUTF8(mCurToken).get(),
                NS_ConvertUTF16toUTF8(mCurValue).get()));
 
   while (hostChar()) { /* consume */ }
 
   // appHosts have to end with "}", otherwise we have to report an error
   if (!accept(CLOSE_CURL)) {
-    const char16_t* params[] = { mCurValue.get() };
-    logWarningErrorToConsole(nsIScriptError::warningFlag, "policyURIParseError",
+    const char16_t* params[] = { mCurToken.get() };
+    logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
                              params, ArrayLength(params));
     return nullptr;
   }
   return new nsCSPHostSrc(mCurValue);
 }
 
 // keyword-source = "'self'" / "'unsafe-inline'" / "'unsafe-eval'"
 nsCSPBaseSrc*
@@ -459,17 +473,21 @@ nsCSPParser::hostSource()
   if (atEnd()) {
     return cspHost;
   }
 
   // Calling path() to see if there is a path to parse, if an error
   // occurs, path() reports the error; handing cspHost as an argument
   // which simplifies parsing of several paths.
   if (!path(cspHost)) {
-    return cspHost;
+    // If the host [port] is followed by a path, it has to be a valid path,
+    // otherwise we pass the nullptr, indicating an error, up the callstack.
+    // see also http://www.w3.org/TR/CSP11/#source-list
+    delete cspHost;
+    return nullptr;
   }
 
   // Calling fileAndArguments to see if there are any files to parse;
   // if an error occurs, fileAndArguments() reports the error; if
   // fileAndArguments returns true, we have a valid file, so we add it.
   if (fileAndArguments()) {
     cspHost->setFileAndArguments(mCurValue);
   }
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4508,16 +4508,21 @@ nsDocument::SetScriptGlobalObject(nsIScr
   }
 
   // Set our visibility state, but do not fire the event.  This is correct
   // because either we're coming out of bfcache (in which case IsVisible() will
   // still test false at this point and no state change will happen) or we're
   // doing the initial document load and don't want to fire the event for this
   // change.
   mVisibilityState = GetVisibilityState();
+
+  // The global in the template contents owner document should be the same.
+  if (mTemplateContentsOwner && mTemplateContentsOwner != this) {
+    mTemplateContentsOwner->SetScriptGlobalObject(aScriptGlobalObject);
+  }
 }
 
 nsIScriptGlobalObject*
 nsDocument::GetScriptHandlingObjectInternal() const
 {
   MOZ_ASSERT(!mScriptGlobalObject,
              "Do not call this when mScriptGlobalObject is set!");
   if (mHasHadDefaultView) {
@@ -9438,17 +9443,16 @@ nsDocument::GetCurrentContentSink()
 
 nsIDocument*
 nsDocument::GetTemplateContentsOwner()
 {
   if (!mTemplateContentsOwner) {
     bool hasHadScriptObject = true;
     nsIScriptGlobalObject* scriptObject =
       GetScriptHandlingObject(hasHadScriptObject);
-    NS_ENSURE_TRUE(scriptObject || !hasHadScriptObject, nullptr);
 
     nsCOMPtr<nsIDOMDocument> domDocument;
     nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument),
                                     EmptyString(), // aNamespaceURI
                                     EmptyString(), // aQualifiedName
                                     nullptr, // aDoctype
                                     nsIDocument::GetDocumentURI(),
                                     nsIDocument::GetDocBaseURI(),
@@ -9456,22 +9460,26 @@ nsDocument::GetTemplateContentsOwner()
                                     true, // aLoadedAsData
                                     scriptObject, // aEventObject
                                     DocumentFlavorHTML);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     mTemplateContentsOwner = do_QueryInterface(domDocument);
     NS_ENSURE_TRUE(mTemplateContentsOwner, nullptr);
 
-    mTemplateContentsOwner->SetScriptHandlingObject(scriptObject);
+    nsDocument* doc = static_cast<nsDocument*>(mTemplateContentsOwner.get());
+    doc->mHasHadScriptHandlingObject = hasHadScriptObject;
+
+    if (!scriptObject) {
+      mTemplateContentsOwner->SetScopeObject(GetScopeObject());
+    }
 
     // Set |doc| as the template contents owner of itself so that
     // |doc| is the template contents owner of template elements created
     // by |doc|.
-    nsDocument* doc = static_cast<nsDocument*>(mTemplateContentsOwner.get());
     doc->mTemplateContentsOwner = doc;
   }
 
   return mTemplateContentsOwner;
 }
 
 void
 nsDocument::RegisterHostObjectUri(const nsACString& aUri)
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -517,30 +517,41 @@ nsDocumentEncoder::SerializeToStringRecu
 }
 
 nsresult
 nsDocumentEncoder::SerializeToStringIterative(nsINode* aNode,
                                               nsAString& aStr)
 {
   nsresult rv;
 
-  nsINode* node = aNode->GetFirstChild();
+  nsINode* node = nsNodeUtils::GetFirstChildOfTemplateOrNode(aNode);
   while (node) {
     nsINode* current = node;
     rv = SerializeNodeStart(current, 0, -1, aStr, current);
     NS_ENSURE_SUCCESS(rv, rv);
-    node = current->GetFirstChild();
+    node = nsNodeUtils::GetFirstChildOfTemplateOrNode(current);
     while (!node && current && current != aNode) {
       rv = SerializeNodeEnd(current, aStr);
       NS_ENSURE_SUCCESS(rv, rv);
       // Check if we have siblings.
       node = current->GetNextSibling();
       if (!node) {
         // Perhaps parent node has siblings.
         current = current->GetParentNode();
+
+        // Handle template element. If the parent is a template's content,
+        // then adjust the parent to be the template element.
+        if (current && current != aNode &&
+            current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
+          DocumentFragment* frag = static_cast<DocumentFragment*>(current);
+          nsIContent* host = frag->GetHost();
+          if (host && host->IsHTML(nsGkAtoms::_template)) {
+            current = host;
+          }
+        }
       }
     }
   }
 
   return NS_OK;
 }
 
 bool 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2520,18 +2520,18 @@ GetRequestBody(nsIVariant* aBody, nsIInp
 
     // ArrayBuffer?
     AutoSafeJSContext cx;
     JS::Rooted<JS::Value> realVal(cx);
 
     nsresult rv = aBody->GetAsJSVal(&realVal);
     if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) {
       JS::Rooted<JSObject*> obj(cx, realVal.toObjectOrNull());
-      if (JS_IsArrayBufferObject(obj)) {
-          ArrayBuffer buf(obj);
+      ArrayBuffer buf;
+      if (buf.Init(obj)) {
           buf.ComputeLengthAndData();
           return GetRequestBody(buf.Data(), buf.Length(), aResult,
                                 aContentLength, aContentType, aCharset);
       }
     }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
            dataType == nsIDataType::VTYPE_EMPTY) {
--- a/content/base/test/TestCSPParser.cpp
+++ b/content/base/test/TestCSPParser.cpp
@@ -402,38 +402,16 @@ nsresult TestSimplePolicies() {
 nsresult TestPoliciesThatLogWarning() {
 
   static const PolicyTest policies[] =
   {
     { "script-src 'self'; SCRIPT-SRC http://www.example.com",
       "script-src http://www.selfuri.com" },
     { "script-src 'none' test.com; script-src example.com",
       "script-src http://test.com" },
-    { "script-src http://www.example.com//",
-      "script-src http://www.example.com" },
-    { "script-src http://www.example.com/path-1//",
-      "script-src http://www.example.com" },
-    { "script-src http://www.example.com/path-1//path_2",
-      "script-src http://www.example.com" },
-    { "script-src http://www.example.com:88path-1/",
-      "script-src http://www.example.com:88" },
-    { "script-src http://www.example.com:88//",
-      "script-src http://www.example.com:88" },
-    { "script-src http://www.example.com:88//path-1",
-      "script-src http://www.example.com:88" },
-    { "script-src http://www.example.com:88//path-1",
-      "script-src http://www.example.com:88" },
-    { "script-src http://www.example.com:88/.js",
-      "script-src http://www.example.com:88" },
-    { "script-src http://www.example.com:88.js",
-      "script-src http://www.example.com:88" },
-    { "script-src http://www.example.com:*.js",
-      "script-src http://www.example.com:*" },
-    { "script-src http://www.example.com:*.",
-      "script-src http://www.example.com:*" }
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 1);
 }
 
 // ============================= TestBadPolicies ========================
 
@@ -456,17 +434,28 @@ nsresult TestBadPolicies() {
     { "default-src 'unsafe-inlin' ", "" },
     { "default-src :88", "" },
     { "script-src abc::::::88", "" },
     { "asdf http://test.com", ""},
     { "script-src *.*:*", "" },
     { "img-src *::88", "" },
     { "object-src http://localhost:", "" },
     { "script-src test..com", "" },
-    { "script-src sub1.sub2.example+", "" }
+    { "script-src sub1.sub2.example+", "" },
+    { "script-src http://www.example.com//", "" },
+    { "script-src http://www.example.com/path-1//", "" },
+    { "script-src http://www.example.com/path-1//path_2", "" },
+    { "script-src http://www.example.com:88path-1/", "" },
+    { "script-src http://www.example.com:88//", "" },
+    { "script-src http://www.example.com:88//path-1", "" },
+    { "script-src http://www.example.com:88//path-1", "" },
+    { "script-src http://www.example.com:88/.js", "" },
+    { "script-src http://www.example.com:88.js", "" },
+    { "script-src http://www.example.com:*.js", "" },
+    { "script-src http://www.example.com:*.", "" },
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 0);
 }
 
 // ============================= TestGoodGeneratedPolicies ========================
 
--- a/content/base/test/unit/xpcshell.ini
+++ b/content/base/test/unit/xpcshell.ini
@@ -22,12 +22,14 @@ support-files =
 
 [test_bug553888.js]
 [test_bug558431.js]
 [test_bug737966.js]
 [test_csputils.js]
 [test_cspreports.js]
 [test_error_codes.js]
 run-sequentially = Hardcoded 4444 port.
+# Bug 1018414: hardcoded localhost doesn't work properly on some OS X installs
+skip-if = os == 'mac'
 [test_thirdpartyutil.js]
 [test_xhr_standalone.js]
 [test_xmlserializer.js]
 [test_csp_ignores_path.js]
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -65,16 +65,17 @@
 #include <algorithm>
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 
 #include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/CheckedInt.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/Endian.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/PathHelpers.h"
@@ -4001,31 +4002,35 @@ CanvasRenderingContext2D::FillRuleChange
     mPath = nullptr;
   }
 }
 
 void
 CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
                                        double dy, ErrorResult& error)
 {
-  dom::Uint8ClampedArray arr(imageData.GetDataObject());
+  dom::Uint8ClampedArray arr;
+  DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
+  MOZ_ASSERT(inited);
 
   error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
                                 imageData.Width(), imageData.Height(),
                                 &arr, false, 0, 0, 0, 0);
 }
 
 void
 CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
                                        double dy, double dirtyX,
                                        double dirtyY, double dirtyWidth,
                                        double dirtyHeight,
                                        ErrorResult& error)
 {
-  dom::Uint8ClampedArray arr(imageData.GetDataObject());
+  dom::Uint8ClampedArray arr;
+  DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
+  MOZ_ASSERT(inited);
 
   error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
                                 imageData.Width(), imageData.Height(),
                                 &arr, true,
                                 JS_DoubleToInt32(dirtyX),
                                 JS_DoubleToInt32(dirtyY),
                                 JS_DoubleToInt32(dirtyWidth),
                                 JS_DoubleToInt32(dirtyHeight));
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -37,16 +37,17 @@
 #include "WebGLValidateStrings.h"
 #include <algorithm>
 
 // needed to check if current OS is lower than 10.7
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
+#include "mozilla/DebugOnly.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Endian.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gl;
@@ -3708,17 +3709,19 @@ WebGLContext::TexImage2D(GLenum target, 
     if (IsContextLost())
         return;
 
     if (!pixels) {
         // Spec says to generate an INVALID_VALUE error
         return ErrorInvalidValue("texImage2D: null ImageData");
     }
 
-    Uint8ClampedArray arr(pixels->GetDataObject());
+    Uint8ClampedArray arr;
+    DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
+    MOZ_ASSERT(inited);
     arr.ComputeLengthAndData();
 
     return TexImage2D_base(target, level, internalformat, pixels->Width(),
                            pixels->Height(), 4*pixels->Width(), 0,
                            format, type, arr.Data(), arr.Length(), -1,
                            WebGLTexelFormat::RGBA8, false);
 }
 
@@ -3841,17 +3844,19 @@ WebGLContext::TexSubImage2D(GLenum targe
                             ErrorResult& rv)
 {
     if (IsContextLost())
         return;
 
     if (!pixels)
         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
 
-    Uint8ClampedArray arr(pixels->GetDataObject());
+    Uint8ClampedArray arr;
+    DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
+    MOZ_ASSERT(inited);
     arr.ComputeLengthAndData();
 
     return TexSubImage2D_base(target, level, xoffset, yoffset,
                               pixels->Width(), pixels->Height(),
                               4*pixels->Width(), format, type,
                               arr.Data(), arr.Length(),
                               -1,
                               WebGLTexelFormat::RGBA8, false);
--- a/content/html/content/src/HTMLTemplateElement.cpp
+++ b/content/html/content/src/HTMLTemplateElement.cpp
@@ -6,51 +6,33 @@
 #include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/HTMLTemplateElementBinding.h"
 
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsIAtom.h"
 #include "nsRuleData.h"
 
-using namespace mozilla::dom;
-
-nsGenericHTMLElement*
-NS_NewHTMLTemplateElement(already_AddRefed<nsINodeInfo>&& aNodeInfo,
-                          FromParser aFromParser)
-{
-  HTMLTemplateElement* it = new HTMLTemplateElement(aNodeInfo);
-  nsresult rv = it->Init();
-  if (NS_FAILED(rv)) {
-    delete it;
-    return nullptr;
-  }
-
-  return it;
-}
+NS_IMPL_NS_NEW_HTML_ELEMENT(Template)
 
 namespace mozilla {
 namespace dom {
 
 HTMLTemplateElement::HTMLTemplateElement(already_AddRefed<nsINodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
 {
   SetHasWeirdParserInsertionMode();
-}
 
-nsresult
-HTMLTemplateElement::Init()
-{
   nsIDocument* contentsOwner = OwnerDoc()->GetTemplateContentsOwner();
-  NS_ENSURE_TRUE(contentsOwner, NS_ERROR_UNEXPECTED);
+  if (!contentsOwner) {
+    MOZ_CRASH("There should always be a template contents owner.");
+  }
 
   mContent = contentsOwner->CreateDocumentFragment();
   mContent->SetHost(this);
-
-  return NS_OK;
 }
 
 HTMLTemplateElement::~HTMLTemplateElement()
 {
   if (mContent) {
     mContent->SetHost(nullptr);
   }
 }
@@ -72,17 +54,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // QueryInterface implementation for HTMLTemplateElement
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLTemplateElement)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
 
-NS_IMPL_ELEMENT_CLONE_WITH_INIT(HTMLTemplateElement)
+NS_IMPL_ELEMENT_CLONE(HTMLTemplateElement)
 
 JSObject*
 HTMLTemplateElement::WrapNode(JSContext *aCx)
 {
   return HTMLTemplateElementBinding::Wrap(aCx, this);
 }
 
 } // namespace dom
--- a/content/html/content/src/HTMLTemplateElement.h
+++ b/content/html/content/src/HTMLTemplateElement.h
@@ -23,18 +23,16 @@ public:
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTemplateElement,
                                            nsGenericHTMLElement)
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
-  nsresult Init();
-
   DocumentFragment* Content()
   {
     return mContent;
   }
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx) MOZ_OVERRIDE;
 
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -8,16 +8,17 @@
 #include "prlog.h"
 #include "prdtoa.h"
 #include "AudioStream.h"
 #include "VideoUtils.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Mutex.h"
 #include <algorithm>
 #include "mozilla/Preferences.h"
+#include "mozilla/Telemetry.h"
 #include "soundtouch/SoundTouch.h"
 #include "Latency.h"
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
@@ -67,16 +68,26 @@ bool AudioStream::sCubebLatencyPrefSet;
     // audible.
     sCubebLatencyPrefSet = Preferences::HasUserValue(aPref);
     uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_MS);
     StaticMutexAutoLock lock(sMutex);
     sCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
   }
 }
 
+/*static*/ bool AudioStream::GetFirstStream()
+{
+  static bool sFirstStream = true;
+
+  StaticMutexAutoLock lock(sMutex);
+  bool result = sFirstStream;
+  sFirstStream = false;
+  return result;
+}
+
 /*static*/ double AudioStream::GetVolumeScale()
 {
   StaticMutexAutoLock lock(sMutex);
   return sVolumeScale;
 }
 
 /*static*/ cubeb* AudioStream::GetCubebContext()
 {
@@ -379,16 +390,19 @@ WriteDumpFile(FILE* aDumpFile, AudioStre
 
 // NOTE: this must not block a LowLatency stream for any significant amount
 // of time, or it will block the entirety of MSG
 nsresult
 AudioStream::Init(int32_t aNumChannels, int32_t aRate,
                   const dom::AudioChannel aAudioChannel,
                   LatencyRequest aLatencyRequest)
 {
+  mStartTime = TimeStamp::Now();
+  mIsFirst = GetFirstStream();
+
   if (!GetCubebContext() || aNumChannels < 0 || aRate < 0) {
     return NS_ERROR_FAILURE;
   }
 
   PR_LOG(gAudioStreamLog, PR_LOG_DEBUG,
     ("%s  channels: %d, rate: %d for %p", __FUNCTION__, aNumChannels, aRate, this));
   mInRate = mOutRate = aRate;
   mChannels = aNumChannels;
@@ -489,16 +503,24 @@ AudioStream::OpenCubeb(cubeb_stream_para
     } else {
       MonitorAutoLock mon(mMonitor);
       mState = ERRORED;
       LOG(("AudioStream::OpenCubeb() %p failed to init cubeb", this));
       return NS_ERROR_FAILURE;
     }
   }
 
+  if (!mStartTime.IsNull()) {
+		TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
+    LOG(("AudioStream creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
+         (uint32_t) timeDelta.ToMilliseconds()));
+		Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
+                          Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
+  }
+
   return NS_OK;
 }
 
 void
 AudioStream::CheckForStart()
 {
   if (mState == INITIALIZED) {
     // Start the stream right away when low latency has been requested. This means
--- a/content/media/AudioStream.h
+++ b/content/media/AudioStream.h
@@ -302,16 +302,17 @@ private:
   // So we can call it asynchronously from AudioInitTask
   nsresult OpenCubeb(cubeb_stream_params &aParams,
                      LatencyRequest aLatencyRequest);
 
   void CheckForStart();
 
   static void PrefChanged(const char* aPref, void* aClosure);
   static double GetVolumeScale();
+  static bool GetFirstStream();
   static cubeb* GetCubebContext();
   static cubeb* GetCubebContextUnlocked();
   static uint32_t GetCubebLatency();
   static bool CubebLatencyPrefSet();
 
   static long DataCallback_S(cubeb_stream*, void* aThis, void* aBuffer, long aFrames)
   {
     return static_cast<AudioStream*>(aThis)->DataCallback(aBuffer, aFrames);
@@ -418,16 +419,17 @@ private:
                  // completion.
     DRAINED,     // StateCallback has indicated that the drain is complete.
     ERRORED,     // Stream disabled due to an internal error.
     SHUTDOWN     // Shutdown has been called
   };
 
   StreamState mState;
   bool mNeedsStart; // needed in case Start() is called before cubeb is open
+  bool mIsFirst;
 
   // This mutex protects the static members below.
   static StaticMutex sMutex;
   static cubeb* sCubebContext;
 
   // Prefered samplerate, in Hz (characteristic of the
   // hardware/mixer/platform/API used).
   static uint32_t sPreferredSampleRate;
--- a/content/media/omx/OMXCodecProxy.cpp
+++ b/content/media/omx/OMXCodecProxy.cpp
@@ -75,17 +75,17 @@ OMXCodecProxy::~OMXCodecProxy()
         // this value come from stagefrigh's AwesomePlayer.
         usleep(1000);
     }
   }
   // Complete all pending Binder ipc transactions
   IPCThreadState::self()->flushCommands();
 
   if (mManagerService.get() && mClient.get()) {
-    mManagerService->cancelClient(mClient);
+    mManagerService->cancelClient(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER);
   }
 
   mSource.clear();
   free(mComponentName);
   mComponentName = nullptr;
 }
 
 MediaResourceManagerClient::State OMXCodecProxy::getState()
@@ -121,17 +121,17 @@ void OMXCodecProxy::requestResource()
   mClient = new MediaResourceManagerClient(listener);
 
   mManagerService = mClient->getMediaResourceManagerService();
   if (!mManagerService.get()) {
     mClient = nullptr;
     return;
   }
 
-  mManagerService->requestMediaResource(mClient, MediaResourceManagerClient::HW_VIDEO_DECODER);
+  mManagerService->requestMediaResource(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER, true /* will wait */);
 }
 
 bool OMXCodecProxy::IsWaitingResources()
 {
   Mutex::Autolock autoLock(mLock);
   return mState == MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE;
 }
 
--- a/content/media/omx/OMXCodecWrapper.cpp
+++ b/content/media/omx/OMXCodecWrapper.cpp
@@ -29,16 +29,42 @@ using namespace mozilla::layers;
 
 #define CODEC_ERROR(args...)                                                   \
   do {                                                                         \
     __android_log_print(ANDROID_LOG_ERROR, "OMXCodecWrapper", ##args);         \
   } while (0)
 
 namespace android {
 
+bool
+OMXCodecReservation::ReserveOMXCodec()
+{
+  if (!mManagerService.get()) {
+    sp<MediaResourceManagerClient::EventListener> listener = this;
+    mClient = new MediaResourceManagerClient(listener);
+
+    mManagerService = mClient->getMediaResourceManagerService();
+    if (!mManagerService.get()) {
+      mClient = nullptr;
+      return true; // not really in use, but not usable
+    }
+  }
+  return (mManagerService->requestMediaResource(mClient, mType, false) == OK); // don't wait
+}
+
+void
+OMXCodecReservation::ReleaseOMXCodec()
+{
+  if (!mManagerService.get() || !mClient.get()) {
+    return;
+  }
+
+  mManagerService->cancelClient(mClient, mType);
+}
+
 OMXAudioEncoder*
 OMXCodecWrapper::CreateAACEncoder()
 {
   nsAutoPtr<OMXAudioEncoder> aac(new OMXAudioEncoder(CodecType::AAC_ENC));
   // Return the object only when media codec is valid.
   NS_ENSURE_TRUE(aac->IsValid(), nullptr);
 
   return aac.forget();
--- a/content/media/omx/OMXCodecWrapper.h
+++ b/content/media/omx/OMXCodecWrapper.h
@@ -2,28 +2,64 @@
 /* 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 OMXCodecWrapper_h_
 #define OMXCodecWrapper_h_
 
 #include <gui/Surface.h>
+#include <utils/RefBase.h>
 #include <stagefright/foundation/ABuffer.h>
 #include <stagefright/foundation/AMessage.h>
 #include <stagefright/MediaCodec.h>
 
 #include "AudioSegment.h"
 #include "GonkNativeWindow.h"
 #include "GonkNativeWindowClient.h"
 
+#include "IMediaResourceManagerService.h"
+#include "MediaResourceManagerClient.h"
+
 #include <speex/speex_resampler.h>
 
 namespace android {
 
+// Wrapper class for managing HW codec reservations
+class OMXCodecReservation : public MediaResourceManagerClient::EventListener
+{
+public:
+  OMXCodecReservation(bool aEncoder)
+  {
+    mType = aEncoder ? IMediaResourceManagerService::HW_VIDEO_ENCODER :
+            IMediaResourceManagerService::HW_VIDEO_DECODER;
+  }
+
+  virtual ~OMXCodecReservation()
+  {
+    ReleaseOMXCodec();
+  }
+
+  /** Reserve the Encode or Decode resource for this instance */
+  virtual bool ReserveOMXCodec();
+
+  /** Release the Encode or Decode resource for this instance */
+  virtual void ReleaseOMXCodec();
+
+  // MediaResourceManagerClient::EventListener
+  virtual void statusChanged(int event) {}
+
+private:
+  IMediaResourceManagerService::ResourceType mType;
+
+  sp<MediaResourceManagerClient> mClient;
+  sp<IMediaResourceManagerService> mManagerService;
+};
+
+
 class OMXAudioEncoder;
 class OMXVideoEncoder;
 
 /**
  * This class (and its subclasses) wraps the video and audio codec from
  * MediaCodec API in libstagefright. Currently only AVC/H.264 video encoder and
  * AAC audio encoder are supported.
  *
--- a/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp
+++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.cpp
@@ -29,30 +29,33 @@ enum {
 class BpMediaResourceManagerService : public BpInterface<IMediaResourceManagerService>
 {
 public:
     BpMediaResourceManagerService(const sp<IBinder>& impl)
         : BpInterface<IMediaResourceManagerService>(impl)
     {
     }
 
-    virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
+    virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
         data.writeStrongBinder(client->asBinder());
         data.writeInt32(resourceType);
+        data.writeInt32(willWait ? 1 : 0);
         remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply);
+        return reply.readInt32();
     }
 
-    virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client)
+    virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
         data.writeStrongBinder(client->asBinder());
+        data.writeInt32(resourceType);
         remote()->transact(DEREGISTER_CLIENT, data, &reply);
         return reply.readInt32();
     }
 };
 
 IMPLEMENT_META_INTERFACE(MediaResourceManagerService, "android.media.IMediaResourceManagerService");
 
 // ----------------------------------------------------------------------
@@ -61,24 +64,27 @@ status_t BnMediaResourceManagerService::
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     switch(code) {
 
         case REQUEST_MEDIA_RESOURCE: {
             CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
             sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
             int resourceType = data.readInt32();
-            requestMediaResource(client, resourceType);
+            bool willWait = (data.readInt32() == 1);
+            status_t result = requestMediaResource(client, resourceType, willWait);
+            reply->writeInt32(result);
             return NO_ERROR;
         } break;
         case DEREGISTER_CLIENT: {
             CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
             sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
-            cancelClient(client);
-            reply->writeInt32(NO_ERROR);
+            int resourceType = data.readInt32();
+            status_t result = cancelClient(client, resourceType);
+            reply->writeInt32(result);
             return NO_ERROR;
         } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
 }
 
 // ----------------------------------------------------------------------------
--- a/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h
+++ b/content/media/omx/mediaresourcemanager/IMediaResourceManagerService.h
@@ -17,20 +17,46 @@ namespace android {
 
 // ----------------------------------------------------------------------------
 
 class IMediaResourceManagerService : public IInterface
 {
 public:
     DECLARE_META_INTERFACE(MediaResourceManagerService);
 
+    // Enumeration for the resource types
+    enum ResourceType {
+      HW_VIDEO_DECODER = 0,
+      HW_AUDIO_DECODER,  // Not supported currently.
+      HW_VIDEO_ENCODER,
+      HW_CAMERA,          // Not supported currently.
+      NUM_OF_RESOURCE_TYPES,
+      INVALID_RESOURCE_TYPE = -1
+    };
+
+    enum ErrorCode {
+        RESOURCE_NOT_AVAILABLE = -EAGAIN
+    };
+
     // Request a media resource for IMediaResourceManagerClient.
-    virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
+    // client is the binder that service will notify (through
+    // IMediaResourceManagerClient::statusChanged()) when request status changed.
+    // resourceType is type of resource that client would like to request.
+    // willWait indicates that, when the resource is not currently available
+    // (i.e., already in use by another client), if the client wants to wait. If
+    // true, client will be put into a (FIFO) waiting list and be notified when
+    // resource is available.
+    // For unsupported types, this function returns BAD_TYPE. For supported
+    // types, it always returns OK when willWait is true; otherwise it will
+    // return true when resouce is available, or RESOURCE_NOT_AVAILABLE when
+    // resouce is in use.
+    virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait) = 0;
     // Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
-    virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client) = 0;
+    // Client must call this function after it's done with the media resource requested.
+    virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
 };
 
 
 // ----------------------------------------------------------------------------
 
 class BnMediaResourceManagerService : public BnInterface<IMediaResourceManagerService>
 {
 public:
--- a/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.h
+++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerClient.h
@@ -17,22 +17,16 @@ class MediaResourceManagerClient: public
 {
 public:
   // Enumeration for the valid decoding states
   enum State {
     CLIENT_STATE_WAIT_FOR_RESOURCE,
     CLIENT_STATE_RESOURCE_ASSIGNED,
     CLIENT_STATE_SHUTDOWN
   };
-  // Enumeration for the resource types
-  enum ResourceType {
-    HW_VIDEO_DECODER,
-    HW_AUDIO_DECODER,
-    HW_CAMERA
-  };
 
   struct EventListener : public virtual RefBase {
     // Notifies a change of media resource request status.
     virtual void statusChanged(int event) = 0;
   };
 
   MediaResourceManagerClient(const wp<EventListener>& listener);
 
--- a/content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
+++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerService.cpp
@@ -2,33 +2,37 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaResourceManagerService"
 
+#include <mozilla/Assertions.h>
+
 #include <binder/IServiceManager.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <utils/Log.h>
 
 #include "MediaResourceManagerClient.h"
 #include "MediaResourceManagerService.h"
 
 namespace android {
 
+const char* MediaResourceManagerService::kMsgKeyResourceType = "res-type";
+
 /* static */
 void MediaResourceManagerService::instantiate() {
   defaultServiceManager()->addService(
-            String16("media.resource_manager"), new MediaResourceManagerService());
+            String16("media.resource_manager"),
+            new MediaResourceManagerService());
 }
 
 MediaResourceManagerService::MediaResourceManagerService()
-  : mVideoDecoderCount(VIDEO_DECODER_COUNT)
 {
   mLooper = new ALooper;
   mLooper->setName("MediaResourceManagerService");
 
   mReflector = new AHandlerReflector<MediaResourceManagerService>(this);
   // Register AMessage handler to ALooper.
   mLooper->registerHandler(mReflector);
   // Start ALooper thread.
@@ -44,104 +48,324 @@ MediaResourceManagerService::~MediaResou
 }
 
 void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
 {
   if (who != NULL) {
     Mutex::Autolock autoLock(mLock);
     sp<IBinder> binder = who.promote();
     if (binder != NULL) {
-      cancelClientLocked(binder);
+      mResources.forgetClient(binder);
     }
   }
 }
 
-void MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType)
+status_t MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client,
+                                                           int resourceType, bool willWait)
 {
-  if (resourceType != MediaResourceManagerClient::HW_VIDEO_DECODER) {
-    // Support only HW_VIDEO_DECODER
-    return;
-  }
-
-  {
-    Mutex::Autolock autoLock(mLock);
-    sp<IBinder> binder = client->asBinder();
-    mVideoCodecRequestQueue.push_back(binder);
-    binder->linkToDeath(this);
+  ResourceType type = static_cast<ResourceType>(resourceType);
+  // Support only HW_VIDEO_DECODER and HW_VIDEO_ENCODER.
+  switch (type) {
+    case HW_VIDEO_DECODER:
+    case HW_VIDEO_ENCODER:
+      break;
+    default:
+      // Type not supported.
+      return BAD_TYPE;
   }
 
-  sp<AMessage> notify =
-            new AMessage(kNotifyRequest, mReflector->id());
-  // Post AMessage to MediaResourceManagerService via ALooper.
-  notify->post();
-}
+  Mutex::Autolock autoLock(mLock);
 
-status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client)
-{
-  {
-    Mutex::Autolock autoLock(mLock);
-    sp<IBinder> binder = client->asBinder();
-    cancelClientLocked(binder);
+  // Must know if it will be granted or not - if there are enough unfufilled requests to
+  // use up the resource, fail.  Otherwise we know that enqueuing under lock will succeed.
+  if (!willWait &&
+      (mResources.findAvailableResource(type, mResources.countRequests(type) + 1) ==
+       NAME_NOT_FOUND)) {
+    return RESOURCE_NOT_AVAILABLE;
   }
+  // We could early-return here without enqueuing IF we can do the rest of
+  // the allocation safely here.  However, enqueuing ensures there's only
+  // one copy of that code, and that any callbacks are made from the same
+  // context.
 
-  sp<AMessage> notify =
-            new AMessage(kNotifyRequest, mReflector->id());
+  sp<IBinder> binder = client->asBinder();
+  mResources.enqueueRequest(binder, type);
+  binder->linkToDeath(this);
+
+  sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
+  notify->setInt32(kMsgKeyResourceType, resourceType);
   // Post AMessage to MediaResourceManagerService via ALooper.
   notify->post();
 
+  return OK;
+}
+
+status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client,
+                                                   int resourceType)
+{
+  Mutex::Autolock autoLock(mLock);
+
+  sp<IBinder> binder = client->asBinder();
+  cancelClientLocked(binder, static_cast<ResourceType>(resourceType));
+
+  sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
+  notify->setInt32(kMsgKeyResourceType, resourceType);
+  // Next!
+  // Note: since we held the lock while releasing and then posting, if there is
+  // a queue, no willWait==false entries can jump into the queue thinking they'll
+  // get the resource.
+  notify->post();
+
   return NO_ERROR;
 }
 
+// Extract resource type from message.
+static int32_t getResourceType(const sp<AMessage>& message)
+{
+  int32_t resourceType = MediaResourceManagerService::INVALID_RESOURCE_TYPE;
+  return message->findInt32(MediaResourceManagerService::kMsgKeyResourceType, &resourceType) ?
+          resourceType : MediaResourceManagerService::INVALID_RESOURCE_TYPE;
+}
+
 // Called on ALooper thread.
 void MediaResourceManagerService::onMessageReceived(const sp<AMessage> &msg)
 {
   Mutex::Autolock autoLock(mLock);
+  ResourceType type = static_cast<ResourceType>(getResourceType(msg));
+
+  // Note: a message is sent both for "I added an entry to the queue"
+  // (which may succeed, typically if the queue is empty), and for "I gave
+  // up the resource", in which case it's "give to the next waiting client,
+  // or no one".
+
+  // Exit if no resource is available, but leave the client in the waiting
+  // list.
+  int found = mResources.findAvailableResource(type);
+  if (found == NAME_NOT_FOUND) {
+    return;
+  }
 
   // Exit if no request.
-  if (mVideoCodecRequestQueue.empty()) {
+  if (!mResources.hasRequest(type)) {
     return;
   }
 
-  // Check if resource is available
-  int found = -1;
-  for (int i=0 ; i<mVideoDecoderCount ; i++) {
-    if (!mVideoDecoderSlots[i].mClient.get()) {
+  const sp<IBinder>& req = mResources.nextRequest(type);
+  mResources.aquireResource(req, type, found);
+  // Notify resource assignment to the client.
+  sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
+  client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
+  mResources.dequeueRequest(type);
+}
+
+void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
+                                                     ResourceType resourceType)
+{
+  mResources.forgetClient(binder, resourceType);
+  binder->unlinkToDeath(this);
+}
+
+MediaResourceManagerService::ResourceTable::ResourceTable()
+{
+  // Populate types of resources.
+  for (int type = 0; type < NUM_OF_RESOURCE_TYPES; type++) {
+    ssize_t index = mMap.add(static_cast<ResourceType>(type), Resources());
+    Resources& resources = mMap.editValueAt(index);
+    int available;
+    switch (type) {
+      case HW_VIDEO_DECODER:
+        available = VIDEO_DECODER_COUNT;
+        break;
+      case HW_VIDEO_ENCODER:
+        available = VIDEO_ENCODER_COUNT;
+        break;
+      default:
+        available = 0;
+        break;
+    }
+    resources.mSlots.insertAt(0, available);
+  }
+}
+
+MediaResourceManagerService::ResourceTable::~ResourceTable() {
+  // Remove resouces.
+  mMap.clear();
+}
+
+bool MediaResourceManagerService::ResourceTable::supportsType(ResourceType type)
+{
+  return mMap.indexOfKey(type) != NAME_NOT_FOUND;
+}
+
+ssize_t MediaResourceManagerService::ResourceTable::findAvailableResource(ResourceType type,
+                                                                          size_t numberNeeded)
+{
+  MOZ_ASSERT(numberNeeded > 0);
+  ssize_t found = mMap.indexOfKey(type);
+  if (found == NAME_NOT_FOUND) {
+    // Unsupported type.
+    return found;
+  }
+  const Slots& slots = mMap.valueAt(found).mSlots;
+
+  found = NAME_NOT_FOUND;
+  for (size_t i = 0; i < slots.size(); i++) {
+    if (slots[i].mClient != nullptr) {
+      // Already in use.
+      continue;
+    }
+    if (--numberNeeded == 0) {
       found = i;
+      break;
     }
   }
 
-  // Exit if no resource is available.
-  if (found == -1) {
-    return;
+  return found;
+}
+
+bool MediaResourceManagerService::ResourceTable::isOwnedByClient(const sp<IBinder>& client,
+                                                                 ResourceType type,
+                                                                 size_t index)
+{
+  ResourceSlot* slot = resourceOfTypeAt(type, index);
+  return slot && slot->mClient == client;
+}
+
+status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp<IBinder>& client,
+                                                                    ResourceType type,
+                                                                    size_t index)
+{
+  ResourceSlot* slot = resourceOfTypeAt(type, index);
+  // Resouce should not be in use.
+  MOZ_ASSERT(slot && slot->mClient == nullptr);
+  if (!slot) {
+    return NAME_NOT_FOUND;
+  } else if (slot->mClient != nullptr) {
+    // Resource already in use by other client.
+    return PERMISSION_DENIED;
+  }
+
+  slot->mClient = client;
+
+
+  return OK;
+}
+
+MediaResourceManagerService::ResourceSlot*
+MediaResourceManagerService::ResourceTable::resourceOfTypeAt(ResourceType type,
+                                                             size_t index)
+{
+  ssize_t found = mMap.indexOfKey(type);
+  if (found == NAME_NOT_FOUND) {
+    // Unsupported type.
+    return nullptr;
+  }
+
+  Slots& slots = mMap.editValueAt(found).mSlots;
+  MOZ_ASSERT(index < slots.size());
+  if (index >= slots.size()) {
+    // Index out of range.
+    return nullptr;
+  }
+  return &(slots.editItemAt(index));
+}
+
+bool MediaResourceManagerService::ResourceTable::hasRequest(ResourceType type)
+{
+  ssize_t found = mMap.indexOfKey(type);
+  if (found == NAME_NOT_FOUND) {
+    // Unsupported type.
+    return nullptr;
   }
 
-  // Assign resource to IMediaResourceManagerClient
-  Fifo::iterator front(mVideoCodecRequestQueue.begin());
-  mVideoDecoderSlots[found].mClient = *front;
-  mVideoCodecRequestQueue.erase(front);
-  // Notify resource assignment to the client.
-  sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(mVideoDecoderSlots[found].mClient);
-  client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
+  const Fifo& queue = mMap.valueAt(found).mRequestQueue;
+  return !queue.empty();
+}
+
+uint32_t MediaResourceManagerService::ResourceTable::countRequests(ResourceType type)
+{
+  ssize_t found = mMap.indexOfKey(type);
+  if (found == NAME_NOT_FOUND) {
+    // Unsupported type.
+    return 0;
+  }
+
+  const Fifo& queue = mMap.valueAt(found).mRequestQueue;
+  return queue.size();
+}
+
+const sp<IBinder>& MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
+{
+  ssize_t found = mMap.indexOfKey(type);
+  if (found == NAME_NOT_FOUND) {
+    // Unsupported type.
+    return nullptr;
+  }
+
+  const Fifo& queue = mMap.valueAt(found).mRequestQueue;
+  return *(queue.begin());
 }
 
-void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder)
+status_t MediaResourceManagerService::ResourceTable::enqueueRequest(const sp<IBinder>& client,
+                                                                    ResourceType type)
+{
+  ssize_t found = mMap.indexOfKey(type);
+  if (found == NAME_NOT_FOUND) {
+    // Unsupported type.
+    return found;
+  }
+
+  mMap.editValueAt(found).mRequestQueue.push_back(client);
+  return OK;
+}
+
+status_t MediaResourceManagerService::ResourceTable::dequeueRequest(ResourceType type)
 {
-  // Clear the request from request queue.
-  Fifo::iterator it(mVideoCodecRequestQueue.begin());
-  while (it != mVideoCodecRequestQueue.end()) {
-    if ((*it).get() == binder.get()) {
-      mVideoCodecRequestQueue.erase(it);
+  ssize_t found = mMap.indexOfKey(type);
+  if (found == NAME_NOT_FOUND) {
+    // Unsupported type.
+    return found;
+  }
+
+  Fifo& queue = mMap.editValueAt(found).mRequestQueue;
+  queue.erase(queue.begin());
+  return OK;
+}
+
+status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
+{
+  // Traverse all resources.
+  for (int i = 0; i < mMap.size(); i++) {
+    forgetClient(client, mMap.keyAt(i));
+  }
+  return OK;
+}
+
+status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
+{
+  MOZ_ASSERT(supportsType(type));
+
+  Resources& resources = mMap.editValueFor(type);
+
+  // Remove pending requests for given client.
+  Fifo& queue = resources.mRequestQueue;
+  Fifo::iterator it(queue.begin());
+  while (it != queue.end()) {
+    if ((*it).get() == client.get()) {
+      queue.erase(it);
       break;
     }
     it++;
   }
 
-  // Clear the client from the resource
-  for (int i=0 ; i<mVideoDecoderCount ; i++) {
-    if (mVideoDecoderSlots[i].mClient.get() == binder.get()) {
-      mVideoDecoderSlots[i].mClient = NULL;
+  // Revoke ownership for given client.
+  Slots& slots = resources.mSlots;
+  for (int i = 0; i < slots.size(); i++) {
+    ResourceSlot& slot = slots.editItemAt(i);
+    if (client.get() == slot.mClient.get()) {
+      slot.mClient = nullptr;
     }
   }
-  binder->unlinkToDeath(this);
+
+  return OK;
 }
 
 }; // namespace android
-
--- a/content/media/omx/mediaresourcemanager/MediaResourceManagerService.h
+++ b/content/media/omx/mediaresourcemanager/MediaResourceManagerService.h
@@ -5,91 +5,131 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ANDROID_MEDIARESOURCEMANAGERSERVICE_H
 #define ANDROID_MEDIARESOURCEMANAGERSERVICE_H
 
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AHandlerReflector.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <utils/KeyedVector.h>
 #include <utils/List.h>
 #include <utils/RefBase.h>
+#include <utils/Vector.h>
 
 #include "IMediaResourceManagerClient.h"
 #include "IMediaResourceManagerService.h"
 
 namespace android {
 
 /**
  * Manage permissions of using media resources(hw decoder, hw encoder, camera)
- * XXX Current implementaion support only one hw video decoder.
+ * XXX Current implementation supports only one hw video codec.
  *     Need to extend to support multiple instance and other resources.
  */
 class MediaResourceManagerService: public BnMediaResourceManagerService,
                                    public IBinder::DeathRecipient
 {
 public:
-  // The maximum number of hardware decoders available.
-  enum { VIDEO_DECODER_COUNT = 1 };
+  // The maximum number of hardware resoureces available.
+  enum
+  {
+    VIDEO_DECODER_COUNT = 1,
+    VIDEO_ENCODER_COUNT = 1
+  };
 
-  enum {
-    kNotifyRequest = 'noti'
+  enum
+  {
+    kNotifyRequest = 'noti',
   };
 
+  static const char* kMsgKeyResourceType;
+
   // Instantiate MediaResourceManagerService and register to service manager.
   // If service manager is not present, wait until service manager becomes present.
   static  void instantiate();
 
   // DeathRecipient
   virtual void binderDied(const wp<IBinder>& who);
 
   // derived from IMediaResourceManagerService
-  virtual void requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType);
-  virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client);
+  virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client,
+                                        int resourceType, bool willWait);
+  virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client,
+                                int resourceType);
 
   // Receive a message from AHandlerReflector.
   // Called on ALooper thread.
   void onMessageReceived(const sp<AMessage> &msg);
 
 protected:
   MediaResourceManagerService();
   virtual ~MediaResourceManagerService();
 
-protected:
+private:
   // Represent a media resouce.
   // Hold a IMediaResourceManagerClient that got a media resource as IBinder.
-  struct ResourceSlot {
-    ResourceSlot ()
-      {
-      }
-      sp<IBinder> mClient;
-    };
+  struct ResourceSlot
+  {
+    sp<IBinder> mClient;
+  };
+  typedef Vector<ResourceSlot> Slots;
 
-  void cancelClientLocked(const sp<IBinder>& binder);
+  typedef List<sp<IBinder> > Fifo;
+  struct Resources
+  {
+    // Queue of media resource requests. Hold IMediaResourceManagerClient that
+    // requesting a media resource as IBinder.
+    Fifo mRequestQueue;
+    // All resources that can be requested. Hold |ResourceSlot|s that track
+    // their usage.
+    Slots mSlots;
+  };
 
-  // mVideoDecoderSlots is the array of slots that represent a media resource.
-  ResourceSlot mVideoDecoderSlots[VIDEO_DECODER_COUNT];
-  // The maximum number of hardware decoders available on the device.
-  int mVideoDecoderCount;
+  typedef KeyedVector<ResourceType, Resources> ResourcesMap;
+  // Manages requests from clients and availability of resources.
+  class ResourceTable
+  {
+    ResourceTable();
+    ~ResourceTable();
+    // Resource operations.
+    bool supportsType(ResourceType type);
+    ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
+    bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
+    status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
+    ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
+    // Request operations.
+    bool hasRequest(ResourceType type);
+    uint32_t countRequests(ResourceType type);
+    const sp<IBinder>& nextRequest(ResourceType type);
+    status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
+    status_t dequeueRequest(ResourceType type);
+    status_t forgetClient(const sp<IBinder>& client, ResourceType type);
+    status_t forgetClient(const sp<IBinder>& client);
 
-  // The lock protects mVideoDecoderSlots and mVideoCodecRequestQueue called
-  //  from multiple threads.
-  Mutex mLock;
-  typedef List<sp<IBinder> > Fifo;
-  // Queue of media resource requests.
-  // Hold IMediaResourceManagerClient that requesting a media resource as IBinder.
-  Fifo mVideoCodecRequestQueue;
+    friend class MediaResourceManagerService;
+
+    // A map for all types of supported resources.
+    ResourcesMap mMap;
+  };
+
+  void cancelClientLocked(const sp<IBinder>& binder, ResourceType resourceType);
 
   // ALooper is a message loop used in stagefright.
   // It creates a thread for messages and handles messages in the thread.
   // ALooper is a clone of Looper in android Java.
   // http://developer.android.com/reference/android/os/Looper.html
   sp<ALooper> mLooper;
   // deliver a message to a wrapped object(OmxDecoder).
   // AHandlerReflector is similar to Handler in android Java.
   // http://developer.android.com/reference/android/os/Handler.html
   sp<AHandlerReflector<MediaResourceManagerService> > mReflector;
 
+  // The lock protects manager operations called from multiple threads.
+  Mutex mLock;
+
+  // Keeps all the records.
+  ResourceTable mResources;
 };
 
 }; // namespace android
 
 #endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H
--- a/content/media/omx/mediaresourcemanager/moz.build
+++ b/content/media/omx/mediaresourcemanager/moz.build
@@ -1,14 +1,22 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+EXPORTS += [
+    'IMediaResourceManagerClient.h',
+    'IMediaResourceManagerDeathNotifier.h',
+    'IMediaResourceManagerService.h',
+    'MediaResourceManagerClient.h',
+    'MediaResourceManagerService.h',
+]
+
 SOURCES += [
     'IMediaResourceManagerClient.cpp',
     'IMediaResourceManagerDeathNotifier.cpp',
     'IMediaResourceManagerService.cpp',
     'MediaResourceManagerClient.cpp',
     'MediaResourceManagerService.cpp',
 ]
 
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -222,17 +222,16 @@ static bool UseAudioChannelService()
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioDestinationNode, AudioNode,
                                    mAudioChannelAgent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
   NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
-  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(AudioDestinationNode, AudioNode)
 
 AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
                                            bool aIsOffline,
                                            AudioChannel aChannel,
--- a/content/media/webaudio/AudioDestinationNode.h
+++ b/content/media/webaudio/AudioDestinationNode.h
@@ -7,27 +7,25 @@
 #ifndef AudioDestinationNode_h_
 #define AudioDestinationNode_h_
 
 #include "mozilla/dom/AudioChannelBinding.h"
 #include "AudioNode.h"
 #include "nsIDOMEventListener.h"
 #include "nsIAudioChannelAgent.h"
 #include "AudioChannelCommon.h"
-#include "nsWeakReference.h"
 
 namespace mozilla {
 namespace dom {
 
 class AudioContext;
 
 class AudioDestinationNode : public AudioNode
                            , public nsIDOMEventListener
                            , public nsIAudioChannelAgentCallback
-                           , public nsSupportsWeakReference
                            , public MainThreadMediaStreamListener
 {
 public:
   // This node type knows what MediaStreamGraph to use based on
   // whether it's in offline mode.
   AudioDestinationNode(AudioContext* aContext,
                        bool aIsOffline,
                        AudioChannel aChannel = AudioChannel::Normal,
--- a/content/media/webaudio/AudioNode.cpp
+++ b/content/media/webaudio/AudioNode.cpp
@@ -4,21 +4,24 @@
  * 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 "AudioNode.h"
 #include "mozilla/ErrorResult.h"
 #include "AudioNodeStream.h"
 #include "AudioNodeEngine.h"
 #include "mozilla/dom/AudioParam.h"
+#include "mozilla/Services.h"
+#include "nsIObserverService.h"
 
 namespace mozilla {
 namespace dom {
 
 static const uint32_t INVALID_PORT = 0xffffffff;
+static uint32_t gId = 0;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AudioNode, DOMEventTargetHelper)
   tmp->DisconnectFromGraph();
   if (tmp->mContext) {
     tmp->mContext->UpdateNodeCount(-1);
   }
@@ -44,39 +47,48 @@ AudioNode::Release()
     DisconnectFromGraph();
   }
   nsrefcnt r = DOMEventTargetHelper::Release();
   NS_LOG_RELEASE(this, r, "AudioNode");
   return r;
 }
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioNode)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 AudioNode::AudioNode(AudioContext* aContext,
                      uint32_t aChannelCount,
                      ChannelCountMode aChannelCountMode,
                      ChannelInterpretation aChannelInterpretation)
   : DOMEventTargetHelper(aContext->GetParentObject())
   , mContext(aContext)
   , mChannelCount(aChannelCount)
   , mChannelCountMode(aChannelCountMode)
   , mChannelInterpretation(aChannelInterpretation)
+  , mId(gId++)
+#ifdef DEBUG
+  , mDemiseNotified(false)
+#endif
 {
   MOZ_ASSERT(aContext);
   DOMEventTargetHelper::BindToOwner(aContext->GetParentObject());
   SetIsDOMBinding();
   aContext->UpdateNodeCount(1);
 }
 
 AudioNode::~AudioNode()
 {
   MOZ_ASSERT(mInputNodes.IsEmpty());
   MOZ_ASSERT(mOutputNodes.IsEmpty());
   MOZ_ASSERT(mOutputParams.IsEmpty());
+#ifdef DEBUG
+  MOZ_ASSERT(mDemiseNotified,
+             "The webaudio-node-demise notification must have been sent");
+#endif
   if (mContext) {
     mContext->UpdateNodeCount(-1);
   }
 }
 
 size_t
 AudioNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
@@ -380,16 +392,26 @@ AudioNode::DestroyMediaStream()
       MutexAutoLock lock(ns->Engine()->NodeMutex());
       MOZ_ASSERT(ns, "How come we don't have a stream here?");
       MOZ_ASSERT(ns->Engine()->Node() == this, "Invalid node reference");
       ns->Engine()->ClearNode();
     }
 
     mStream->Destroy();
     mStream = nullptr;
+
+    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+    if (obs) {
+      nsAutoString id;
+      id.AppendPrintf("%u", mId);
+      obs->NotifyObservers(nullptr, "webaudio-node-demise", id.get());
+    }
+#ifdef DEBUG
+    mDemiseNotified = true;
+#endif
   }
 }
 
 void
 AudioNode::RemoveOutputParam(AudioParam* aParam)
 {
   mOutputParams.RemoveElement(aParam);
 }
--- a/content/media/webaudio/AudioNode.h
+++ b/content/media/webaudio/AudioNode.h
@@ -11,16 +11,17 @@
 #include "mozilla/dom/AudioNodeBinding.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "AudioContext.h"
 #include "MediaStreamGraph.h"
 #include "WebAudioUtils.h"
 #include "mozilla/MemoryReporting.h"
+#include "nsWeakReference.h"
 
 namespace mozilla {
 
 namespace dom {
 
 class AudioContext;
 class AudioBufferSourceNode;
 class AudioParam;
@@ -77,17 +78,18 @@ private:
  * finished do so strictly *after* producing and returning their last block.
  * In this way, an engine that receives non-null input knows that the input
  * comes from nodes that are still alive and will keep their output nodes
  * alive for at least as long as it takes to process messages from the graph
  * thread.  i.e. the engine receiving non-null input knows that its node is
  * still alive, and will still be alive when it receives a message from the
  * engine.
  */
-class AudioNode : public DOMEventTargetHelper
+class AudioNode : public DOMEventTargetHelper,
+                  public nsSupportsWeakReference
 {
 protected:
   // You can only use refcounting to delete this object
   virtual ~AudioNode();
 
 public:
   AudioNode(AudioContext* aContext,
             uint32_t aChannelCount,
@@ -128,16 +130,18 @@ public:
   virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv);
 
   // The following two virtual methods must be implemented by each node type
   // to provide their number of input and output ports. These numbers are
   // constant for the lifetime of the node. Both default to 1.
   virtual uint16_t NumberOfInputs() const { return 1; }
   virtual uint16_t NumberOfOutputs() const { return 1; }
 
+  uint32_t Id() const { return mId; }
+
   uint32_t ChannelCount() const { return mChannelCount; }
   virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv)
   {
     if (aChannelCount == 0 ||
         aChannelCount > WebAudioUtils::MaxChannelCount) {
       aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
       return;
     }
@@ -261,14 +265,20 @@ private:
   // AudioParam::mInputNodes of the mOutputParams entry. We won't necessarily be
   // able to identify the exact matching entry, since mOutputParams doesn't
   // include the port identifiers and the same node could be connected on
   // multiple ports.
   nsTArray<nsRefPtr<AudioParam> > mOutputParams;
   uint32_t mChannelCount;
   ChannelCountMode mChannelCountMode;
   ChannelInterpretation mChannelInterpretation;
+  const uint32_t mId;
+#ifdef DEBUG
+  // In debug builds, check to make sure that the node demise notification has
+  // been properly sent before the node is destroyed.
+  bool mDemiseNotified;
+#endif
 };
 
 }
 }
 
 #endif
--- a/content/media/webaudio/MediaStreamAudioSourceNode.cpp
+++ b/content/media/webaudio/MediaStreamAudioSourceNode.cpp
@@ -37,17 +37,17 @@ MediaStreamAudioSourceNode::MediaStreamA
               ChannelInterpretation::Speakers),
     mInputStream(aMediaStream)
 {
   AudioNodeEngine* engine = new MediaStreamAudioSourceNodeEngine(this);
   mStream = aContext->Graph()->CreateAudioNodeExternalInputStream(engine);
   ProcessedMediaStream* outputStream = static_cast<ProcessedMediaStream*>(mStream.get());
   mInputPort = outputStream->AllocateInputPort(aMediaStream->GetStream(),
                                                MediaInputPort::FLAG_BLOCK_INPUT);
-  mInputStream->AddConsumerToKeepAlive(this);
+  mInputStream->AddConsumerToKeepAlive(static_cast<nsIDOMEventTarget*>(this));
 
   PrincipalChanged(mInputStream); // trigger enabling/disabling of the connector
   mInputStream->AddPrincipalChangeObserver(this);
 }
 
 MediaStreamAudioSourceNode::~MediaStreamAudioSourceNode()
 {
   if (mInputStream) {
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/chrome.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_AudioNodeDevtoolsAPI.html]
--- a/content/media/webaudio/test/moz.build
+++ b/content/media/webaudio/test/moz.build
@@ -3,8 +3,12 @@
 # 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/.
 
 MOCHITEST_MANIFESTS += [
     'blink/mochitest.ini',
     'mochitest.ini',
 ]
+
+MOCHITEST_CHROME_MANIFESTS += [
+    'chrome.ini'
+]
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_AudioNodeDevtoolsAPI.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the devtool AudioNode API</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+  Components.utils.import('resource://gre/modules/Services.jsm');
+
+  SimpleTest.waitForExplicitFinish();
+
+  var ac = new AudioContext();
+  var ids;
+  var weak;
+  (function() {
+    var src1 = ac.createBufferSource();
+    var src2 = ac.createBufferSource();
+    ok(src2.id > src1.id, "The ID should be monotonic");
+    ok(src1.id > ac.destination.id, "The ID of the destination node should be the lowest");
+    ids = [src1.id, src2.id];
+    weak = Components.utils.getWeakReference(src1);
+    is(weak.get(), src1, "The node should support a weak reference");
+  })();
+  function observer(subject, topic, data) {
+    var id = parseInt(data);
+    var index = ids.indexOf(id);
+    if (index != -1) {
+      info("Dropping id " + id + " at index " + index);
+      ids.splice(index, 1);
+      if (ids.length == 0) {
+        SimpleTest.executeSoon(function() {
+          is(weak.get(), null, "The weak reference must be dropped now");
+          Services.obs.removeObserver(observer, "webaudio-node-demise");
+          SimpleTest.finish();
+        });
+      }
+    }
+  }
+  Services.obs.addObserver(observer, "webaudio-node-demise", false);
+
+  forceCC();
+  forceCC();
+
+  function forceCC() {
+    SpecialPowers.DOMWindowUtils.cycleCollect();
+    SpecialPowers.DOMWindowUtils.garbageCollect();
+    SpecialPowers.DOMWindowUtils.garbageCollect();
+  }
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -55,16 +55,17 @@
 #include "nsIHTMLDocument.h"
 #include "mozAutoDocUpdate.h"
 #include "nsMimeTypes.h"
 #include "nsHtml5SVGLoadDispatcher.h"
 #include "nsTextNode.h"
 #include "mozilla/dom/CDATASection.h"
 #include "mozilla/dom/Comment.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLTemplateElement.h"
 #include "mozilla/dom/ProcessingInstruction.h"
 
 using namespace mozilla::dom;
 
 // XXX Open Issues:
 // 1) what's not allowed - We need to figure out which HTML tags
 //    (prefixed with a HTML namespace qualifier) are explicitly not
 //    allowed (if any).
@@ -843,17 +844,27 @@ nsXMLContentSink::GetCurrentStackNode()
 
 nsresult
 nsXMLContentSink::PushContent(nsIContent *aContent)
 {
   NS_PRECONDITION(aContent, "Null content being pushed!");
   StackNode *sn = mContentStack.AppendElement();
   NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
 
-  sn->mContent = aContent;
+  nsIContent* contentToPush = aContent;
+
+  // When an XML parser would append a node to a template element, it
+  // must instead append it to the template element's template contents.
+  if (contentToPush->IsHTML(nsGkAtoms::_template)) {
+    HTMLTemplateElement* templateElement =
+      static_cast<HTMLTemplateElement*>(contentToPush);
+    contentToPush = templateElement->Content();
+  }
+
+  sn->mContent = contentToPush;
   sn->mNumFlushed = 0;
   return NS_OK;
 }
 
 void
 nsXMLContentSink::PopContent()
 {
   int32_t count = mContentStack.Length();
@@ -1071,18 +1082,23 @@ nsXMLContentSink::HandleEndElement(const
   NS_ASSERTION(content, "failed to pop content");
 #ifdef DEBUG
   // Check that we're closing the right thing
   nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
   int32_t debugNameSpaceID;
   nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
                                  getter_AddRefs(debugTagAtom),
                                  &debugNameSpaceID);
-  NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
-               "Wrong element being closed");
+  // Check if we are closing a template element because template
+  // elements do not get pushed on the stack, the template
+  // element content is pushed instead.
+  bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
+                           debugNameSpaceID == kNameSpaceID_XHTML;
+  NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
+               isTemplateElement, "Wrong element being closed");
 #endif  
 
   result = CloseElement(content);
 
   if (mCurrentHead == content) {
     mCurrentHead = nullptr;
   }
   
--- a/dom/archivereader/ArchiveRequest.cpp
+++ b/dom/archivereader/ArchiveRequest.cpp
@@ -149,19 +149,23 @@ ArchiveRequest::ReaderReady(nsTArray<nsC
     case GetFilenames:
       rv = GetFilenamesResult(cx, result.address(), aFileList);
       break;
 
     case GetFile:
       rv = GetFileResult(cx, &result, aFileList);
       break;
 
-      case GetFiles:
-        rv = GetFilesResult(cx, &result, aFileList);
-        break;
+    case GetFiles:
+      rv = GetFilesResult(cx, &result, aFileList);
+      break;
+
+    default:
+      rv = NS_ERROR_UNEXPECTED;
+      break;
   }
 
   if (NS_FAILED(rv)) {
     NS_WARNING("Get*Result failed!");
   }
 
   if (NS_SUCCEEDED(rv)) {
     FireSuccess(result);
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1492,17 +1492,17 @@ Navigator::GetFeature(const nsAString& a
   nsRefPtr<Promise> p = new Promise(go);
 
 #if defined(XP_LINUX)
   if (aName.EqualsLiteral("hardware.memory")) {
     // with seccomp enabled, fopen() should be in a non-sandboxed process
     if (XRE_GetProcessType() == GeckoProcessType_Default) {
       uint32_t memLevel = mozilla::hal::GetTotalSystemMemoryLevel();
       if (memLevel == 0) {
-        p->MaybeReject(NS_LITERAL_STRING("Abnormal"));
+        p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
         return p.forget();
       }
       p->MaybeResolve((int)memLevel);
     } else {
       mozilla::dom::ContentChild* cc =
         mozilla::dom::ContentChild::GetSingleton();
       nsRefPtr<Promise> ipcRef(p);
       cc->SendGetSystemMemory(reinterpret_cast<uint64_t>(ipcRef.forget().take()));
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -239,16 +239,17 @@ AutoJSAPIWithErrorsReportedToWindow::Aut
 
 AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
                                  bool aIsMainThread,
                                  JSContext* aCx)
   : AutoJSAPI(aCx ? aCx : FindJSContext(aGlobalObject), aIsMainThread, /* aSkipNullAc = */ true)
   , ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
   , mAc(cx(), aGlobalObject->GetGlobalJSObject())
   , mStack(ScriptSettingsStack::Ref())
+  , mWebIDLCallerPrincipal(nullptr)
 {
   MOZ_ASSERT(aGlobalObject);
   MOZ_ASSERT_IF(!aCx, aIsMainThread); // cx is mandatory off-main-thread.
   MOZ_ASSERT_IF(aCx && aIsMainThread, aCx == FindJSContext(aGlobalObject));
   mStack.Push(this);
 }
 
 AutoEntryScript::~AutoEntryScript()
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -174,17 +174,24 @@ public:
 
   void SetWebIDLCallerPrincipal(nsIPrincipal *aPrincipal) {
     mWebIDLCallerPrincipal = aPrincipal;
   }
 
 private:
   JSAutoCompartment mAc;
   dom::ScriptSettingsStack& mStack;
-  nsCOMPtr<nsIPrincipal> mWebIDLCallerPrincipal;
+  // It's safe to make this a weak pointer, since it's the subject principal
+  // when we go on the stack, so can't go away until after we're gone.  In
+  // particular, this is only used from the CallSetup constructor, and only in
+  // the aIsJSImplementedWebIDL case.  And in that case, the subject principal
+  // is the principal of the callee function that is part of the CallArgs just a
+  // bit up the stack, and which will outlive us.  So we know the principal
+  // can't go away until then either.
+  nsIPrincipal* mWebIDLCallerPrincipal;
   friend nsIPrincipal* GetWebIDLCallerPrincipal();
 };
 
 /*
  * A class that can be used to force a particular incumbent script on the stack.
  */
 class AutoIncumbentScript : protected ScriptSettingsStackEntry {
 public:
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2610,23 +2610,16 @@ OldBindingConstructorEnabled(const nsGlo
       expose = nsContentUtils::IsSystemPrincipal(aWin->GetPrincipal());
     }
 
     if (!expose) {
       return false;
     }
   }
 
-  // Don't expose CSSSupportsRule unless @supports processing is enabled.
-  if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSSupportsRule_id) {
-    if (!CSSSupportsRule::PrefEnabled()) {
-      return false;
-    }
-  }
-
   // Don't expose CSSFontFeatureValuesRule unless the pref is enabled
   if (aStruct->mDOMClassInfoID == eDOMClassInfo_CSSFontFeatureValuesRule_id) {
     return nsCSSFontFeatureValuesRule::PrefEnabled();
   }
 
   return true;
 }
 
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3020,17 +3020,17 @@ NS_IMETHODIMP
 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx,
                             int64_t* aResult)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   if (!aFile.isPrimitive()) {
     JSObject* obj = aFile.toObjectOrNull();
 
-    FileHandle* fileHandle;
+    FileHandle* fileHandle = nullptr;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(FileHandle, obj, fileHandle))) {
       *aResult = fileHandle->GetFileId();
       return NS_OK;
     }
 
     nsISupports* nativeObj =
       nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, obj);
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1557,17 +1557,17 @@ class CGClassConstructor(CGAbstractStati
               // Adding more relocations
               return ThrowConstructorWithoutNew(cx, "${ctorName}");
             }
             """,
             chromeOnlyCheck=chromeOnlyCheck,
             ctorName=ctorName)
 
         name = self._ctor.identifier.name
-        nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
+        nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
         callGenerator = CGMethodCall(nativeName, True, self.descriptor,
                                      self._ctor, isConstructor=True,
                                      constructorName=ctorName)
         return preamble + callGenerator.define()
 
 
 # Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod.
 class CGConstructNavigatorObjectHelper(CGAbstractStaticMethod):
@@ -6942,17 +6942,17 @@ class CGSpecializedMethod(CGAbstractStat
         nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
                                                         self.method)
         return CGMethodCall(nativeName, self.method.isStatic(), self.descriptor,
                             self.method).define()
 
     @staticmethod
     def makeNativeName(descriptor, method):
         name = method.identifier.name
-        return MakeNativeName(descriptor.binaryNames.get(name, name))
+        return MakeNativeName(descriptor.binaryNameFor(name))
 
 
 class CGMethodPromiseWrapper(CGAbstractStaticMethod):
     """
     A class for generating a wrapper around another method that will
     convert exceptions to promises.
     """
     def __init__(self, descriptor, methodToWrap):
@@ -7031,17 +7031,17 @@ class CGLegacyCallHook(CGAbstractBinding
 
     def define(self):
         if not self._legacycaller:
             return ""
         return CGAbstractBindingMethod.define(self)
 
     def generate_code(self):
         name = self._legacycaller.identifier.name
-        nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
+        nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
         return CGMethodCall(nativeName, False, self.descriptor,
                             self._legacycaller)
 
 
 class CGNewResolveHook(CGAbstractBindingMethod):
     """
     NewResolve hook for objects with custom hooks.
     """
@@ -7282,17 +7282,17 @@ class CGSpecializedGetter(CGAbstractStat
 
         return (prefix +
                 CGGetterCall(self.attr.type, nativeName,
                              self.descriptor, self.attr).define())
 
     @staticmethod
     def makeNativeName(descriptor, attr):
         name = attr.identifier.name
-        nativeName = MakeNativeName(descriptor.binaryNames.get(name, name))
+        nativeName = MakeNativeName(descriptor.binaryNameFor(name))
         # resultOutParam does not depend on whether resultAlreadyAddRefed is set
         _, resultOutParam, _, _ = getRetvalDeclarationForType(attr.type,
                                                               descriptor,
                                                               False)
         infallible = ('infallible' in
                       descriptor.getExtendedAttributes(attr, getter=True))
         if resultOutParam or attr.type.nullable() or not infallible:
             nativeName = "Get" + nativeName
@@ -7385,17 +7385,17 @@ class CGSpecializedSetter(CGAbstractStat
         nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
                                                         self.attr)
         return CGSetterCall(self.attr.type, nativeName, self.descriptor,
                             self.attr).define()
 
     @staticmethod
     def makeNativeName(descriptor, attr):
         name = attr.identifier.name
-        return "Set" + MakeNativeName(descriptor.binaryNames.get(name, name))
+        return "Set" + MakeNativeName(descriptor.binaryNameFor(name))
 
 
 class CGStaticSetter(CGAbstractStaticBindingMethod):
     """
     A class for generating the C++ code for an IDL static attribute setter.
     """
     def __init__(self, descriptor, attr):
         self.attr = attr
@@ -9090,17 +9090,17 @@ class CGProxySpecialOperation(CGPerSigna
     (don't use this directly, use the derived classes below).
 
     If checkFound is False, will just assert that the prop is found instead of
     checking that it is before wrapping the value.
     """
     def __init__(self, descriptor, operation, checkFound=True, argumentMutableValue=None):
         self.checkFound = checkFound
 
-        nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
+        nativeName = MakeNativeName(descriptor.binaryNameFor(operation))
         operation = descriptor.operations[operation]
         assert len(operation.signatures()) == 1
         signature = operation.signatures()[0]
 
         returnType, arguments = signature
 
         # We pass len(arguments) as the final argument so that the
         # CGPerSignatureCall won't do any argument conversion of its own.
@@ -12303,22 +12303,22 @@ def genConstructorBody(descriptor, initC
         contractId=descriptor.interface.getJSImplementation(),
         implClass=descriptor.name,
         initCall=initCall)
 
 
 # We're always fallible
 def callbackGetterName(attr, descriptor):
     return "Get" + MakeNativeName(
-        descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name))
+        descriptor.binaryNameFor(attr.identifier.name))
 
 
 def callbackSetterName(attr, descriptor):
     return "Set" + MakeNativeName(
-        descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name))
+        descriptor.binaryNameFor(attr.identifier.name))
 
 
 class CGJSImplGetter(CGJSImplMember):
     """
     Class for generating code for the getters of attributes for a JS-implemented
     WebIDL interface.
     """
     def __init__(self, descriptor, attr):
@@ -13047,17 +13047,17 @@ class CallCallback(CallbackMethod):
 
 
 class CallbackOperationBase(CallbackMethod):
     """
     Common class for implementing various callback operations.
     """
     def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False):
         self.singleOperation = singleOperation
-        self.methodName = descriptor.binaryNames.get(jsName, jsName)
+        self.methodName = descriptor.binaryNameFor(jsName)
         CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException)
 
     def getThisDecl(self):
         if not self.singleOperation:
             return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n"
         # This relies on getCallableDecl declaring a boolean
         # isCallable in the case when we're a single-operation
         # interface.
@@ -13102,17 +13102,17 @@ class CallbackOperation(CallbackOperatio
     Codegen actual WebIDL operations on callback interfaces.
     """
     def __init__(self, method, signature, descriptor):
         self.ensureASCIIName(method)
         self.method = method
         jsName = method.identifier.name
         CallbackOperationBase.__init__(self, signature,
                                        jsName,
-                                       MakeNativeName(descriptor.binaryNames.get(jsName, jsName)),
+                                       MakeNativeName(descriptor.binaryNameFor(jsName)),
                                        descriptor, descriptor.interface.isSingleOperationInterface(),
                                        rethrowContentException=descriptor.interface.isJSImplemented())
 
     def getPrettyName(self):
         return "%s.%s" % (self.descriptorProvider.interface.identifier.name,
                           self.method.identifier.name)
 
 
@@ -13146,18 +13146,17 @@ class CallbackGetter(CallbackAccessor):
         return fill(
             """
             JS::Rooted<JSObject *> callback(cx, mCallback);
             if (!JS_GetProperty(cx, callback, "${attrName}", &rval)) {
               aRv.Throw(NS_ERROR_UNEXPECTED);
               return${errorReturn};
             }
             """,
-            attrName=self.descriptorProvider.binaryNames.get(self.attrName,
-                                                             self.attrName),
+            attrName=self.descriptorProvider.binaryNameFor(self.attrName),
             errorReturn=self.getDefaultRetval())
 
 
 class CallbackSetter(CallbackAccessor):
     def __init__(self, attr, descriptor):
         CallbackAccessor.__init__(self, attr,
                                   (BuiltinTypes[IDLBuiltinType.Types.void],
                                    [FakeArgument(attr.type, attr)]),
@@ -13172,18 +13171,17 @@ class CallbackSetter(CallbackAccessor):
         return fill(
             """
             MOZ_ASSERT(argv.length() == 1);
             if (!JS_SetProperty(cx, CallbackPreserveColor(), "${attrName}", argv[0])) {
               aRv.Throw(NS_ERROR_UNEXPECTED);
               return${errorReturn};
             }
             """,
-            attrName=self.descriptorProvider.binaryNames.get(self.attrName,
-                                                             self.attrName),
+            attrName=self.descriptorProvider.binaryNameFor(self.attrName),
             errorReturn=self.getDefaultRetval())
 
     def getArgcDecl(self):
         return None
 
 
 class CGJSImplInitOperation(CallbackOperationBase):
     """
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -409,22 +409,19 @@ class Descriptor(DescriptorProvider):
                     add('all', [config], attribute)
 
         if self.interface.isJSImplemented():
             addExtendedAttribute('implicitJSContext', ['constructor'])
         else:
             for attribute in ['implicitJSContext', 'resultNotAddRefed']:
                 addExtendedAttribute(attribute, desc.get(attribute, {}))
 
-        self.binaryNames = desc.get('binaryNames', {})
-        if '__legacycaller' not in self.binaryNames:
-            self.binaryNames["__legacycaller"] = "LegacyCall"
-        if '__stringifier' not in self.binaryNames:
-            self.binaryNames["__stringifier"] = "Stringify"
-
+        self._binaryNames = desc.get('binaryNames', {})
+        self._binaryNames.setdefault('__legacycaller', 'LegacyCall')
+        self._binaryNames.setdefault('__stringifier', 'Stringify')
 
         if not self.interface.isExternal():
             self.permissions = dict()
 
             # Adds a permission list to this descriptor and returns the index to use.
             def addPermissions(ifaceOrMember):
                 checkPermissions = ifaceOrMember.getExtendedAttribute("CheckPermissions")
                 if checkPermissions is None:
@@ -452,16 +449,19 @@ class Descriptor(DescriptorProvider):
         self.prototypeChain = []
         parent = interface
         while parent:
             self.prototypeChain.insert(0, parent.identifier.name)
             parent = parent.parent
         config.maxProtoChainLength = max(config.maxProtoChainLength,
                                          len(self.prototypeChain))
 
+    def binaryNameFor(self, name):
+        return self._binaryNames.get(name, name)
+
     def hasInterfaceOrInterfacePrototypeObject(self):
 
         # Forward-declared interfaces don't need either interface object or
         # interface prototype object as they're going to use QI (on main thread)
         # or be passed as a JSObject (on worker threads).
         if self.interface.isExternal():
             return False
 
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -21,17 +21,17 @@ namespace dom {
 
 /*
  * Class that just handles the JSObject storage and tracing for typed arrays
  */
 struct TypedArrayObjectStorage : AllTypedArraysBase {
 protected:
   JSObject* mObj;
 
-  TypedArrayObjectStorage(JSObject *obj) : mObj(obj)
+  TypedArrayObjectStorage() : mObj(nullptr)
   {
   }
 
   explicit TypedArrayObjectStorage(TypedArrayObjectStorage&& aOther)
     : mObj(aOther.mObj)
   {
     aOther.mObj = nullptr;
   }
@@ -55,28 +55,18 @@ private:
  * or array buffer object.
  */
 template<typename T,
          JSObject* UnwrapArray(JSObject*),
          void GetLengthAndData(JSObject*, uint32_t*, T**)>
 struct TypedArray_base : public TypedArrayObjectStorage {
   typedef T element_type;
 
-  TypedArray_base(JSObject* obj)
-    : TypedArrayObjectStorage(obj),
-      mData(nullptr),
-      mLength(0),
-      mComputed(false)
-  {
-    MOZ_ASSERT(obj != nullptr);
-  }
-
   TypedArray_base()
-    : TypedArrayObjectStorage(nullptr),
-      mData(nullptr),
+    : mData(nullptr),
       mLength(0),
       mComputed(false)
   {
   }
 
   explicit TypedArray_base(TypedArray_base&& aOther)
     : TypedArrayObjectStorage(Move(aOther)),
       mData(aOther.mData),
@@ -92,17 +82,17 @@ private:
   mutable T* mData;
   mutable uint32_t mLength;
   mutable bool mComputed;
 
 public:
   inline bool Init(JSObject* obj)
   {
     MOZ_ASSERT(!inited());
-    DoInit(obj);
+    mObj = UnwrapArray(obj);
     return inited();
   }
 
   inline bool inited() const {
     return !!mObj;
   }
 
   inline T *Data() const {
@@ -130,21 +120,16 @@ public:
   {
     MOZ_ASSERT(inited());
     MOZ_ASSERT(!mComputed);
     GetLengthAndData(mObj, &mLength, &mData);
     mComputed = true;
   }
 
 protected:
-  inline void DoInit(JSObject* obj)
-  {
-    mObj = UnwrapArray(obj);
-  }
-
   inline void ComputeData() const {
     MOZ_ASSERT(inited());
     if (!mComputed) {
       GetLengthAndData(mObj, &mLength, &mData);
       mComputed = true;
     }
   }
 
@@ -158,20 +143,16 @@ template<typename T,
          T* GetData(JSObject*),
          void GetLengthAndData(JSObject*, uint32_t*, T**),
          JSObject* CreateNew(JSContext*, uint32_t)>
 struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> {
 private:
   typedef TypedArray_base<T, UnwrapArray, GetLengthAndData> Base;
 
 public:
-  TypedArray(JSObject* obj)
-    : Base(obj)
-  {}
-
   TypedArray()
     : Base()
   {}
 
   explicit TypedArray(TypedArray&& aOther)
     : Base(Move(aOther))
   {
   }
--- a/dom/bluetooth2/BluetoothAdapter.cpp
+++ b/dom/bluetooth2/BluetoothAdapter.cpp
@@ -19,16 +19,19 @@
 #include "mozilla/LazyIdleThread.h"
 
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
 
+#define ERR_INVALID_ADAPTER_STATE "InvalidAdapterStateError"
+#define ERR_CHANGE_ADAPTER_STATE  "ChangeAdapterStateError"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothAdapter,
@@ -116,16 +119,17 @@ public:
   }
 
   void
   ReleaseMembers()
   {
     BluetoothReplyRunnable::ReleaseMembers();
     mAdapterPtr = nullptr;
   }
+
 private:
   nsRefPtr<BluetoothAdapter> mAdapterPtr;
 };
 
 class GetScoConnectionStatusTask : public BluetoothReplyRunnable
 {
 public:
   GetScoConnectionStatusTask(nsIDOMDOMRequest* aReq) :
@@ -151,30 +155,63 @@ public:
 
   void
   ReleaseMembers()
   {
     BluetoothReplyRunnable::ReleaseMembers();
   }
 };
 
+class EnableDisableAdapterTask : public BluetoothReplyRunnable
+{
+public:
+  EnableDisableAdapterTask(Promise* aPromise)
+    : BluetoothReplyRunnable(nullptr)
+    , mPromise(aPromise)
+  { }
+
+  bool
+  ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
+  {
+    /*
+     * It is supposed to be Promise<void> according to BluetoothAdapter.webidl,
+     * but we have to pass "true" since it is mandatory to pass an
+     * argument while calling MaybeResolve.
+     */
+    mPromise->MaybeResolve(true);
+    aValue.setUndefined();
+    return true;
+  }
+
+  void
+  ReleaseMembers()
+  {
+    BluetoothReplyRunnable::ReleaseMembers();
+    mPromise = nullptr;
+  }
+
+private:
+  nsRefPtr<Promise> mPromise;
+};
+
 static int kCreatePairedDeviceTimeout = 50000; // unit: msec
 
 BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
                                    const BluetoothValue& aValue)
   : DOMEventTargetHelper(aWindow)
   , BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
   , mJsUuids(nullptr)
   , mJsDeviceAddresses(nullptr)
+  // TODO: Change to Disabled after Bug 1006309 landed
+  , mState(BluetoothAdapterState::Enabled)
   , mDiscoverable(false)
   , mDiscovering(false)
   , mPairable(false)
   , mPowered(false)
   , mIsRooted(false)
-  , mState(BluetoothAdapterState::Disabled)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(IsDOMBinding());
 
   const InfallibleTArray<BluetoothNamedValue>& values =
     aValue.get_ArrayOfBluetoothNamedValue();
   for (uint32_t i = 0; i < values.Length(); ++i) {
     SetPropertyByValue(values[i]);
@@ -226,17 +263,21 @@ BluetoothAdapter::Root()
   mIsRooted = true;
 }
 
 void
 BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
 {
   const nsString& name = aValue.name();
   const BluetoothValue& value = aValue.value();
-  if (name.EqualsLiteral("Name")) {
+  if (name.EqualsLiteral("State")) {
+    bool isEnabled = value.get_bool();
+    mState = isEnabled ? BluetoothAdapterState::Enabled
+                       : BluetoothAdapterState::Disabled;
+  } else if (name.EqualsLiteral("Name")) {
     mName = value.get_nsString();
   } else if (name.EqualsLiteral("Address")) {
     mAddress = value.get_nsString();
   } else if (name.EqualsLiteral("Path")) {
     mPath = value.get_nsString();
   } else if (name.EqualsLiteral("Discoverable")) {
     mDiscoverable = value.get_bool();
   } else if (name.EqualsLiteral("Discovering")) {
@@ -664,29 +705,65 @@ BluetoothAdapter::SetPairingConfirmation
     BT_WARNING("SetPairingConfirmation failed!");
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return request.forget();
 }
 
-/*
- * TODO: Implement Enable/Disable functions
- */
+already_AddRefed<Promise>
+BluetoothAdapter::EnableDisable(bool aEnable)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  NS_ENSURE_TRUE(global, nullptr);
+
+  nsRefPtr<Promise> promise = new Promise(global);
+
+  // Make sure BluetoothService is available before modifying adapter state
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    promise->MaybeReject(ERR_CHANGE_ADAPTER_STATE);
+    return promise.forget();
+  }
+
+  if (aEnable) {
+    if (mState != BluetoothAdapterState::Disabled) {
+      promise->MaybeReject(ERR_INVALID_ADAPTER_STATE);
+      return promise.forget();
+    }
+    mState = BluetoothAdapterState::Enabling;
+  } else {
+    if (mState != BluetoothAdapterState::Enabled) {
+      promise->MaybeReject(ERR_INVALID_ADAPTER_STATE);
+      return promise.forget();
+    }
+    mState = BluetoothAdapterState::Disabling;
+  }
+
+  // TODO: Fire attr changed event for this state change
+  nsRefPtr<BluetoothReplyRunnable> result = new EnableDisableAdapterTask(promise);
+
+  if(NS_FAILED(bs->EnableDisable(aEnable, result))) {
+    promise->MaybeReject(ERR_CHANGE_ADAPTER_STATE);
+  }
+
+  return promise.forget();
+}
+
 already_AddRefed<Promise>
 BluetoothAdapter::Enable()
 {
-  return nullptr;
+  return EnableDisable(true);
 }
 
 already_AddRefed<Promise>
 BluetoothAdapter::Disable()
 {
-  return nullptr;
+  return EnableDisable(false);
 }
 
 already_AddRefed<DOMRequest>
 BluetoothAdapter::Connect(BluetoothDevice& aDevice,
                           const Optional<short unsigned int>& aServiceUuid,
                           ErrorResult& aRv)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetOwner();
--- a/dom/bluetooth2/BluetoothAdapter.h
+++ b/dom/bluetooth2/BluetoothAdapter.h
@@ -117,20 +117,19 @@ public:
                ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     SetPairingConfirmation(const nsAString& aDeviceAddress, bool aConfirmation,
                            ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
                      ErrorResult& aRv);
 
-  already_AddRefed<Promise>
-    Enable();
-  already_AddRefed<Promise>
-    Disable();
+  already_AddRefed<Promise> EnableDisable(bool aEnable);
+  already_AddRefed<Promise> Enable();
+  already_AddRefed<Promise> Disable();
 
   already_AddRefed<DOMRequest>
     Connect(BluetoothDevice& aDevice,
             const Optional<short unsigned int>& aServiceUuid, ErrorResult& aRv);
   already_AddRefed<DOMRequest>
     Disconnect(BluetoothDevice& aDevice,
                const Optional<short unsigned int>& aServiceUuid,
                ErrorResult& aRv);
--- a/dom/bluetooth2/BluetoothService.cpp
+++ b/dom/bluetooth2/BluetoothService.cpp
@@ -158,24 +158,18 @@ BluetoothService::ToggleBtAck::Run()
     return NS_OK;
   }
 
   // Update mEnabled of BluetoothService object since
   // StartInternal/StopInternal have been already done.
   sBluetoothService->SetEnabled(mEnabled);
   sToggleInProgress = false;
 
-  nsAutoString signalName;
-  signalName = mEnabled ? NS_LITERAL_STRING("Enabled")
-                        : NS_LITERAL_STRING("Disabled");
-  BluetoothSignal signal(signalName, NS_LITERAL_STRING(KEY_MANAGER), true);
-  sBluetoothService->DistributeSignal(signal);
-
-  // Event 'AdapterAdded' has to be fired after firing 'Enabled'
   sBluetoothService->TryFiringAdapterAdded();
+  sBluetoothService->FireAdapterStateChanged(mEnabled);
 
   return NS_OK;
 }
 
 class BluetoothService::StartupTask : public nsISettingsServiceCallback
 {
 public:
   NS_DECL_ISUPPORTS
@@ -215,29 +209,16 @@ BluetoothService::IsToggling() const
   return sToggleInProgress;
 }
 
 BluetoothService::~BluetoothService()
 {
   Cleanup();
 }
 
-PLDHashOperator
-RemoveObserversExceptBluetoothManager
-  (const nsAString& key,
-   nsAutoPtr<BluetoothSignalObserverList>& value,
-   void* arg)
-{
-  if (!key.EqualsLiteral(KEY_MANAGER)) {
-    return PL_DHASH_REMOVE;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
 // static
 BluetoothService*
 BluetoothService::Create()
 {
 #if defined(MOZ_B2G_BT)
   if (!IsMainProcess()) {
     return BluetoothServiceChildProcess::Create();
   }
@@ -379,17 +360,18 @@ BluetoothService::DistributeSignal(const
                NS_ConvertUTF16toUTF8(aSignal.path()).get());
     return;
   }
   MOZ_ASSERT(ol->Length());
   ol->Broadcast(aSignal);
 }
 
 nsresult
-BluetoothService::StartBluetooth(bool aIsStartup)
+BluetoothService::StartBluetooth(bool aIsStartup,
+                                 BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (sInShutdown) {
     // Don't try to start if we're already shutting down.
     MOZ_ASSERT(false, "Start called while in shutdown!");
     return NS_ERROR_FAILURE;
   }
@@ -400,32 +382,33 @@ BluetoothService::StartBluetooth(bool aI
    * send ToggleBtAck task. One special case happens at startup stage. At
    * startup, the initialization of BluetoothService still has to be done
    * even if Bluetooth is already enabled.
    *
    * Please see bug 892392 for more information.
    */
   if (aIsStartup || !sBluetoothService->IsEnabled()) {
     // Switch Bluetooth on
-    if (NS_FAILED(sBluetoothService->StartInternal())) {
+    if (NS_FAILED(sBluetoothService->StartInternal(aRunnable))) {
       BT_WARNING("Bluetooth service failed to start!");
     }
   } else {
     BT_WARNING("Bluetooth has already been enabled before.");
     nsRefPtr<nsRunnable> runnable = new BluetoothService::ToggleBtAck(true);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       BT_WARNING("Failed to dispatch to main thread!");
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-BluetoothService::StopBluetooth(bool aIsStartup)
+BluetoothService::StopBluetooth(bool aIsStartup,
+                                BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothProfileManagerBase* profile;
   profile = BluetoothHfpManager::Get();
   NS_ENSURE_TRUE(profile, NS_ERROR_FAILURE);
   if (profile->IsConnected()) {
     profile->Disconnect(nullptr);
@@ -461,65 +444,56 @@ BluetoothService::StopBluetooth(bool aIs
    * send ToggleBtAck task. One special case happens at startup stage. At
    * startup, the initialization of BluetoothService still has to be done
    * even if Bluetooth is disabled.
    *
    * Please see bug 892392 for more information.
    */
   if (aIsStartup || sBluetoothService->IsEnabled()) {
     // Switch Bluetooth off
-    if (NS_FAILED(sBluetoothService->StopInternal())) {
+    if (NS_FAILED(sBluetoothService->StopInternal(aRunnable))) {
       BT_WARNING("Bluetooth service failed to stop!");
     }
   } else {
     BT_WARNING("Bluetooth has already been enabled/disabled before.");
     nsRefPtr<nsRunnable> runnable = new BluetoothService::ToggleBtAck(false);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       BT_WARNING("Failed to dispatch to main thread!");
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-BluetoothService::StartStopBluetooth(bool aStart, bool aIsStartup)
+BluetoothService::StartStopBluetooth(bool aStart,
+                                     bool aIsStartup,
+                                     BluetoothReplyRunnable* aRunnable)
 {
   nsresult rv;
   if (aStart) {
-    rv = StartBluetooth(aIsStartup);
+    rv = StartBluetooth(aIsStartup, aRunnable);
   } else {
-    rv = StopBluetooth(aIsStartup);
+    rv = StopBluetooth(aIsStartup, aRunnable);
   }
   return rv;
 }
 
 void
 BluetoothService::SetEnabled(bool aEnabled)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   AutoInfallibleTArray<BluetoothParent*, 10> childActors;
   GetAllBluetoothActors(childActors);
 
   for (uint32_t index = 0; index < childActors.Length(); index++) {
     unused << childActors[index]->SendEnabled(aEnabled);
   }
 
-  if (!aEnabled) {
-    /**
-     * Remove all handlers except BluetoothManager when turning off bluetooth
-     * since it is possible that the event 'onAdapterAdded' would be fired after
-     * BluetoothManagers of child process are registered. Please see Bug 827759
-     * for more details.
-     */
-    mBluetoothSignalObserverTable.Enumerate(
-      RemoveObserversExceptBluetoothManager, nullptr);
-  }
-
   /**
    * mEnabled: real status of bluetooth
    * aEnabled: expected status of bluetooth
    */
   if (mEnabled == aEnabled) {
     BT_WARNING("Bluetooth has already been enabled/disabled before "
                "or the toggling is failed.");
   }
@@ -548,17 +522,17 @@ BluetoothService::HandleStartup()
   sToggleInProgress = true;
   return NS_OK;
 }
 
 nsresult
 BluetoothService::HandleStartupSettingsCheck(bool aEnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return StartStopBluetooth(aEnable, true);
+  return StartStopBluetooth(aEnable, true, nullptr);
 }
 
 nsresult
 BluetoothService::HandleSettingsChanged(const nsAString& aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // The string that we're interested in will be a JSON string that looks like:
@@ -605,47 +579,16 @@ BluetoothService::HandleSettingsChanged(
     }
 
     if (!value.isBoolean()) {
       MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.debugging.enabled'!");
       return NS_ERROR_UNEXPECTED;
     }
 
     SWITCH_BT_DEBUG(value.toBoolean());
-
-    return NS_OK;
-  }
-
-  // Second, check if the string is BLUETOOTH_ENABLED_SETTING
-  if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING, &match)) {
-    MOZ_ASSERT(!JS_IsExceptionPending(cx));
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  if (match) {
-    JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, obj, "value", &value)) {
-      MOZ_ASSERT(!JS_IsExceptionPending(cx));
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    if (!value.isBoolean()) {
-      MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
-      return NS_ERROR_UNEXPECTED;
-    }
-
-    if (sToggleInProgress || value.toBoolean() == IsEnabled()) {
-      // Nothing to do here.
-      return NS_OK;
-    }
-
-    sToggleInProgress = true;
-
-    nsresult rv = StartStopBluetooth(value.toBoolean(), false);
-    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
 BluetoothService::HandleShutdown()
 {
@@ -699,17 +642,17 @@ BluetoothService::HandleShutdown()
         }
       }
       else {
         MOZ_ASSERT(false, "Failed to initialize shutdown timer!");
       }
     }
   }
 
-  if (IsEnabled() && NS_FAILED(StopBluetooth(false))) {
+  if (IsEnabled() && NS_FAILED(StopBluetooth(false, nullptr))) {
     MOZ_ASSERT(false, "Failed to deliver stop message!");
   }
 
   return NS_OK;
 }
 
 // static
 BluetoothService*
@@ -780,16 +723,48 @@ BluetoothService::TryFiringAdapterAdded(
 void
 BluetoothService::AdapterAddedReceived()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mAdapterAddedReceived = true;
 }
 
+/**
+ * Enable/Disable the local adapter.
+ *
+ * There is only one adapter on the mobile in current use cases.
+ * In addition, bluedroid couldn't enable/disable a single adapter.
+ * So currently we will turn on/off BT to enable/disable the adapter.
+ *
+ * TODO: To support enable/disable single adapter in the future,
+ *       we will need to implement EnableDisableInternal for different stacks.
+ */
+nsresult
+BluetoothService::EnableDisable(bool aEnable,
+                                BluetoothReplyRunnable* aRunnable)
+{
+  sToggleInProgress = true;
+  return StartStopBluetooth(aEnable, false, aRunnable);
+}
+
+void
+BluetoothService::FireAdapterStateChanged(bool aEnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InfallibleTArray<BluetoothNamedValue> props;
+  BT_APPEND_NAMED_VALUE(props, "State", aEnable);
+  BluetoothValue value(props);
+
+  BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
+                         NS_LITERAL_STRING(KEY_ADAPTER), value);
+  DistributeSignal(signal);
+}
+
 void
 BluetoothService::Notify(const BluetoothSignal& aData)
 {
   nsString type = NS_LITERAL_STRING("bluetooth-pairing-request");
 
   AutoSafeJSContext cx;
   JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(),
                                              JS::NullPtr()));
--- a/dom/bluetooth2/BluetoothService.h
+++ b/dom/bluetooth2/BluetoothService.h
@@ -310,56 +310,62 @@ public:
 
   /**
    * Below 2 function/variable are used for ensuring event 'AdapterAdded' will
    * be fired after event 'Enabled'.
    */
   void TryFiringAdapterAdded();
   void AdapterAddedReceived();
 
+  void FireAdapterStateChanged(bool aEnable);
+  nsresult EnableDisable(bool aEnable,
+                         BluetoothReplyRunnable* aRunnable);
+
+  /**
+   * Platform specific startup functions go here. Usually deals with member
+   * variables, so not static. Guaranteed to be called outside of main thread.
+   *
+   * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult
+  StartInternal(BluetoothReplyRunnable* aRunnable) = 0;
+
+  /**
+   * Platform specific startup functions go here. Usually deals with member
+   * variables, so not static. Guaranteed to be called outside of main thread.
+   *
+   * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult
+  StopInternal(BluetoothReplyRunnable* aRunnable) = 0;
+
 protected:
   BluetoothService() : mEnabled(false)
                      , mAdapterAddedReceived(false)
   {
   }
 
   virtual ~BluetoothService();
 
   bool
   Init();
 
   void
   Cleanup();
 
   nsresult
-  StartBluetooth(bool aIsStartup);
-
-  nsresult
-  StopBluetooth(bool aIsStartup);
+  StartBluetooth(bool aIsStartup, BluetoothReplyRunnable* aRunnable);
 
   nsresult
-  StartStopBluetooth(bool aStart, bool aIsStartup);
+  StopBluetooth(bool aIsStartup, BluetoothReplyRunnable* aRunnable);
 
-  /**
-   * Platform specific startup functions go here. Usually deals with member
-   * variables, so not static. Guaranteed to be called outside of main thread.
-   *
-   * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
-   */
-  virtual nsresult
-  StartInternal() = 0;
-
-  /**
-   * Platform specific startup functions go here. Usually deals with member
-   * variables, so not static. Guaranteed to be called outside of main thread.
-   *
-   * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
-   */
-  virtual nsresult
-  StopInternal() = 0;
+  nsresult
+  StartStopBluetooth(bool aStart,
+                     bool aIsStartup,
+                     BluetoothReplyRunnable* aRunnable);
 
   /**
    * Called when XPCOM first creates this service.
    */
   virtual nsresult
   HandleStartup();
 
   /**
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp
@@ -28,44 +28,57 @@
 #include "BluetoothUtils.h"
 #include "BluetoothUuid.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/ipc/UnixSocket.h"
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 
+#define ENSURE_BLUETOOTH_IS_READY(runnable, result)                    \
+  do {                                                                 \
+    if (!sBtInterface || !IsEnabled()) {                               \
+      NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth is not ready");     \
+      DispatchBluetoothReply(runnable, BluetoothValue(), errorStr);    \
+      return result;                                                   \
+    }                                                                  \
+  } while(0)
+
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
-/**
- *  Static variables
- */
-static bluetooth_device_t* sBtDevice;
-static const bt_interface_t* sBtInterface;
-static bool sAdapterDiscoverable = false;
-static bool sIsBtEnabled = false;
+// TODO: Non thread-safe static variables
 static nsString sAdapterBdAddress;
 static nsString sAdapterBdName;
-static uint32_t sAdapterDiscoverableTimeout;
 static InfallibleTArray<nsString> sAdapterBondedAddressArray;
-static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
+static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray;
+
+// Static variables below should only be used on *main thread*
+static const bt_interface_t* sBtInterface;
 static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
+static nsTArray<int> sRequestedDeviceCountArray;
+static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
+static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
+static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
-static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
-static nsTArray<int> sRequestedDeviceCountArray;
+
+// Static variables below should only be used on *callback thread*
+
+
+// Atomic static variables
+static Atomic<bool> sAdapterDiscoverable(false);
+static Atomic<uint32_t> sAdapterDiscoverableTimeout(0);
 
 /**
  *  Classes only used in this file
  */
-class DistributeBluetoothSignalTask : public nsRunnable {
+class DistributeBluetoothSignalTask MOZ_FINAL : public nsRunnable
+{
 public:
   DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
     mSignal(aSignal)
   {
   }
 
   NS_IMETHOD
   Run()
@@ -79,22 +92,19 @@ public:
 
     return NS_OK;
   }
 
 private:
   BluetoothSignal mSignal;
 };
 
-class SetupAfterEnabledTask : public nsRunnable
+class SetupAfterEnabledTask MOZ_FINAL : public nsRunnable
 {
 public:
-  SetupAfterEnabledTask()
-  { }
-
   NS_IMETHOD
   Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     // Bluetooth just enabled, clear profile controllers and runnable arrays.
     sControllerArray.Clear();
     sBondingRunnableArray.Clear();
@@ -130,27 +140,47 @@ public:
     if (!opp || !opp->Listen()) {
       BT_LOGR("Fail to start BluetoothOppManager listening");
     }
 
     return NS_OK;
   }
 };
 
-class CleanupTask : public nsRunnable
+class CleanupTask MOZ_FINAL : public nsRunnable
 {
 public:
-  CleanupTask()
-  { }
-
   NS_IMETHOD
   Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
+    /*
+     * Cleanup static adapter properties and notify adapter to clean them
+     *
+     * TODO: clean up and notify Discovering also
+     */
+    sAdapterBdAddress.Truncate();
+    sAdapterBdName.Truncate();
+    sAdapterDiscoverable = false;
+
+    InfallibleTArray<BluetoothNamedValue> props;
+    BT_APPEND_NAMED_VALUE(props, "Name", sAdapterBdName);
+    BT_APPEND_NAMED_VALUE(props, "Address", sAdapterBdAddress);
+    BT_APPEND_NAMED_VALUE(props, "Discoverable",
+                          BluetoothValue(sAdapterDiscoverable));
+    BluetoothValue value(props);
+    BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
+                           NS_LITERAL_STRING(KEY_ADAPTER), value);
+
+    BluetoothService* bs = BluetoothService::Get();
+    NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+
+    bs->DistributeSignal(signal);
+
     // Cleanup bluetooth interfaces after BT state becomes BT_STATE_OFF.
     BluetoothHfpManager::DeinitHfpInterface();
     BluetoothA2dpManager::DeinitA2dpInterface();
     sBtInterface->cleanup();
 
     return NS_OK;
   }
 };
@@ -265,55 +295,79 @@ PlayStatusStringToControlPlayStatus(cons
     playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK;
   } else if (aPlayStatus.EqualsLiteral("ERROR")) {
     playStatus = ControlPlayStatus::PLAYSTATUS_ERROR;
   }
 
   return playStatus;
 }
 
-static bool
-IsReady()
-{
-  if (!sBtInterface || !sIsBtEnabled) {
-    BT_LOGR("Warning! Bluetooth Service is not ready");
-    return false;
-  }
-  return true;
-}
-
+/**
+ *  Bluedroid HAL callback functions
+ *
+ *  Several callbacks are dispatched to main thread to avoid racing issues.
+ */
 static void
 AdapterStateChangeCallback(bt_state_t aStatus)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
-  BT_LOGR("BT_STATE %d", aStatus);
+  BT_LOGR("BT_STATE: %d", aStatus);
+
+  bool isBtEnabled = (aStatus == BT_STATE_ON);
 
-  sIsBtEnabled = (aStatus == BT_STATE_ON);
-
-  if (!sIsBtEnabled && NS_FAILED(NS_DispatchToMainThread(new CleanupTask()))) {
+  if (!isBtEnabled &&
+      NS_FAILED(NS_DispatchToMainThread(new CleanupTask()))) {
     BT_WARNING("Failed to dispatch to main thread!");
+    return;
   }
 
   nsRefPtr<nsRunnable> runnable =
-    new BluetoothService::ToggleBtAck(sIsBtEnabled);
+    new BluetoothService::ToggleBtAck(isBtEnabled);
   if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
     BT_WARNING("Failed to dispatch to main thread!");
     return;
   }
 
-  if (sIsBtEnabled &&
+  if (isBtEnabled &&
       NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) {
     BT_WARNING("Failed to dispatch to main thread!");
+    return;
+  }
+
+  // Resolve promise if existed
+  if(!sChangeAdapterStateRunnableArray.IsEmpty()) {
+    DispatchBluetoothReply(sChangeAdapterStateRunnableArray[0],
+                           BluetoothValue(true),
+                           EmptyString());
+    sChangeAdapterStateRunnableArray.RemoveElementAt(0);
   }
 }
 
+class AdapterPropertiesCallbackTask MOZ_FINAL : public nsRunnable
+{
+public:
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (!sSetPropertyRunnableArray.IsEmpty()) {
+      DispatchBluetoothReply(sSetPropertyRunnableArray[0],
+                             BluetoothValue(true), EmptyString());
+      sSetPropertyRunnableArray.RemoveElementAt(0);
+    }
+
+    return NS_OK;
+  }
+};
+
 /**
  * AdapterPropertiesCallback will be called after enable() but before
- * AdapterStateChangeCallback sIsBtEnabled get updated. At that moment, both
+ * AdapterStateChangeCallback is called. At that moment, both
  * BluetoothManager/BluetoothAdapter does not register observer yet.
  */
 static void
 AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
                           bt_property_t *aProperties)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
@@ -380,42 +434,85 @@ AdapterPropertiesCallback(bt_status_t aS
   BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
                          NS_LITERAL_STRING(KEY_ADAPTER), value);
   nsRefPtr<DistributeBluetoothSignalTask>
     t = new DistributeBluetoothSignalTask(signal);
   if (NS_FAILED(NS_DispatchToMainThread(t))) {
     BT_WARNING("Failed to dispatch to main thread!");
   }
 
-  // bluedroid BTU task was stored in the task queue, see GKI_send_msg
-  if (!sSetPropertyRunnableArray.IsEmpty()) {
-    DispatchBluetoothReply(sSetPropertyRunnableArray[0], BluetoothValue(true),
-                           EmptyString());
-    sSetPropertyRunnableArray.RemoveElementAt(0);
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(new AdapterPropertiesCallbackTask());
+}
+
+class RemoteDevicePropertiesCallbackTask : public nsRunnable
+{
+  const InfallibleTArray<BluetoothNamedValue> mProps;
+  nsString mRemoteDeviceBdAddress;
+public:
+  RemoteDevicePropertiesCallbackTask(
+    const InfallibleTArray<BluetoothNamedValue>& aProps,
+    const nsAString& aRemoteDeviceBdAddress)
+  : mProps(aProps)
+  , mRemoteDeviceBdAddress(aRemoteDeviceBdAddress)
+  { }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (sRequestedDeviceCountArray.IsEmpty()) {
+      // This is possible because the callback would be called after turning
+      // Bluetooth on.
+      return NS_OK;
+    }
+
+    // Update to registered BluetoothDevice objects
+    BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
+                           mRemoteDeviceBdAddress, mProps);
+    nsRefPtr<DistributeBluetoothSignalTask>
+      t = new DistributeBluetoothSignalTask(signal);
+    if (NS_FAILED(NS_DispatchToMainThread(t))) {
+      BT_WARNING("Failed to dispatch to main thread!");
+      return NS_OK;
+    }
+
+    static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
+
+    // Use address as the index
+    sRemoteDevicesPack.AppendElement(
+      BluetoothNamedValue(mRemoteDeviceBdAddress, mProps));
+
+    if (--sRequestedDeviceCountArray[0] == 0) {
+      if (!sGetDeviceRunnableArray.IsEmpty()) {
+        DispatchBluetoothReply(sGetDeviceRunnableArray[0],
+                               sRemoteDevicesPack, EmptyString());
+        sGetDeviceRunnableArray.RemoveElementAt(0);
+      }
+
+      sRequestedDeviceCountArray.RemoveElementAt(0);
+      sRemoteDevicesPack.Clear();
+    }
+
+    return NS_OK;
   }
-}
+};
 
 /**
  * RemoteDevicePropertiesCallback will be called, as the following conditions:
  * 1. When BT is turning on, bluedroid automatically execute this callback
  * 2. When get_remote_device_properties()
  */
 static void
 RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
                                int aNumProperties, bt_property_t *aProperties)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
-  if (sRequestedDeviceCountArray.IsEmpty()) {
-    MOZ_ASSERT(sGetDeviceRunnableArray.IsEmpty());
-    return;
-  }
-
-  sRequestedDeviceCountArray[0]--;
-
   InfallibleTArray<BluetoothNamedValue> props;
 
   nsString remoteDeviceBdAddress;
   BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
   BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress);
 
   for (int i = 0; i < aNumProperties; ++i) {
     bt_property_t p = aProperties[i];
@@ -430,46 +527,19 @@ RemoteDevicePropertiesCallback(bt_status
       nsString icon;
       ClassToIcon(cod, icon);
       BT_APPEND_NAMED_VALUE(props, "Icon", icon);
     } else {
       BT_LOGD("Other non-handled device properties. Type: %d", p.type);
     }
   }
 
-  // Update to registered BluetoothDevice objects
-  BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
-                         remoteDeviceBdAddress, props);
-  nsRefPtr<DistributeBluetoothSignalTask>
-    t = new DistributeBluetoothSignalTask(signal);
-  if (NS_FAILED(NS_DispatchToMainThread(t))) {
-    BT_WARNING("Failed to dispatch to main thread!");
-  }
-
-  // Use address as the index
-  sRemoteDevicesPack.AppendElement(
-    BluetoothNamedValue(remoteDeviceBdAddress, props));
-
-  if (sRequestedDeviceCountArray[0] == 0) {
-    MOZ_ASSERT(!sGetDeviceRunnableArray.IsEmpty());
-
-    if (sGetDeviceRunnableArray.IsEmpty()) {
-      BT_LOGR("No runnable to return");
-      return;
-    }
-
-    DispatchBluetoothReply(sGetDeviceRunnableArray[0],
-                           sRemoteDevicesPack, EmptyString());
-
-    // After firing it, clean up cache
-    sRemoteDevicesPack.Clear();
-
-    sRequestedDeviceCountArray.RemoveElementAt(0);
-    sGetDeviceRunnableArray.RemoveElementAt(0);
-  }
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(
+    new RemoteDevicePropertiesCallbackTask(props, remoteDeviceBdAddress));
 }
 
 static void
 DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   BluetoothValue propertyValue;
@@ -506,28 +576,43 @@ DeviceFoundCallback(int aNumProperties, 
                          NS_LITERAL_STRING(KEY_ADAPTER), value);
   nsRefPtr<DistributeBluetoothSignalTask>
     t = new DistributeBluetoothSignalTask(signal);
   if (NS_FAILED(NS_DispatchToMainThread(t))) {
     BT_WARNING("Failed to dispatch to main thread!");
   }
 }
 
+class DiscoveryStateChangedCallbackTask MOZ_FINAL : public nsRunnable
+{
+public:
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
+      BluetoothValue values(true);
+      DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
+                             values, EmptyString());
+
+      sChangeDiscoveryRunnableArray.RemoveElementAt(0);
+    }
+
+    return NS_OK;
+  }
+};
+
 static void
 DiscoveryStateChangedCallback(bt_discovery_state_t aState)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
-  if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
-    BluetoothValue values(true);
-    DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
-                           values, EmptyString());
-
-    sChangeDiscoveryRunnableArray.RemoveElementAt(0);
-  }
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(new DiscoveryStateChangedCallbackTask());
 }
 
 static void
 PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress,
                    bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
@@ -576,70 +661,101 @@ SspRequestCallback(bt_bdaddr_t* aRemoteB
                          NS_LITERAL_STRING(KEY_LOCAL_AGENT), value);
   nsRefPtr<DistributeBluetoothSignalTask>
     t = new DistributeBluetoothSignalTask(signal);
   if (NS_FAILED(NS_DispatchToMainThread(t))) {
     BT_WARNING("Failed to dispatch to main thread!");
   }
 }
 
+class BondStateChangedCallbackTask : public nsRunnable
+{
+  nsString mRemoteDeviceBdAddress;
+  bool mBonded;
+public:
+  BondStateChangedCallbackTask(const nsAString& aRemoteDeviceBdAddress,
+                               bool aBonded)
+  : mRemoteDeviceBdAddress(aRemoteDeviceBdAddress)
+  , mBonded(aBonded)
+  { }
+
+  NS_IMETHOD
+  Run()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (mBonded && !sBondingRunnableArray.IsEmpty()) {
+      DispatchBluetoothReply(sBondingRunnableArray[0],
+                             BluetoothValue(true), EmptyString());
+
+      sBondingRunnableArray.RemoveElementAt(0);
+    } else if (!mBonded && !sUnbondingRunnableArray.IsEmpty()) {
+      DispatchBluetoothReply(sUnbondingRunnableArray[0],
+                             BluetoothValue(true), EmptyString());
+
+      sUnbondingRunnableArray.RemoveElementAt(0);
+    }
+
+    // Update bonding status to gaia
+    InfallibleTArray<BluetoothNamedValue> propertiesArray;
+    BT_APPEND_NAMED_VALUE(propertiesArray, "address", mRemoteDeviceBdAddress);
+    BT_APPEND_NAMED_VALUE(propertiesArray, "status", mBonded);
+
+    BluetoothSignal signal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
+                           NS_LITERAL_STRING(KEY_ADAPTER),
+                           BluetoothValue(propertiesArray));
+    NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
+
+    return NS_OK;
+  }
+};
+
 static void
 BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
                          bt_bond_state_t aState)
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
-  nsAutoString remoteAddress;
-  BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
+  if (aState == BT_BOND_STATE_BONDING) {
+    // No need to handle bonding state
+    return;
+  }
 
-  // We don't need to handle bonding state
-  NS_ENSURE_TRUE_VOID(aState != BT_BOND_STATE_BONDING);
-  NS_ENSURE_FALSE_VOID(aState == BT_BOND_STATE_BONDED &&
-                       sAdapterBondedAddressArray.Contains(remoteAddress));
+  nsAutoString remoteBdAddress;
+  BdAddressTypeToString(aRemoteBdAddress, remoteBdAddress);
+
+  if (aState == BT_BOND_STATE_BONDED &&
+      sAdapterBondedAddressArray.Contains(remoteBdAddress)) {
+    // See bug 940271 for more details about this case.
+    return;
+  }
+
   bool bonded;
   if (aState == BT_BOND_STATE_NONE) {
     bonded = false;
-    sAdapterBondedAddressArray.RemoveElement(remoteAddress);
+    sAdapterBondedAddressArray.RemoveElement(remoteBdAddress);
   } else if (aState == BT_BOND_STATE_BONDED) {
     bonded = true;
-    sAdapterBondedAddressArray.AppendElement(remoteAddress);
+    sAdapterBondedAddressArray.AppendElement(remoteBdAddress);
   }
 
   // Update bonded address list to BluetoothAdapter
   InfallibleTArray<BluetoothNamedValue> propertiesChangeArray;
   BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices",
                         sAdapterBondedAddressArray);
 
   BluetoothValue value(propertiesChangeArray);
   BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
                          NS_LITERAL_STRING(KEY_ADAPTER),
                          BluetoothValue(propertiesChangeArray));
   NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
 
-  // Update bonding status to gaia
-  InfallibleTArray<BluetoothNamedValue> propertiesArray;
-  BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
-  BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded);
-
-  BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
-                            NS_LITERAL_STRING(KEY_ADAPTER),
-                            BluetoothValue(propertiesArray));
-  NS_DispatchToMainThread(new DistributeBluetoothSignalTask(newSignal));
-
-  if (bonded && !sBondingRunnableArray.IsEmpty()) {
-    DispatchBluetoothReply(sBondingRunnableArray[0],
-                           BluetoothValue(true), EmptyString());
-
-    sBondingRunnableArray.RemoveElementAt(0);
-  } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
-    DispatchBluetoothReply(sUnbondingRunnableArray[0],
-                           BluetoothValue(true), EmptyString());
-
-    sUnbondingRunnableArray.RemoveElementAt(0);
-  }
+  // Redirect to main thread to avoid racing problem
+  NS_DispatchToMainThread(
+    new BondStateChangedCallbackTask(remoteBdAddress, bonded));
 }
 
 static void
 AclStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
                         bt_acl_state_t aState)
 {
   //FIXME: This will be implemented in the later patchset
 }
@@ -668,25 +784,27 @@ bt_callbacks_t sBluetoothCallbacks =
 /**
  *  Static functions
  */
 static bool
 EnsureBluetoothHalLoad()
 {
   hw_module_t* module;
   hw_device_t* device;
+
   int err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
   if (err != 0) {
     BT_LOGR("Error: %s", strerror(err));
     return false;
   }
   module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
-  sBtDevice = (bluetooth_device_t *)device;
-  NS_ENSURE_TRUE(sBtDevice, false);
-  sBtInterface = sBtDevice->get_bluetooth_interface();
+  bluetooth_device_t* btDevice = (bluetooth_device_t *)device;
+  NS_ENSURE_TRUE(btDevice, false);
+
+  sBtInterface = btDevice->get_bluetooth_interface();
   NS_ENSURE_TRUE(sBtInterface, false);
 
   return true;
 }
 
 static bool
 EnableInternal()
 {
@@ -704,22 +822,26 @@ EnableInternal()
   BluetoothA2dpManager::InitA2dpInterface();
   return sBtInterface->enable();
 }
 
 static nsresult
 StartStopGonkBluetooth(bool aShouldEnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
+
   NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
 
-  if (sIsBtEnabled == aShouldEnable) {
+  BluetoothService* bs = BluetoothService::Get();
+  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+
+  if (bs->IsEnabled() == aShouldEnable) {
     // Keep current enable status
     nsRefPtr<nsRunnable> runnable =
-      new BluetoothService::ToggleBtAck(sIsBtEnabled);
+      new BluetoothService::ToggleBtAck(aShouldEnable);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       BT_WARNING("Failed to dispatch to main thread!");
     }
     return NS_OK;
   }
 
   int ret = aShouldEnable ? EnableInternal() : sBtInterface->disable();
   NS_ENSURE_TRUE(ret == BT_STATUS_SUCCESS, NS_ERROR_FAILURE);
@@ -767,38 +889,48 @@ BluetoothServiceBluedroid::BluetoothServ
   }
 }
 
 BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
 {
 }
 
 nsresult
-BluetoothServiceBluedroid::StartInternal()
+BluetoothServiceBluedroid::StartInternal(BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  // aRunnable will be a nullptr while startup
+  if(aRunnable) {
+    sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
+  }
+
   nsresult ret = StartStopGonkBluetooth(true);
   if (NS_FAILED(ret)) {
     nsRefPtr<nsRunnable> runnable =
       new BluetoothService::ToggleBtAck(false);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       BT_WARNING("Failed to dispatch to main thread!");
     }
     BT_LOGR("Error");
   }
 
   return ret;
 }
 
 nsresult
-BluetoothServiceBluedroid::StopInternal()
+BluetoothServiceBluedroid::StopInternal(BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  // aRunnable will be a nullptr during starup and shutdown
+  if(aRunnable) {
+    sChangeAdapterStateRunnableArray.AppendElement(aRunnable);
+  }
+
   nsresult ret = StartStopGonkBluetooth(false);
   if (NS_FAILED(ret)) {
     nsRefPtr<nsRunnable> runnable =
       new BluetoothService::ToggleBtAck(true);
     if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
       BT_WARNING("Failed to dispatch to main thread!");
     }
     BT_LOGR("Error");
@@ -823,27 +955,32 @@ BluetoothServiceBluedroid::GetAdaptersIn
    *     |__ BluetoothNamedValue =
    *     |     {"Adapter", BluetoothValue = BluetoothNamedValue[]}
    *     ...
    */
   BluetoothValue adaptersProperties = InfallibleTArray<BluetoothNamedValue>();
   uint32_t numAdapters = 1; // Bluedroid supports single adapter only
 
   for (uint32_t i = 0; i < numAdapters; i++) {
+    // Since Atomic<*> is not acceptable for BT_APPEND_NAMED_VALUE(),
+    // create another variable to store data.
+    bool discoverable = sAdapterDiscoverable;
+    uint32_t discoverableTimeout = sAdapterDiscoverableTimeout;
+
     BluetoothValue properties = InfallibleTArray<BluetoothNamedValue>();
 
     // TODO: Revise here based on new BluetoothAdapter interface
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
                           "Address", sAdapterBdAddress);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
                           "Name", sAdapterBdName);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "Discoverable", sAdapterDiscoverable);
+                          "Discoverable", discoverable);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
-                          "DiscoverableTimeout", sAdapterDiscoverableTimeout);
+                          "DiscoverableTimeout", discoverableTimeout);
     BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(),
                           "Devices", sAdapterBondedAddressArray);
 
     BT_APPEND_NAMED_VALUE(adaptersProperties.get_ArrayOfBluetoothNamedValue(),
                           "Adapter", properties);
   }
 
   DispatchBluetoothReply(aRunnable, adaptersProperties, EmptyString());
@@ -851,21 +988,17 @@ BluetoothServiceBluedroid::GetAdaptersIn
 }
 
 nsresult
 BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal(
   uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-    return NS_OK;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   BluetoothProfileManagerBase* profile =
     BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
   if (!profile) {
     InfallibleTArray<BluetoothNamedValue> emptyArr;
     DispatchBluetoothReply(aRunnable, emptyArr,
                            NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
     return NS_OK;
@@ -905,21 +1038,17 @@ BluetoothServiceBluedroid::GetConnectedD
 }
 
 nsresult
 BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal(
   const nsTArray<nsString>& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-    return NS_OK;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   int requestedDeviceCount = aDeviceAddress.Length();
   if (requestedDeviceCount == 0) {
     InfallibleTArray<BluetoothNamedValue> emptyArr;
     DispatchBluetoothReply(aRunnable, BluetoothValue(emptyArr), EmptyString());
     return NS_OK;
   }
 
@@ -942,22 +1071,18 @@ BluetoothServiceBluedroid::GetPairedDevi
 }
 
 nsresult
 BluetoothServiceBluedroid::StartDiscoveryInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
-    return NS_OK;
-  }
   int ret = sBtInterface->start_discovery();
   if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery"));
 
     return NS_OK;
   }
 
   sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
@@ -965,21 +1090,17 @@ BluetoothServiceBluedroid::StartDiscover
 }
 
 nsresult
 BluetoothServiceBluedroid::StopDiscoveryInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-    return NS_OK;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   int ret = sBtInterface->cancel_discovery();
   if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery"));
     return NS_OK;
   }
 
   sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
@@ -989,22 +1110,17 @@ BluetoothServiceBluedroid::StopDiscovery
 
 nsresult
 BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
                                        const BluetoothNamedValue& aValue,
                                        BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-
-    return NS_OK;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   const nsString propName = aValue.name();
   bt_property_t prop;
   bt_scan_mode_t scanMode;
   nsCString str;
 
   // For Bluedroid, it's necessary to check property name for SetProperty
   if (propName.EqualsLiteral("Name")) {
@@ -1067,21 +1183,17 @@ BluetoothServiceBluedroid::UpdateSdpReco
 
 nsresult
 BluetoothServiceBluedroid::CreatePairedDeviceInternal(
   const nsAString& aDeviceAddress, int aTimeout,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-    return NS_OK;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   bt_bdaddr_t remoteAddress;
   StringToBdAddressType(aDeviceAddress, &remoteAddress);
 
   int ret = sBtInterface->create_bond(&remoteAddress);
   if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("CreatedPairedDevice"));
   } else {
@@ -1092,21 +1204,17 @@ BluetoothServiceBluedroid::CreatePairedD
 }
 
 nsresult
 BluetoothServiceBluedroid::RemoveDeviceInternal(
   const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-    return NS_OK;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK);
 
   bt_bdaddr_t remoteAddress;
   StringToBdAddressType(aDeviceAddress, &remoteAddress);
 
   int ret = sBtInterface->remove_bond(&remoteAddress);
   if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret,
                      NS_LITERAL_STRING("RemoveDevice"));
@@ -1119,21 +1227,17 @@ BluetoothServiceBluedroid::RemoveDeviceI
 
 bool
 BluetoothServiceBluedroid::SetPinCodeInternal(
   const nsAString& aDeviceAddress, const nsAString& aPinCode,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-    return false;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, false);
 
   bt_bdaddr_t remoteAddress;
   StringToBdAddressType(aDeviceAddress, &remoteAddress);
 
   int ret = sBtInterface->pin_reply(
       &remoteAddress, true, aPinCode.Length(),
       (bt_pin_code_t*)NS_ConvertUTF16toUTF8(aPinCode).get());
 
@@ -1156,21 +1260,17 @@ BluetoothServiceBluedroid::SetPasskeyInt
 
 bool
 BluetoothServiceBluedroid::SetPairingConfirmationInternal(
   const nsAString& aDeviceAddress, bool aConfirm,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (!IsReady()) {
-    NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
-    DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
-    return false;
-  }
+  ENSURE_BLUETOOTH_IS_READY(aRunnable, false);
 
   bt_bdaddr_t remoteAddress;
   StringToBdAddressType(aDeviceAddress, &remoteAddress);
 
   int ret = sBtInterface->ssp_reply(&remoteAddress, (bt_ssp_variant_t)0,
                                     aConfirm, 0);
   if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret,
--- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h
@@ -17,18 +17,18 @@ BEGIN_BLUETOOTH_NAMESPACE
 class BluetoothServiceBluedroid : public BluetoothService
 {
 public:
   static const bt_interface_t* GetBluetoothInterface();
 
   BluetoothServiceBluedroid();
   ~BluetoothServiceBluedroid();
 
-  virtual nsresult StartInternal();
-  virtual nsresult StopInternal();
+  virtual nsresult StartInternal(BluetoothReplyRunnable* aRunnable);
+  virtual nsresult StopInternal(BluetoothReplyRunnable* aRunnable);
 
   virtual nsresult
   GetAdaptersInternal(BluetoothReplyRunnable* aRunnable);
 
   virtual nsresult
   GetConnectedDevicePropertiesInternal(uint16_t aProfileId,
                                        BluetoothReplyRunnable* aRunnable);
 
--- a/dom/bluetooth2/bluez/BluetoothDBusService.cpp
+++ b/dom/bluetooth2/bluez/BluetoothDBusService.cpp
@@ -2092,18 +2092,20 @@ public:
     Task* task = new StartDBusConnectionTask(connection);
     DispatchToDBusThread(task);
 
     return NS_OK;
   }
 };
 
 nsresult
-BluetoothDBusService::StartInternal()
+BluetoothDBusService::StartInternal(BluetoothReplyRunnable* aRunnable)
 {
+  MOZ_ASSERT(!aRunnable);
+
   nsRefPtr<nsRunnable> runnable = new StartBluetoothRunnable();
   nsresult rv = DispatchToBtThread(runnable);
   if (NS_FAILED(rv)) {
     BT_WARNING("Failed to dispatch to BT thread!");
   }
   return rv;
 }
 
@@ -2220,18 +2222,20 @@ public:
 
     DispatchToDBusThread(new DeleteDBusConnectionTask());
 
     return NS_OK;
   }
 };
 
 nsresult
-BluetoothDBusService::StopInternal()
+BluetoothDBusService::StopInternal(BluetoothReplyRunnable* aRunnable)
 {
+  MOZ_ASSERT(!aRunnable);
+
   nsRefPtr<nsRunnable> runnable = new StopBluetoothRunnable();
   nsresult rv = DispatchToBtThread(runnable);
   if (NS_FAILED(rv)) {
     BT_WARNING("Failed to dispatch to BT thread!");
   }
   return rv;
 }
 
--- a/dom/bluetooth2/bluez/BluetoothDBusService.h
+++ b/dom/bluetooth2/bluez/BluetoothDBusService.h
@@ -42,19 +42,19 @@ public:
     EVENT_UNKNOWN
   };
 
   BluetoothDBusService();
   ~BluetoothDBusService();
 
   bool IsReady();
 
-  virtual nsresult StartInternal() MOZ_OVERRIDE;
+  virtual nsresult StartInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
-  virtual nsresult StopInternal() MOZ_OVERRIDE;
+  virtual nsresult StopInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
   GetAdaptersInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
   GetConnectedDevicePropertiesInternal(uint16_t aServiceUuid,
                                        BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
--- a/dom/bluetooth2/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth2/ipc/BluetoothParent.cpp
@@ -187,16 +187,20 @@ BluetoothParent::RecvPBluetoothRequestCo
 
 #ifdef DEBUG
   actor->mRequestType = aRequest.type();
 #endif
 
   switch (aRequest.type()) {
     case Request::TGetAdaptersRequest:
       return actor->DoRequest(aRequest.get_GetAdaptersRequest());
+    case Request::TStartBluetoothRequest:
+      return actor->DoRequest(aRequest.get_StartBluetoothRequest());
+    case Request::TStopBluetoothRequest:
+      return actor->DoRequest(aRequest.get_StopBluetoothRequest());
     case Request::TSetPropertyRequest:
       return actor->DoRequest(aRequest.get_SetPropertyRequest());
     case Request::TStartDiscoveryRequest:
       return actor->DoRequest(aRequest.get_StartDiscoveryRequest());
     case Request::TStopDiscoveryRequest:
       return actor->DoRequest(aRequest.get_StopDiscoveryRequest());
     case Request::TPairRequest:
       return actor->DoRequest(aRequest.get_PairRequest());
@@ -317,16 +321,40 @@ BluetoothRequestParent::DoRequest(const 
 
   nsresult rv = mService->GetAdaptersInternal(mReplyRunnable.get());
   NS_ENSURE_SUCCESS(rv, false);
 
   return true;
 }
 
 bool
+BluetoothRequestParent::DoRequest(const StartBluetoothRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TStartBluetoothRequest);
+
+  nsresult rv = mService->StartInternal(mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const StopBluetoothRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TStopBluetoothRequest);
+
+  nsresult rv = mService->StopInternal(mReplyRunnable.get());
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return true;
+}
+
+bool
 BluetoothRequestParent::DoRequest(const SetPropertyRequest& aRequest)
 {
   MOZ_ASSERT(mService);
   MOZ_ASSERT(mRequestType == Request::TSetPropertyRequest);
 
   nsresult rv =
     mService->SetProperty(aRequest.type(), aRequest.value(),
                           mReplyRunnable.get());
--- a/dom/bluetooth2/ipc/BluetoothParent.h
+++ b/dom/bluetooth2/ipc/BluetoothParent.h
@@ -124,16 +124,22 @@ protected:
 
   void
   RequestComplete();
 
   bool
   DoRequest(const GetAdaptersRequest& aRequest);
 
   bool
+  DoRequest(const StartBluetoothRequest& aRequest);
+
+  bool
+  DoRequest(const StopBluetoothRequest& aRequest);
+
+  bool
   DoRequest(const SetPropertyRequest& aRequest);
 
   bool
   DoRequest(const GetPropertyRequest& aRequest);
 
   bool
   DoRequest(const StartDiscoveryRequest& aRequest);
 
--- a/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp
@@ -99,16 +99,30 @@ nsresult
 BluetoothServiceChildProcess::GetAdaptersInternal(
                                               BluetoothReplyRunnable* aRunnable)
 {
   SendRequest(aRunnable, GetAdaptersRequest());
   return NS_OK;
 }
 
 nsresult
+BluetoothServiceChildProcess::StartInternal(BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, StartBluetoothRequest());
+  return NS_OK;
+}
+
+nsresult
+BluetoothServiceChildProcess::StopInternal(BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, StopBluetoothRequest());
+  return NS_OK;
+}
+
+nsresult
 BluetoothServiceChildProcess::GetConnectedDevicePropertiesInternal(
                                               uint16_t aServiceUuid,
                                               BluetoothReplyRunnable* aRunnable)
 {
   SendRequest(aRunnable, ConnectedDevicePropertiesRequest(aServiceUuid));
   return NS_OK;
 }
 nsresult
@@ -372,28 +386,16 @@ BluetoothServiceChildProcess::HandleShut
   // If this process is shutting down then we need to disconnect ourselves from
   // the parent.
   if (sBluetoothChild) {
     sBluetoothChild->BeginShutdown();
   }
   return NS_OK;
 }
 
-nsresult
-BluetoothServiceChildProcess::StartInternal()
-{
-  MOZ_CRASH("This should never be called!");
-}
-
-nsresult
-BluetoothServiceChildProcess::StopInternal()
-{
-  MOZ_CRASH("This should never be called!");
-}
-
 bool
 BluetoothServiceChildProcess::IsConnected(uint16_t aServiceUuid)
 {
   MOZ_CRASH("This should never be called!");
 }
 
 nsresult
 BluetoothServiceChildProcess::SendSinkMessage(const nsAString& aDeviceAddresses,
--- a/dom/bluetooth2/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth2/ipc/BluetoothServiceChildProcess.h
@@ -42,16 +42,22 @@ public:
   UnregisterBluetoothSignalHandler(const nsAString& aNodeName,
                                    BluetoothSignalObserver* aMsgHandler)
                                    MOZ_OVERRIDE;
 
   virtual nsresult
   GetAdaptersInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
 
   virtual nsresult
+  StartInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
+  StopInternal(BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
+
+  virtual nsresult
   GetPairedDevicePropertiesInternal(const nsTArray<nsString>& aDeviceAddresses,
                                     BluetoothReplyRunnable* aRunnable)
                                     MOZ_OVERRIDE;
 
   virtual nsresult
   GetConnectedDevicePropertiesInternal(uint16_t aServiceUuid,
                                        BluetoothReplyRunnable* aRunnable)
                                        MOZ_OVERRIDE;
@@ -194,24 +200,16 @@ protected:
 
   virtual nsresult
   HandleStartup() MOZ_OVERRIDE;
 
   virtual nsresult
   HandleShutdown() MOZ_OVERRIDE;
 
 private:
-  // This method should never be called.
-  virtual nsresult
-  StartInternal() MOZ_OVERRIDE;
-
-  // This method should never be called.
-  virtual nsresult
-  StopInternal() MOZ_OVERRIDE;
-
   bool
   IsSignalRegistered(const nsAString& aNodeName) {
     return !!mBluetoothSignalObserverTable.Get(aNodeName);
   }
 };
 
 END_BLUETOOTH_NAMESPACE
 
--- a/dom/bluetooth2/ipc/PBluetooth.ipdl
+++ b/dom/bluetooth2/ipc/PBluetooth.ipdl
@@ -20,16 +20,24 @@ namespace bluetooth {
 
 /**
  * Bluetooth request types.
  */
 
 struct GetAdaptersRequest
 { };
 
+struct StartBluetoothRequest
+{
+};
+
+struct StopBluetoothRequest
+{
+};
+
 struct SetPropertyRequest
 {
   BluetoothObjectType type;
   BluetoothNamedValue value;
 };
 
 struct GetPropertyRequest
 {
@@ -161,16 +169,18 @@ struct SendPlayStatusRequest
   int64_t duration;
   int64_t position;
   nsString playStatus;
 };
 
 union Request
 {
   GetAdaptersRequest;
+  StartBluetoothRequest;
+  StopBluetoothRequest;
   SetPropertyRequest;
   GetPropertyRequest;
   StartDiscoveryRequest;
   StopDiscoveryRequest;
   PairRequest;
   UnpairRequest;
   SetPinCodeRequest;
   SetPasskeyRequest;
--- a/dom/cellbroadcast/interfaces/nsIDOMMozCellBroadcastMessage.idl
+++ b/dom/cellbroadcast/interfaces/nsIDOMMozCellBroadcastMessage.idl
@@ -1,21 +1,22 @@
 /* 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 "domstubs.idl"
 #include "nsISupports.idl"
 
 interface nsIDOMMozCellBroadcastEtwsInfo;
 
 /**
  * MozCellBroadcastMessage encapsulates Cell Broadcast short message service
  * (CBS) messages.
  */
-[scriptable, uuid(6abe65de-6729-41f7-906a-3f3a2dbe30ae)]
+[scriptable, uuid(701e74a9-5fc4-4e2d-a324-9b7693395159)]
 interface nsIDOMMozCellBroadcastMessage : nsISupports
 {
   /**
    * Indication of the geographical area over which the Message Code is unique,
    * and the display mode.
    *
    * Possible values are: "cell-immediate", "plmn", "location-area" and "cell".
    */
@@ -48,17 +49,17 @@ interface nsIDOMMozCellBroadcastMessage 
    * Possible values are "normal", "class-0", "class-1", "class-2", "class-3",
    * "user-1", and "user-2".
    */
   readonly attribute DOMString messageClass;
 
   /**
    * System time stamp at receival.
    */
-  readonly attribute jsval timestamp; // jsval is for Date.
+  readonly attribute DOMTimeStamp timestamp;
 
   /**
    * Additional ETWS-specific info.
    */
   readonly attribute nsIDOMMozCellBroadcastEtwsInfo etws;
 
   /**
    * Service Category.
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_etws.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_etws.js
@@ -191,17 +191,17 @@ function testReceiving_ETWS_MessageId() 
 function testReceiving_ETWS_Timestamp() {
   log("Test receiving ETWS Primary Notification - Timestamp");
 
   // Here we use a simple ETWS message for test.
   let pdu = buildHexStr(0, 12); // 6 octets
   doTestHelper(pdu, testReceiving_ETWS_WarningType, function(message) {
     // Cell Broadcast messages do not contain a timestamp field (however, ETWS
     // does). We only check the timestamp doesn't go too far (60 seconds) here.
-    let msMessage = message.timestamp.getTime();
+    let msMessage = message.timestamp;
     let msNow = Date.now();
     ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp");
   });
 }
 
 function testReceiving_ETWS_WarningType() {
   log("Test receiving ETWS Primary Notification - Warning Type");
 
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
@@ -356,17 +356,17 @@ function testReceiving_GSM_Language_and_
 
 function testReceiving_GSM_Timestamp() {
   log("Test receiving GSM Cell Broadcast - Timestamp");
 
   let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
   doTestHelper(pdu, testReceiving_GSM_WarningType, function(message) {
     // Cell Broadcast messages do not contain a timestamp field (however, ETWS
     // does). We only check the timestamp doesn't go too far (60 seconds) here.
-    let msMessage = message.timestamp.getTime();
+    let msMessage = message.timestamp;
     let msNow = Date.now();
     ok(Math.abs(msMessage - msNow) < (1000 * 60), "message.timestamp");
   });
 }
 
 function testReceiving_GSM_WarningType() {
   log("Test receiving GSM Cell Broadcast - Warning Type");
 
--- a/dom/datastore/DataStoreService.cpp
+++ b/dom/datastore/DataStoreService.cpp
@@ -145,17 +145,17 @@ RejectPromise(nsPIDOMWindow* aWindow, Pr
   if (aRv == NS_ERROR_DOM_SECURITY_ERR) {
     error = new DOMError(aWindow, NS_LITERAL_STRING("SecurityError"),
                          NS_LITERAL_STRING("Access denied"));
   } else {
     error = new DOMError(aWindow, NS_LITERAL_STRING("InternalError"),
                          NS_LITERAL_STRING("An error occurred"));
   }
 
-  aPromise->MaybeReject(error);
+  aPromise->MaybeRejectBrokenly(error);
 }
 
 void
 DeleteDatabase(const nsAString& aName,
                const nsAString& aManifestURL)
 {
   AssertIsInMainProcess();
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/events/KeyNameList.h
+++ b/dom/events/KeyNameList.h
@@ -15,23 +15,159 @@
  */
 
 #define DEFINE_KEYNAME_INTERNAL(aCPPName, aDOMKeyName) \
   NS_DEFINE_KEYNAME(aCPPName, aDOMKeyName)
 
 #define DEFINE_KEYNAME_WITH_SAME_NAME(aName) \
   DEFINE_KEYNAME_INTERNAL(aName, #aName)
 
+/******************************************************************************
+ * Special Key Values
+ *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(Unidentified)
+
+/******************************************************************************
+ * Our Internal Key Values (must have "Moz" prefix)
+ *****************************************************************************/
 DEFINE_KEYNAME_INTERNAL(PrintableKey, "MozPrintableKey")
 
+/******************************************************************************
+ * Modifier Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(Alt)
+DEFINE_KEYNAME_WITH_SAME_NAME(AltGraph)
+DEFINE_KEYNAME_WITH_SAME_NAME(CapsLock)
+DEFINE_KEYNAME_WITH_SAME_NAME(Control)
+DEFINE_KEYNAME_WITH_SAME_NAME(Fn)
+// DEFINE_KEYNAME_WITH_SAME_NAME(FnLock)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Hyper)
+DEFINE_KEYNAME_WITH_SAME_NAME(Meta)
+DEFINE_KEYNAME_WITH_SAME_NAME(NumLock)
+DEFINE_KEYNAME_WITH_SAME_NAME(OS)
+DEFINE_KEYNAME_WITH_SAME_NAME(ScrollLock)
+DEFINE_KEYNAME_WITH_SAME_NAME(Shift)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Super)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Symbol)
+// DEFINE_KEYNAME_WITH_SAME_NAME(SymbolLock)
+
+/******************************************************************************
+ * Whitespace Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(Enter)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Separator)
+DEFINE_KEYNAME_WITH_SAME_NAME(Tab)
+
+/******************************************************************************
+ * Navigation Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(Down) // Rename to ArrowDown
+DEFINE_KEYNAME_WITH_SAME_NAME(Left) // Rename to ArrowLeft
+DEFINE_KEYNAME_WITH_SAME_NAME(Right) // Rename to ArrowRight
+DEFINE_KEYNAME_WITH_SAME_NAME(Up) // Rename to ArrowUp
+DEFINE_KEYNAME_WITH_SAME_NAME(End)
+DEFINE_KEYNAME_WITH_SAME_NAME(Home)
+DEFINE_KEYNAME_WITH_SAME_NAME(PageDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(PageUp)
+
+/******************************************************************************
+ * Editing Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(Backspace)
+DEFINE_KEYNAME_WITH_SAME_NAME(Clear)
+DEFINE_KEYNAME_WITH_SAME_NAME(Copy)
+DEFINE_KEYNAME_WITH_SAME_NAME(Crsel) // Rename to CrSel
+DEFINE_KEYNAME_WITH_SAME_NAME(Cut)
+DEFINE_KEYNAME_WITH_SAME_NAME(Del) // Rename to Delete
+DEFINE_KEYNAME_WITH_SAME_NAME(EraseEof)
+DEFINE_KEYNAME_WITH_SAME_NAME(Exsel) // Rename to ExSel
+DEFINE_KEYNAME_WITH_SAME_NAME(Insert)
+DEFINE_KEYNAME_WITH_SAME_NAME(Paste)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Redo)
+DEFINE_KEYNAME_WITH_SAME_NAME(Undo)
+
+/******************************************************************************
+ * UI Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(Accept)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Again)
 DEFINE_KEYNAME_WITH_SAME_NAME(Attn)
-DEFINE_KEYNAME_WITH_SAME_NAME(Apps)
-DEFINE_KEYNAME_WITH_SAME_NAME(Crsel)
-DEFINE_KEYNAME_WITH_SAME_NAME(Exsel)
+DEFINE_KEYNAME_WITH_SAME_NAME(Cancel)
+DEFINE_KEYNAME_WITH_SAME_NAME(Menu) // Rename to ContextMenu
+DEFINE_KEYNAME_WITH_SAME_NAME(Esc) // Rename to Escape
+DEFINE_KEYNAME_WITH_SAME_NAME(Execute)
+DEFINE_KEYNAME_WITH_SAME_NAME(Find)
+DEFINE_KEYNAME_WITH_SAME_NAME(Help)
+DEFINE_KEYNAME_WITH_SAME_NAME(Pause)
+DEFINE_KEYNAME_WITH_SAME_NAME(Play)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Props)
+DEFINE_KEYNAME_WITH_SAME_NAME(Select)
+// DEFINE_KEYNAME_WITH_SAME_NAME(ZoomIn)
+// DEFINE_KEYNAME_WITH_SAME_NAME(ZoomOut)
+
+/******************************************************************************
+ * Device Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessUp)
+DEFINE_KEYNAME_WITH_SAME_NAME(Camera)
+DEFINE_KEYNAME_WITH_SAME_NAME(Eject)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LogOff)
+DEFINE_KEYNAME_WITH_SAME_NAME(Power)
+// DEFINE_KEYNAME_WITH_SAME_NAME(PowerOff)
+DEFINE_KEYNAME_WITH_SAME_NAME(PrintScreen)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Hibernate)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Standby)
+// DEFINE_KEYNAME_WITH_SAME_NAME(WakeUp)
+
+/******************************************************************************
+ * IME and Composition Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(AllCandidates)
+DEFINE_KEYNAME_WITH_SAME_NAME(Alphanumeric)
+DEFINE_KEYNAME_WITH_SAME_NAME(CodeInput)
+DEFINE_KEYNAME_WITH_SAME_NAME(Compose)
+DEFINE_KEYNAME_WITH_SAME_NAME(Convert)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Dead)
+DEFINE_KEYNAME_WITH_SAME_NAME(FinalMode)
+// DEFINE_KEYNAME_WITH_SAME_NAME(GroupFirst)
+// DEFINE_KEYNAME_WITH_SAME_NAME(GroupLast)
+// DEFINE_KEYNAME_WITH_SAME_NAME(GroupNext)
+// DEFINE_KEYNAME_WITH_SAME_NAME(GroupPrevious)
+DEFINE_KEYNAME_WITH_SAME_NAME(ModeChange)
+// DEFINE_KEYNAME_WITH_SAME_NAME(NextCandidate)
+DEFINE_KEYNAME_WITH_SAME_NAME(Nonconvert) // Rename to NonConvert
+DEFINE_KEYNAME_WITH_SAME_NAME(PreviousCandidate)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Process)
+// DEFINE_KEYNAME_WITH_SAME_NAME(SingleCandidate)
+
+/******************************************************************************
+ * Keys specific to Korean keyboards
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(HangulMode)
+DEFINE_KEYNAME_WITH_SAME_NAME(HanjaMode)
+DEFINE_KEYNAME_WITH_SAME_NAME(JunjaMode)
+
+/******************************************************************************
+ * Keys specific to Japanese keyboards
+ *****************************************************************************/
+// DEFINE_KEYNAME_WITH_SAME_NAME(Eisu)
+DEFINE_KEYNAME_WITH_SAME_NAME(HalfWidth) // Rename to Hankaku
+DEFINE_KEYNAME_WITH_SAME_NAME(Hiragana)
+// DEFINE_KEYNAME_WITH_SAME_NAME(HiraganaKatakana)
+DEFINE_KEYNAME_WITH_SAME_NAME(KanaMode)
+DEFINE_KEYNAME_WITH_SAME_NAME(KanjiMode)
+DEFINE_KEYNAME_WITH_SAME_NAME(Katakana)
+DEFINE_KEYNAME_WITH_SAME_NAME(RomanCharacters) // Rename to Romaji
+DEFINE_KEYNAME_WITH_SAME_NAME(FullWidth) // Rename to Zenkaku
+// DEFINE_KEYNAME_WITH_SAME_NAME(ZenkakuHankaku)
+
+/******************************************************************************
+ * General-Purpose Function Keys
+ *****************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(F1)
 DEFINE_KEYNAME_WITH_SAME_NAME(F2)
 DEFINE_KEYNAME_WITH_SAME_NAME(F3)
 DEFINE_KEYNAME_WITH_SAME_NAME(F4)
 DEFINE_KEYNAME_WITH_SAME_NAME(F5)
 DEFINE_KEYNAME_WITH_SAME_NAME(F6)
 DEFINE_KEYNAME_WITH_SAME_NAME(F7)
 DEFINE_KEYNAME_WITH_SAME_NAME(F8)
@@ -57,16 +193,57 @@ DEFINE_KEYNAME_WITH_SAME_NAME(F27)
 DEFINE_KEYNAME_WITH_SAME_NAME(F28)
 DEFINE_KEYNAME_WITH_SAME_NAME(F29)
 DEFINE_KEYNAME_WITH_SAME_NAME(F30)
 DEFINE_KEYNAME_WITH_SAME_NAME(F31)
 DEFINE_KEYNAME_WITH_SAME_NAME(F32)
 DEFINE_KEYNAME_WITH_SAME_NAME(F33)
 DEFINE_KEYNAME_WITH_SAME_NAME(F34)
 DEFINE_KEYNAME_WITH_SAME_NAME(F35)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Soft1)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Soft2)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Soft3)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Soft4)
+
+/******************************************************************************
+ * Multimedia Keys
+ *****************************************************************************/
+// DEFINE_KEYNAME_WITH_SAME_NAME(Close)
+// DEFINE_KEYNAME_WITH_SAME_NAME(MailForward)
+// DEFINE_KEYNAME_WITH_SAME_NAME(MailReply)
+// DEFINE_KEYNAME_WITH_SAME_NAME(MailSend)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlayPause)
+DEFINE_KEYNAME_WITH_SAME_NAME(SelectMedia) // Rename to MediaSelect
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaStop)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaNextTrack) // Rename to MediaTrackNext
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaPreviousTrack) // Rename to MediaTrackPrevious
+// DEFINE_KEYNAME_WITH_SAME_NAME(New)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Open)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Print)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Save)
+// DEFINE_KEYNAME_WITH_SAME_NAME(SpellCheck)
+DEFINE_KEYNAME_WITH_SAME_NAME(VolumeDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(VolumeUp)
+DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
+
+/******************************************************************************
+ * Application Keys
+ *****************************************************************************/
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalculator)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchCalendar)
+DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMail)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMediaPlayer)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMusicPlayer)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMyComputer)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchScreenSaver)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchSpreadsheet)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebBrowser)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWebCam)
+// DEFINE_KEYNAME_WITH_SAME_NAME(LaunchWordProcessor)
+
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication1)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication2)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication3)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication4)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication5)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication6)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication7)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication8)
@@ -75,191 +252,124 @@ DEFINE_KEYNAME_WITH_SAME_NAME(LaunchAppl
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication11)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication12)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication13)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication14)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication15)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication16)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication17)
 DEFINE_KEYNAME_WITH_SAME_NAME(LaunchApplication18)
-DEFINE_KEYNAME_WITH_SAME_NAME(LaunchMail)
-DEFINE_KEYNAME_WITH_SAME_NAME(List)
-DEFINE_KEYNAME_WITH_SAME_NAME(Props)
-DEFINE_KEYNAME_WITH_SAME_NAME(Soft1)
-DEFINE_KEYNAME_WITH_SAME_NAME(Soft2)
-DEFINE_KEYNAME_WITH_SAME_NAME(Soft3)
-DEFINE_KEYNAME_WITH_SAME_NAME(Soft4)
-DEFINE_KEYNAME_WITH_SAME_NAME(Accept)
-DEFINE_KEYNAME_WITH_SAME_NAME(Again)
-DEFINE_KEYNAME_WITH_SAME_NAME(Enter)
-DEFINE_KEYNAME_WITH_SAME_NAME(Find)
-DEFINE_KEYNAME_WITH_SAME_NAME(Help)
-DEFINE_KEYNAME_WITH_SAME_NAME(Info)
-DEFINE_KEYNAME_WITH_SAME_NAME(Menu)
-DEFINE_KEYNAME_WITH_SAME_NAME(Pause)
-DEFINE_KEYNAME_WITH_SAME_NAME(Play)
-DEFINE_KEYNAME_WITH_SAME_NAME(ScrollLock) // IE9 users "Scroll"
-DEFINE_KEYNAME_WITH_SAME_NAME(Execute)
-DEFINE_KEYNAME_WITH_SAME_NAME(Cancel)
-DEFINE_KEYNAME_WITH_SAME_NAME(Esc)
-DEFINE_KEYNAME_WITH_SAME_NAME(Exit)
-DEFINE_KEYNAME_WITH_SAME_NAME(Zoom)
-DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(BrightnessUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(Camera)
-DEFINE_KEYNAME_WITH_SAME_NAME(Eject)
-DEFINE_KEYNAME_WITH_SAME_NAME(Power)
-DEFINE_KEYNAME_WITH_SAME_NAME(PrintScreen)
+
+/******************************************************************************
+ * Browser Keys
+ *****************************************************************************/
+DEFINE_KEYNAME_WITH_SAME_NAME(BrowserBack)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserFavorites)
+DEFINE_KEYNAME_WITH_SAME_NAME(BrowserForward)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserHome)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserRefresh)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserSearch)
 DEFINE_KEYNAME_WITH_SAME_NAME(BrowserStop)
-DEFINE_KEYNAME_WITH_SAME_NAME(BrowserBack)
-DEFINE_KEYNAME_WITH_SAME_NAME(BrowserForward)
-DEFINE_KEYNAME_WITH_SAME_NAME(Left)
-DEFINE_KEYNAME_WITH_SAME_NAME(PageDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(PageUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(Right)
-DEFINE_KEYNAME_WITH_SAME_NAME(Up)
-DEFINE_KEYNAME_WITH_SAME_NAME(UpLeft)
-DEFINE_KEYNAME_WITH_SAME_NAME(UpRight)
-DEFINE_KEYNAME_WITH_SAME_NAME(Down)
-DEFINE_KEYNAME_WITH_SAME_NAME(DownLeft)
-DEFINE_KEYNAME_WITH_SAME_NAME(DownRight)
-DEFINE_KEYNAME_WITH_SAME_NAME(Home)
-DEFINE_KEYNAME_WITH_SAME_NAME(End)
-DEFINE_KEYNAME_WITH_SAME_NAME(Select)
-DEFINE_KEYNAME_WITH_SAME_NAME(Tab)
-DEFINE_KEYNAME_WITH_SAME_NAME(Backspace)
-DEFINE_KEYNAME_WITH_SAME_NAME(Clear)
-DEFINE_KEYNAME_WITH_SAME_NAME(Copy)
-DEFINE_KEYNAME_WITH_SAME_NAME(Cut)
-DEFINE_KEYNAME_WITH_SAME_NAME(Del)
-DEFINE_KEYNAME_WITH_SAME_NAME(EraseEof)
-DEFINE_KEYNAME_WITH_SAME_NAME(Insert)
-DEFINE_KEYNAME_WITH_SAME_NAME(Paste)
-DEFINE_KEYNAME_WITH_SAME_NAME(Undo)
+
+/******************************************************************************
+ * Media Controller Keys
+ *****************************************************************************/
+// DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceLeft)
+// DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceRight)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostUp)
+// DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderFront)
+// DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
+// DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
+// DEFINE_KEYNAME_WITH_SAME_NAME(AVRInput)
+// DEFINE_KEYNAME_WITH_SAME_NAME(AVRPower)
+DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
+DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
+DEFINE_KEYNAME_WITH_SAME_NAME(Red) // Rename to ColorF0Red
+DEFINE_KEYNAME_WITH_SAME_NAME(Green) // Rename to ColorF1Green
+DEFINE_KEYNAME_WITH_SAME_NAME(Yellow) // Rename to ColorF2Yellow
+DEFINE_KEYNAME_WITH_SAME_NAME(Blue) // Rename to ColorF3Blue
+// DEFINE_KEYNAME_WITH_SAME_NAME(Grey) // Rename to ColorF4Grey
+// DEFINE_KEYNAME_WITH_SAME_NAME(Brown) // Rename to ColorF5Brown
+// DEFINE_KEYNAME_WITH_SAME_NAME(ClosedCaptionToggle)
+DEFINE_KEYNAME_WITH_SAME_NAME(Dimmer)
+// DEFINE_KEYNAME_WITH_SAME_NAME(DisplaySwap)
+DEFINE_KEYNAME_WITH_SAME_NAME(Exit)
+// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite0) // Rename to FavoriteClear0
+// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite1) // Rename to FavoriteClear1
+// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite2) // Rename to FavoriteClear2
+// DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite3) // Rename to FavoriteClear3
+// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite0) // Rename to FavoriteRecall0
+// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite1) // Rename to FavoriteRecall1
+// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite2) // Rename to FavoriteRecall2
+// DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite3) // Rename to FavoriteRecall3
+// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite0) // Rename to FavoriteStore0
+// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite1) // Rename to FavoriteStore1
+// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite2) // Rename to FavoriteStore2
+// DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite3) // Rename to FavoriteStore3
+DEFINE_KEYNAME_WITH_SAME_NAME(Guide)
+// DEFINE_KEYNAME_WITH_SAME_NAME(NextDay) // Rename to GuideNextDay
+// DEFINE_KEYNAME_WITH_SAME_NAME(PrevDay) // Rename to GuidePreviousDay
+DEFINE_KEYNAME_WITH_SAME_NAME(Info)
+// DEFINE_KEYNAME_WITH_SAME_NAME(InstantReplay)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Link)
+// DEFINE_KEYNAME_WITH_SAME_NAME(List) // Rename to ListProgram
+DEFINE_KEYNAME_WITH_SAME_NAME(Live) // Rename to LiveContent
+// DEFINE_KEYNAME_WITH_SAME_NAME(Lock)
+DEFINE_KEYNAME_WITH_SAME_NAME(Apps) // Rename to MediaApps
+DEFINE_KEYNAME_WITH_SAME_NAME(FastFwd) // Rename to MediaFastForward
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaLast)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaRecord)
+DEFINE_KEYNAME_WITH_SAME_NAME(MediaRewind)
+// DEFINE_KEYNAME_WITH_SAME_NAME(MediaSkip)
+// DEFINE_KEYNAME_WITH_SAME_NAME(NextFavoriteChannel)
+// DEFINE_KEYNAME_WITH_SAME_NAME(NextUserProfile)
+// DEFINE_KEYNAME_WITH_SAME_NAME(OnDemand)
+// DEFINE_KEYNAME_WITH_SAME_NAME(PinPDown)
+// DEFINE_KEYNAME_WITH_SAME_NAME(PinPMove)
+DEFINE_KEYNAME_WITH_SAME_NAME(PinPToggle)
+// DEFINE_KEYNAME_WITH_SAME_NAME(PinPUp)
+// DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedDown)
+// DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedReset)
+// DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedUp)
+DEFINE_KEYNAME_WITH_SAME_NAME(RandomToggle)
+// DEFINE_KEYNAME_WITH_SAME_NAME(RcLowBattery)
+// DEFINE_KEYNAME_WITH_SAME_NAME(RecordSpeedNext)
+// DEFINE_KEYNAME_WITH_SAME_NAME(RfBypass)
+// DEFINE_KEYNAME_WITH_SAME_NAME(ScanChannelsToggle)
+// DEFINE_KEYNAME_WITH_SAME_NAME(ScreenModeNext)
+DEFINE_KEYNAME_WITH_SAME_NAME(Settings)
+// DEFINE_KEYNAME_WITH_SAME_NAME(SplitScreenToggle)
+// DEFINE_KEYNAME_WITH_SAME_NAME(STBInput)
+// DEFINE_KEYNAME_WITH_SAME_NAME(STBPower)
+DEFINE_KEYNAME_WITH_SAME_NAME(Subtitle)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Teletext)
+// DEFINE_KEYNAME_WITH_SAME_NAME(TV)
+// DEFINE_KEYNAME_WITH_SAME_NAME(TVInput)
+// DEFINE_KEYNAME_WITH_SAME_NAME(TVPower)
+// DEFINE_KEYNAME_WITH_SAME_NAME(VideoModeNext)
+// DEFINE_KEYNAME_WITH_SAME_NAME(Wink)
+DEFINE_KEYNAME_WITH_SAME_NAME(Zoom) // Rename to ZoomToggle
+
+/******************************************************************************
+ * Deprecated
+ ******************************************************************************/
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadGrave)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadAcute)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadCircumflex)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadTilde)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadMacron)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadBreve)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadAboveDot)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadUmlaut)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadAboveRing)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadDoubleacute)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadCaron)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadCedilla)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadOgonek)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadIota)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadVoicedSound)
 DEFINE_KEYNAME_WITH_SAME_NAME(DeadSemivoicedSound)
-DEFINE_KEYNAME_WITH_SAME_NAME(Alphanumeric)
-DEFINE_KEYNAME_WITH_SAME_NAME(Alt)
-DEFINE_KEYNAME_WITH_SAME_NAME(AltGraph)
-DEFINE_KEYNAME_WITH_SAME_NAME(CapsLock)
-DEFINE_KEYNAME_WITH_SAME_NAME(Control)
-DEFINE_KEYNAME_WITH_SAME_NAME(Fn)
-DEFINE_KEYNAME_WITH_SAME_NAME(FnLock)
-DEFINE_KEYNAME_WITH_SAME_NAME(Meta)
-DEFINE_KEYNAME_WITH_SAME_NAME(Process)
-DEFINE_KEYNAME_WITH_SAME_NAME(NumLock)
-DEFINE_KEYNAME_WITH_SAME_NAME(Shift)
-DEFINE_KEYNAME_WITH_SAME_NAME(SymbolLock)
-DEFINE_KEYNAME_WITH_SAME_NAME(OS) // IE9 uses "Win"
-DEFINE_KEYNAME_WITH_SAME_NAME(Compose)
-DEFINE_KEYNAME_WITH_SAME_NAME(AllCandidates)
-DEFINE_KEYNAME_WITH_SAME_NAME(NextCandidate)
-DEFINE_KEYNAME_WITH_SAME_NAME(PreviousCandidate)
-DEFINE_KEYNAME_WITH_SAME_NAME(CodeInput)
-DEFINE_KEYNAME_WITH_SAME_NAME(Convert)
-DEFINE_KEYNAME_WITH_SAME_NAME(Nonconvert)
-DEFINE_KEYNAME_WITH_SAME_NAME(FinalMode)
-DEFINE_KEYNAME_WITH_SAME_NAME(FullWidth)
-DEFINE_KEYNAME_WITH_SAME_NAME(HalfWidth)
-DEFINE_KEYNAME_WITH_SAME_NAME(ModeChange)
-DEFINE_KEYNAME_WITH_SAME_NAME(RomanCharacters)
-DEFINE_KEYNAME_WITH_SAME_NAME(HangulMode)
-DEFINE_KEYNAME_WITH_SAME_NAME(HanjaMode)
-DEFINE_KEYNAME_WITH_SAME_NAME(JunjaMode)
-DEFINE_KEYNAME_WITH_SAME_NAME(Hiragana)
-DEFINE_KEYNAME_WITH_SAME_NAME(KanaMode)
-DEFINE_KEYNAME_WITH_SAME_NAME(KanjiMode)
-DEFINE_KEYNAME_WITH_SAME_NAME(Katakana)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderFront)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioFaderRear)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceLeft)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBalanceRight)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioBassBoostUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(VolumeMute)
-DEFINE_KEYNAME_WITH_SAME_NAME(VolumeDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(VolumeUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaPause)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlay)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaStop)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaNextTrack)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaPreviousTrack)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaPlayPause)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackSkip)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackStart)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaTrackEnd)
-DEFINE_KEYNAME_WITH_SAME_NAME(SelectMedia)
-DEFINE_KEYNAME_WITH_SAME_NAME(Blue)
-DEFINE_KEYNAME_WITH_SAME_NAME(Brown)
-DEFINE_KEYNAME_WITH_SAME_NAME(ChannelDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(ChannelUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite0)
-DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite1)
-DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite2)
-DEFINE_KEYNAME_WITH_SAME_NAME(ClearFavorite3)
-DEFINE_KEYNAME_WITH_SAME_NAME(Dimmer)
-DEFINE_KEYNAME_WITH_SAME_NAME(DisplaySwap)
-DEFINE_KEYNAME_WITH_SAME_NAME(FastFwd)
-DEFINE_KEYNAME_WITH_SAME_NAME(Green)
-DEFINE_KEYNAME_WITH_SAME_NAME(Grey)
-DEFINE_KEYNAME_WITH_SAME_NAME(Guide)
-DEFINE_KEYNAME_WITH_SAME_NAME(InstantReplay)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaLast)
-DEFINE_KEYNAME_WITH_SAME_NAME(Link)
-DEFINE_KEYNAME_WITH_SAME_NAME(Live)
-DEFINE_KEYNAME_WITH_SAME_NAME(Lock)
-DEFINE_KEYNAME_WITH_SAME_NAME(NextDay)
-DEFINE_KEYNAME_WITH_SAME_NAME(NextFavoriteChannel)
-DEFINE_KEYNAME_WITH_SAME_NAME(OnDemand)
-DEFINE_KEYNAME_WITH_SAME_NAME(PinPDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(PinPMove)
-DEFINE_KEYNAME_WITH_SAME_NAME(PinPToggle)
-DEFINE_KEYNAME_WITH_SAME_NAME(PinPUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedDown)
-DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedReset)
-DEFINE_KEYNAME_WITH_SAME_NAME(PlaySpeedUp)
-DEFINE_KEYNAME_WITH_SAME_NAME(PrevDay)
-DEFINE_KEYNAME_WITH_SAME_NAME(RandomToggle)
-DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite0)
-DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite1)
-DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite2)
-DEFINE_KEYNAME_WITH_SAME_NAME(RecallFavorite3)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaRecord)
-DEFINE_KEYNAME_WITH_SAME_NAME(RecordSpeedNext)
-DEFINE_KEYNAME_WITH_SAME_NAME(Red)
-DEFINE_KEYNAME_WITH_SAME_NAME(MediaRewind)
-DEFINE_KEYNAME_WITH_SAME_NAME(RfBypass)
-DEFINE_KEYNAME_WITH_SAME_NAME(ScanChannelsToggle)
-DEFINE_KEYNAME_WITH_SAME_NAME(ScreenModeNext)
-DEFINE_KEYNAME_WITH_SAME_NAME(Settings)
-DEFINE_KEYNAME_WITH_SAME_NAME(SplitScreenToggle)
-DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite0)
-DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite1)
-DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite2)
-DEFINE_KEYNAME_WITH_SAME_NAME(StoreFavorite3)
-DEFINE_KEYNAME_WITH_SAME_NAME(Subtitle)
-DEFINE_KEYNAME_WITH_SAME_NAME(AudioSurroundModeNext)
-DEFINE_KEYNAME_WITH_SAME_NAME(Teletext)
-DEFINE_KEYNAME_WITH_SAME_NAME(VideoModeNext)
-DEFINE_KEYNAME_WITH_SAME_NAME(DisplayWide)
-DEFINE_KEYNAME_WITH_SAME_NAME(Wink)
-DEFINE_KEYNAME_WITH_SAME_NAME(Yellow)
 
 #undef DEFINE_KEYNAME_WITH_SAME_NAME
 #undef DEFINE_KEYNAME_INTERNAL
--- a/dom/events/PhysicalKeyCodeNameList.h
+++ b/dom/events/PhysicalKeyCodeNameList.h
@@ -37,17 +37,17 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit4)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit5)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit6)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit7)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit8)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Digit9)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Equal)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlBackslash)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlHash)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlHash)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlRo)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(IntlYen)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KeyA)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KeyB)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KeyC)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KeyD)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KeyE)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KeyF)
@@ -92,19 +92,19 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Space)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Tab)
 
 // IME keys
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Convert)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(KanaMode)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang1)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang2)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang3)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang4)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang5)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang3)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang4)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Lang5)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NonConvert)
 
 // Control pad section
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Delete)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(End)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Help)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Home)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Insert)
@@ -126,31 +126,31 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad4)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad5)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad6)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad7)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad8)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Numpad9)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadAdd)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadBackspace)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClear)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClearEntry)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClear)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadClearEntry)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadComma)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadDecimal)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadDivide)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadEnter)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadEqual)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryAdd)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryClear)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryRecall)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryStore)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryAdd)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryClear)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryRecall)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemoryStore)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMemorySubtract)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadMultiply)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenLeft)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenRight)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenLeft)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadParenRight)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(NumpadSubtract)
 
 // Function section
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Escape)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F1)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F2)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F3)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F4)
@@ -170,17 +170,17 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F18)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F19)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F20)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F21)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F22)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F23)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(F24)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Fn)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(FLock)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(FLock)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(PrintScreen)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(ScrollLock)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Pause)
 
 // Media keys
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(BrowserBack)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(BrowserFavorites)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(BrowserForward)
@@ -200,18 +200,17 @@ DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Power)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Sleep)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(VolumeDown)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(VolumeMute)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(VolumeUp)
 DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(WakeUp)
 
 // Legacy keys
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Abort)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Hyper)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Meta)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Resume)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Super)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Suspend)
-DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Turbo)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Abort)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Hyper)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Resume)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Super)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Suspend)
+// DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME(Turbo)
 
 #undef DEFINE_PHYSICAL_KEY_CODE_NAME_WITH_SAME_NAME
 #undef NS_DEFINE_PHYSICAL_KEY_CODE_NAME_INTERNAL
--- a/dom/filesystem/CreateDirectoryTask.cpp
+++ b/dom/filesystem/CreateDirectoryTask.cpp
@@ -117,17 +117,17 @@ CreateDirectoryTask::HandlerCallback()
   if (mFileSystem->IsShutdown()) {
     mPromise = nullptr;
     return;
   }
 
   if (HasError()) {
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
-    mPromise->MaybeReject(domError);
+    mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     return;
   }
   nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
   mPromise->MaybeResolve(dir);
   mPromise = nullptr;
 }
 
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -282,17 +282,17 @@ CreateFileTask::HandlerCallback()
   if (mFileSystem->IsShutdown()) {
     mPromise = nullptr;
     return;
   }
 
   if (HasError()) {
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
-    mPromise->MaybeReject(domError);
+    mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     return;
   }
 
   mPromise->MaybeResolve(mTargetFile);
   mPromise = nullptr;
 }
 
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -192,17 +192,17 @@ GetFileOrDirectoryTask::HandlerCallback(
   if (mFileSystem->IsShutdown()) {
     mPromise = nullptr;
     return;
   }
 
   if (HasError()) {
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
-    mPromise->MaybeReject(domError);
+    mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     return;
   }
 
   if (mIsDirectory) {
     nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
--- a/dom/filesystem/RemoveTask.cpp
+++ b/dom/filesystem/RemoveTask.cpp
@@ -180,17 +180,17 @@ RemoveTask::HandlerCallback()
   if (mFileSystem->IsShutdown()) {
     mPromise = nullptr;
     return;
   }
 
   if (HasError()) {
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
-    mPromise->MaybeReject(domError);
+    mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     return;
   }
 
   mPromise->MaybeResolve(mReturnValue);
   mPromise = nullptr;
 }
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1468,17 +1468,17 @@ ContentChild::AddRemoteAlertObserver(con
 
 bool
 ContentChild::RecvSystemMemoryAvailable(const uint64_t& aGetterId,
                                         const uint32_t& aMemoryAvailable)
 {
     nsRefPtr<Promise> p = dont_AddRef(reinterpret_cast<Promise*>(aGetterId));
 
     if (!aMemoryAvailable) {
-        p->MaybeReject(NS_LITERAL_STRING("Abnormal"));
+        p->MaybeReject(NS_ERROR_NOT_AVAILABLE);
         return true;
     }
 
     p->MaybeResolve((int)aMemoryAvailable);
     return true;
 }
 
 bool
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -56,16 +56,17 @@
 #include "PermissionMessageUtils.h"
 #include "StructuredCloneUtils.h"
 #include "ColorPickerParent.h"
 #include "JavaScriptParent.h"
 #include "FilePickerParent.h"
 #include "TabChild.h"
 #include "LoadContext.h"
 #include "nsNetCID.h"
+#include "gfxPrefs.h"
 #include <algorithm>
 
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
 using namespace mozilla::layout;
 using namespace mozilla::services;
 using namespace mozilla::widget;
@@ -1883,19 +1884,17 @@ TabParent::GetWidget() const
   nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget();
   return widget.forget();
 }
 
 bool
 TabParent::UseAsyncPanZoom()
 {
   bool usingOffMainThreadCompositing = !!CompositorParent::CompositorLoop();
-  bool asyncPanZoomEnabled =
-    Preferences::GetBool("layers.async-pan-zoom.enabled", false);
-  return (usingOffMainThreadCompositing && asyncPanZoomEnabled &&
+  return (usingOffMainThreadCompositing && gfxPrefs::AsyncPanZoomEnabled() &&
           GetScrollingBehavior() == ASYNC_PAN_ZOOM);
 }
 
 nsEventStatus
 TabParent::MaybeForwardEventToRenderFrame(WidgetInputEvent& aEvent,
                                           ScrollableLayerGuid* aOutTargetGuid)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
--- a/dom/mobilemessage/moz.build
+++ b/dom/mobilemessage/moz.build
@@ -2,10 +2,8 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['interfaces', 'src']
 TEST_DIRS += ['tests']
 
-if CONFIG['ENABLE_TESTS']:
-    XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini']
rename from dom/mobilemessage/tests/mochitest.ini
rename to dom/mobilemessage/tests/mochitest/mochitest.ini
rename from dom/mobilemessage/tests/test_sms_basics.html
rename to dom/mobilemessage/tests/mochitest/test_sms_basics.html
rename from dom/mobilemessage/tests/test_smsfilter.html
rename to dom/mobilemessage/tests/mochitest/test_smsfilter.html
--- a/dom/mobilemessage/tests/moz.build
+++ b/dom/mobilemessage/tests/moz.build
@@ -1,8 +1,11 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-MOCHITEST_MANIFESTS += ['mochitest.ini']
+MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
 
+if CONFIG['ENABLE_TESTS']:
+        XPCSHELL_TESTS_MANIFESTS += ['xpcshell/xpcshell.ini']
+
rename from dom/mobilemessage/tests/header_helpers.js
rename to dom/mobilemessage/tests/xpcshell/header_helpers.js
rename from dom/mobilemessage/tests/test_mms_pdu_helper.js
rename to dom/mobilemessage/tests/xpcshell/test_mms_pdu_helper.js
rename from dom/mobilemessage/tests/test_mms_service.js
rename to dom/mobilemessage/tests/xpcshell/test_mms_service.js
rename from dom/mobilemessage/tests/test_smsservice_createsmsmessage.js
rename to dom/mobilemessage/tests/xpcshell/test_smsservice_createsmsmessage.js
rename from dom/mobilemessage/tests/test_wsp_pdu_helper.js
rename to dom/mobilemessage/tests/xpcshell/test_wsp_pdu_helper.js
rename from dom/mobilemessage/tests/xpcshell.ini
rename to dom/mobilemessage/tests/xpcshell/xpcshell.ini
--- a/dom/mobilemessage/tests/xpcshell.ini
+++ b/dom/mobilemessage/tests/xpcshell/xpcshell.ini
@@ -1,14 +1,11 @@
 [DEFAULT]
 head = header_helpers.js
 tail =
-support-files =
-  test_sms_basics.html
-  test_smsfilter.html
 
 [test_smsservice_createsmsmessage.js]
 [test_wsp_pdu_helper.js]
 run-if = toolkit == "gonk"
 [test_mms_pdu_helper.js]
 run-if = toolkit == "gonk"
 [test_mms_service.js]
 run-if = toolkit == "gonk"
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/Promise.h"
 
 #include "jsfriendapi.h"
+#include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Preferences.h"
 #include "PromiseCallback.h"
 #include "PromiseNativeHandler.h"
 #include "PromiseWorkerProxy.h"
 #include "nsContentUtils.h"
@@ -1426,10 +1427,20 @@ PromiseWorkerProxy::CleanUp(JSContext* a
   // Release the Promise and remove the PromiseWorkerProxy from the features of
   // the worker thread since the Promise has been resolved/rejected or the
   // worker thread has been cancelled.
   mWorkerPromise = nullptr;
   mWorkerPrivate->RemoveFeature(aCx, this);
   mCleanedUp = true;
 }
 
+// Specializations of MaybeRejectBrokenly we actually support.
+template<>
+void Promise::MaybeRejectBrokenly(const nsRefPtr<DOMError>& aArg) {
+  MaybeSomething(aArg, &Promise::MaybeReject);
+}
+template<>
+void Promise::MaybeRejectBrokenly(const nsAString& aArg) {
+  MaybeSomething(aArg, &Promise::MaybeReject);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -21,16 +21,17 @@
 #include "mozilla/dom/workers/bindings/WorkerFeature.h"
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 class AnyCallback;
+class DOMError;
 class PromiseCallback;
 class PromiseInit;
 class PromiseNativeHandler;
 
 class Promise;
 class PromiseReportRejectFeature : public workers::WorkerFeature
 {
   // The Promise that owns this feature.
@@ -84,21 +85,31 @@ public:
   // Most DOM objects are handled already.  To add a new type T, add a
   // ToJSValue overload in ToJSValue.h.
   // aArg is a const reference so we can pass rvalues like integer constants
   template <typename T>
   void MaybeResolve(const T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeResolve);
   }
 
-  // aArg is a const reference so we can pass rvalues like NS_ERROR_*
-  template <typename T>
-  void MaybeReject(const T& aArg) {
+  inline void MaybeReject(nsresult aArg) {
+    MOZ_ASSERT(NS_FAILED(aArg));
     MaybeSomething(aArg, &Promise::MaybeReject);
   }
+  // DO NOT USE MaybeRejectBrokenly with in new code.  Promises should be
+  // rejected with Error instances.
+  // Note: MaybeRejectBrokenly is a template so we can use it with DOMError
+  // without instantiating the DOMError specialization of MaybeSomething in
+  // every translation unit that includes this header, because that would
+  // require use to include DOMError.h either here or in all those translation
+  // units.
+  template<typename T>
+  void MaybeRejectBrokenly(const T& aArg); // Not implemented by default; see
+                                           // specializations in the .cpp for
+                                           // the T values we support.
 
   // WebIDL
 
   nsIGlobalObject* GetParentObject() const
   {
     return mGlobal;
   }
 
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -1489,20 +1489,23 @@ this.PushService = {
         // In Multi-sim, there is more than one client in iccProvider. Each
         // client represents a icc service. To maintain backward compatibility
         // with single sim, we always use client 0 for now. Adding support
         // for multiple sim will be addressed in bug 927721, if needed.
         let clientId = 0;
         let iccInfo = icc.getIccInfo(clientId);
         if (iccInfo) {
           debug("Running on mobile data");
+          let ips = {};
+          let prefixLengths = {};
+          nm.active.getAddresses(ips, prefixLengths);
           return {
             mcc: iccInfo.mcc,
             mnc: iccInfo.mnc,
-            ip:  nm.active.ip
+            ip:  ips.value[0]
           }
         }
       }
     } catch (e) {}
 
     debug("Running on wifi");
 
     return {
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -307,17 +307,17 @@ MobileCallForwardingInfo.prototype = {
 
 function CellBroadcastMessage(pdu) {
   this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
   this.messageCode = pdu.messageCode;
   this.messageId = pdu.messageId;
   this.language = pdu.language;
   this.body = pdu.fullBody;
   this.messageClass = pdu.messageClass;
-  this.timestamp = new Date(pdu.timestamp);
+  this.timestamp = pdu.timestamp;
 
   if (pdu.etws != null) {
     this.etws = new CellBroadcastEtwsInfo(pdu.etws);
   }
 
   this.cdmaServiceCategory = pdu.serviceCategory;
 }
 CellBroadcastMessage.prototype = {
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -12786,19 +12786,27 @@ SimRecordHelperObject.prototype = {
         for (let i = 0; i < ad.length; i++) {
           str += ad[i] + ", ";
         }
         this.context.debug("AD: " + str);
       }
 
       let ICCUtilsHelper = this.context.ICCUtilsHelper;
       let RIL = this.context.RIL;
+      // TS 31.102, clause 4.2.18 EFAD
+      let mncLength = 0;
+      if (ad && ad[3]) {
+        mncLength = ad[3] & 0x0f;
+        if (mncLength != 0x02 && mncLength != 0x03) {
+           mncLength = 0;
+        }
+      }
       // The 4th byte of the response is the length of MNC.
       let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi,
-                                                      ad && ad[3]);
+                                                      mncLength);
       if (mccMnc) {
         RIL.iccInfo.mcc = mccMnc.mcc;
         RIL.iccInfo.mnc = mccMnc.mnc;
         ICCUtilsHelper.handleICCInfoChange();
       }
     }
 
     this.context.ICCIOHelper.loadTransparentEF({
@@ -14125,16 +14133,17 @@ ICCUtilsHelperObject.prototype = {
   /**
    * Parse MCC/MNC from IMSI. If there is no available value for the length of
    * mnc, it will use the data in MCC table to parse.
    *
    * @param imsi
    *        The imsi of icc.
    * @param mncLength [optional]
    *        The length of mnc.
+   *        Zero indicates we haven't got a valid mnc length.
    *
    * @return An object contains the parsing result of mcc and mnc.
    *         Or null if any error occurred.
    */
   parseMccMncFromImsi: function(imsi, mncLength) {
     if (!imsi) {
       return null;
     }
--- a/dom/system/gonk/tests/test_ril_worker_icc.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc.js
@@ -2499,17 +2499,17 @@ add_test(function test_reading_ad_and_pa
   let buf    = context.Buf;
   let io     = context.ICCIOHelper;
 
   function do_test(mncLengthInEf, imsi, expectedMcc, expectedMnc) {
     ril.iccInfoPrivate.imsi = imsi;
 
     io.loadTransparentEF = function fakeLoadTransparentEF(options) {
       let ad = [0x00, 0x00, 0x00];
-      if (mncLengthInEf) {
+      if (typeof mncLengthInEf === 'number') {
         ad.push(mncLengthInEf);
       }
 
       // Write data size
       buf.writeInt32(ad.length * 2);
 
       // Write data
       for (let i = 0; i < ad.length; i++) {
@@ -2526,19 +2526,30 @@ add_test(function test_reading_ad_and_pa
 
     record.readAD();
 
     do_check_eq(ril.iccInfo.mcc, expectedMcc);
     do_check_eq(ril.iccInfo.mnc, expectedMnc);
   }
 
   do_test(undefined, "466923202422409", "466", "92" );
+  do_test(0x00,      "466923202422409", "466", "92" );
+  do_test(0x01,      "466923202422409", "466", "92" );
+  do_test(0x02,      "466923202422409", "466", "92" );
   do_test(0x03,      "466923202422409", "466", "923");
+  do_test(0x04,      "466923202422409", "466", "92" );
+  do_test(0xff,      "466923202422409", "466", "92" );
+
   do_test(undefined, "310260542718417", "310", "260");
+  do_test(0x00,      "310260542718417", "310", "260");
+  do_test(0x01,      "310260542718417", "310", "260");
   do_test(0x02,      "310260542718417", "310", "26" );
+  do_test(0x03,      "310260542718417", "310", "260");
+  do_test(0x04,      "310260542718417", "310", "260");
+  do_test(0xff,      "310260542718417", "310", "260");
 
   run_next_test();
 });
 
 add_test(function test_reading_optional_efs() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let record = context.SimRecordHelper;
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -71,17 +71,17 @@ public:
     MOZ_ASSERT(mTelephony);
   }
 
   virtual ~Callback() {}
 
   NS_IMETHODIMP
   NotifyDialError(const nsAString& aError)
   {
-    mPromise->MaybeReject(aError);
+    mPromise->MaybeRejectBrokenly(aError);
     return NS_OK;
   }
 
   NS_IMETHODIMP
   NotifyDialSuccess(uint32_t aCallIndex)
   {
     nsRefPtr<TelephonyCall> call =
       mTelephony->CreateNewDialingCall(mServiceId, mNumber, aCallIndex);
@@ -250,31 +250,31 @@ Telephony::DialInternal(uint32_t aServic
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
   if (!global) {
     return nullptr;
   }
 
   nsRefPtr<Promise> promise = new Promise(global);
 
   if (!IsValidNumber(aNumber) || !IsValidServiceId(aServiceId)) {
-    promise->MaybeReject(NS_LITERAL_STRING("InvalidAccessError"));
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return promise.forget();
   }
 
   // We only support one outgoing call at a time.
   if (HasDialingCall()) {
-    promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     return promise.forget();
   }
 
   nsCOMPtr<nsITelephonyCallback> callback =
     new Callback(this, promise, aServiceId, aNumber);
   nsresult rv = mService->Dial(aServiceId, aNumber, aIsEmergency, callback);
   if (NS_FAILED(rv)) {
-    promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     return promise.forget();
   }
 
   return promise.forget();
 }
 
 already_AddRefed<TelephonyCall>
 Telephony::CreateNewDialingCall(uint32_t aServiceId, const nsAString& aNumber,
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -1,24 +1,26 @@
 [DEFAULT]
 support-files =
   inert_style.css
 
 [test_bug900724.html]
+[test_bug1017896.html]
 [test_content_element.html]
 [test_nested_content_element.html]
 [test_dest_insertion_points.html]
 [test_dest_insertion_points_shadow.html]
 [test_fallback_dest_insertion_points.html]
 [test_dynamic_content_element_matching.html]
 [test_document_register.html]
 [test_document_register_base_queue.html]
 [test_document_register_lifecycle.html]
 [test_document_register_parser.html]
 [test_document_register_stack.html]
 [test_document_shared_registry.html]
 [test_template.html]
+[test_template_xhtml.html]
 [test_shadowroot.html]
 [test_shadowroot_inert_element.html]
 [test_shadowroot_style.html]
 [test_shadowroot_style_multiple_shadow.html]
 [test_shadowroot_style_order.html]
 [test_style_fallback_content.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_bug1017896.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1017896
+-->
+<head>
+  <title>Test template element in stale document.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1017896">Bug 1017896</a>
+<div id="container"></div>
+<script>
+
+SimpleTest.waitForExplicitFinish();
+
+var frame = document.createElement("iframe");
+document.getElementById("container").appendChild(frame);
+
+var staleFrameDoc = frame.contentDocument;
+
+setTimeout(function() {
+  var v = staleFrameDoc.createElement("div");
+  v.innerHTML = "<template>Content</template>";
+  is(v.firstChild.content.childNodes.length, 1, "Template should have one child in template content.");
+  SimpleTest.finish();
+}, 0);
+
+</script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_template_xhtml.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1011831
+-->
+<head>
+  <title>Test for template 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>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1011831">Bug 1011831</a>
+<script>
+var docSrc =
+  '<!DOCTYPE html>' +
+  '<html xmlns="http://www.w3.org/1999/xhtml">' +
+    '<body>' +
+      '<template id="t">Content<span>Content</span></template>' +
+      '<div id="container"><template>One</template><div>Two</div></div>' +
+      '<template id="t2"></template>' +
+    '</body>' +
+  '</html>';
+
+var doc = (new DOMParser()).parseFromString(docSrc, 'application/xhtml+xml');
+
+var t = doc.getElementById("t");
+is(t.childNodes.length, 0, "Template should have no children.");
+is(t.content.childNodes.length, 2, "Template content should have two children, text node and a span.");
+
+// Test serialization of template element.
+is(t.innerHTML, 'Content<span xmlns="http://www.w3.org/1999/xhtml">Content</span>', "Template contents should be serialized.");
+is(t.outerHTML, '<template xmlns="http://www.w3.org/1999/xhtml" id="t">Content<span>Content</span></template>', "Template contents should be serialized.");
+
+var c = doc.getElementById("container");
+is(c.innerHTML, '<template xmlns="http://www.w3.org/1999/xhtml">One</template><div xmlns="http://www.w3.org/1999/xhtml">Two</div>', "Template contents should be serialized.");
+is(c.outerHTML, '<div xmlns="http://www.w3.org/1999/xhtml" id="container"><template>One</template><div>Two</div></div>', "Template contents should be serialized.");
+
+// Test setting innerHTML on template element.
+var t2 = doc.getElementById("t2");
+t2.innerHTML = 'Three<span>Four</span>';
+is(t2.childNodes.length, 0, "Setting innerHTML should append children into template content.");
+is(t2.content.childNodes.length, 2, "Setting innerHTML should append children into template content.");
+
+</script>
+</body>
+</html>
--- a/dom/webidl/AudioNode.webidl
+++ b/dom/webidl/AudioNode.webidl
@@ -38,8 +38,14 @@ interface AudioNode : EventTarget {
     [SetterThrows]
     attribute unsigned long channelCount;
     [SetterThrows]
     attribute ChannelCountMode channelCountMode;
     attribute ChannelInterpretation channelInterpretation;
 
 };
 
+// Mozilla extension
+partial interface AudioNode {
+  [ChromeOnly]
+  readonly attribute unsigned long id;
+};
+
--- a/dom/webidl/CSS.webidl
+++ b/dom/webidl/CSS.webidl
@@ -5,22 +5,21 @@
  *
  * The origin of this IDL file is
  * http://dev.w3.org/csswg/css3-conditional/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-[Pref="layout.css.supports-rule.enabled"]
 interface CSS {
-  [Throws, Pref="layout.css.supports-rule.enabled"]
+  [Throws]
   static boolean supports(DOMString property, DOMString value);
 
-  [Throws, Pref="layout.css.supports-rule.enabled"]
+  [Throws]
   static boolean supports(DOMString conditionText);
 };
 
 // http://dev.w3.org/csswg/cssom/#the-css.escape%28%29-method
 partial interface CSS {
   [Throws]
   static DOMString escape(DOMString ident);
 };
--- a/editor/libeditor/base/ChangeAttributeTxn.cpp
+++ b/editor/libeditor/base/ChangeAttributeTxn.cpp
@@ -2,105 +2,99 @@
 /* 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 "ChangeAttributeTxn.h"
 #include "nsAString.h"
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsError.h"                    // for NS_ERROR_NOT_INITIALIZED, etc
-#include "nsEditor.h"                   // for nsEditor
+#include "nsIDOMElement.h"              // for nsIDOMElement
+#include "nsIEditor.h"                  // for nsIEditor
 #include "nsString.h"                   // for nsString
-#include "mozilla/dom/Element.h"
-
-using namespace mozilla;
 
 ChangeAttributeTxn::ChangeAttributeTxn()
   : EditTxn()
 {
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ChangeAttributeTxn, EditTxn,
                                    mElement)
 
 NS_IMPL_ADDREF_INHERITED(ChangeAttributeTxn, EditTxn)
 NS_IMPL_RELEASE_INHERITED(ChangeAttributeTxn, EditTxn)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ChangeAttributeTxn)
 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
 
-NS_IMETHODIMP ChangeAttributeTxn::Init(nsEditor      *aEditor,
-                                       dom::Element *aElement,
+NS_IMETHODIMP ChangeAttributeTxn::Init(nsIEditor      *aEditor,
+                                       nsIDOMElement  *aElement,
                                        const nsAString& aAttribute,
                                        const nsAString& aValue,
                                        bool aRemoveAttribute)
 {
   NS_ASSERTION(aEditor && aElement, "bad arg");
   if (!aEditor || !aElement) { return NS_ERROR_NULL_POINTER; }
 
   mEditor = aEditor;
-  mElement = aElement;
+  mElement = do_QueryInterface(aElement);
   mAttribute = aAttribute;
   mValue = aValue;
   mRemoveAttribute = aRemoveAttribute;
   mAttributeWasSet=false;
   mUndoValue.Truncate();
   return NS_OK;
 }
 
 NS_IMETHODIMP ChangeAttributeTxn::DoTransaction(void)
 {
   NS_ASSERTION(mEditor && mElement, "bad state");
   if (!mEditor || !mElement) { return NS_ERROR_NOT_INITIALIZED; }
 
-  nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mElement);
   // need to get the current value of the attribute and save it, and set mAttributeWasSet
-  nsresult result = mEditor->GetAttributeValue(element, mAttribute, mUndoValue, &mAttributeWasSet);
-  NS_ENSURE_SUCCESS(result, result);
-
+  nsresult result = mEditor->GetAttributeValue(mElement, mAttribute, mUndoValue, &mAttributeWasSet);
   // XXX: hack until attribute-was-set code is implemented
   if (!mUndoValue.IsEmpty())
     mAttributeWasSet = true;
   // XXX: end hack
-
-  ErrorResult rv;
+  
   // now set the attribute to the new value
   if (!mRemoveAttribute)
-    mElement->SetAttribute(mAttribute, mValue, rv);
+    result = mElement->SetAttribute(mAttribute, mValue);
   else
-    mElement->RemoveAttribute(mAttribute, rv);
+    result = mElement->RemoveAttribute(mAttribute);
 
-  return rv.ErrorCode();
+  return result;
 }
 
 NS_IMETHODIMP ChangeAttributeTxn::UndoTransaction(void)
 {
   NS_ASSERTION(mEditor && mElement, "bad state");
   if (!mEditor || !mElement) { return NS_ERROR_NOT_INITIALIZED; }
 
-  ErrorResult rv;
+  nsresult result;
   if (mAttributeWasSet)
-    mElement->SetAttribute(mAttribute, mUndoValue, rv);
+    result = mElement->SetAttribute(mAttribute, mUndoValue);
   else
-    mElement->RemoveAttribute(mAttribute, rv);
+    result = mElement->RemoveAttribute(mAttribute);
 
-  return rv.ErrorCode();
+  return result;
 }
 
 NS_IMETHODIMP ChangeAttributeTxn::RedoTransaction(void)
 {
   NS_ASSERTION(mEditor && mElement, "bad state");
   if (!mEditor || !mElement) { return NS_ERROR_NOT_INITIALIZED; }
 
-  ErrorResult rv;
+  nsresult result;
   if (!mRemoveAttribute)
-    mElement->SetAttribute(mAttribute, mValue, rv);
+    result = mElement->SetAttribute(mAttribute, mValue);
   else
-    mElement->RemoveAttribute(mAttribute, rv);
+    result = mElement->RemoveAttribute(mAttribute);
 
-  return rv.ErrorCode();
+  return result;
 }
 
 NS_IMETHODIMP ChangeAttributeTxn::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("ChangeAttributeTxn: [mRemoveAttribute == ");
 
   if (!mRemoveAttribute)
     aString.AppendLiteral("false] ");
--- a/editor/libeditor/base/ChangeAttributeTxn.h
+++ b/editor/libeditor/base/ChangeAttributeTxn.h
@@ -4,65 +4,60 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ChangeAttributeTxn_h__
 #define ChangeAttributeTxn_h__
 
 #include "EditTxn.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIDOMElement.h"
 #include "nsISupportsImpl.h"
 #include "nsString.h"
 #include "nscore.h"
 
-class nsEditor;
-
-namespace mozilla {
-namespace dom {
-class Element;
-}
-}
+class nsIEditor;
 
 /**
- * A transaction that changes an attribute of a content node.
+ * A transaction that changes an attribute of a content node. 
  * This transaction covers add, remove, and change attribute.
  */
 class ChangeAttributeTxn : public EditTxn
 {
 public:
   /** Initialize the transaction.
     * @param aEditor the object providing core editing operations
     * @param aNode   the node whose attribute will be changed
     * @param aAttribute the name of the attribute to change
     * @param aValue     the new value for aAttribute, if aRemoveAttribute is false
     * @param aRemoveAttribute if true, remove aAttribute from aNode
     */
-  NS_IMETHOD Init(nsEditor      *aEditor,
-                  mozilla::dom::Element *aNode,
+  NS_IMETHOD Init(nsIEditor      *aEditor,
+                  nsIDOMElement  *aNode,
                   const nsAString& aAttribute,
                   const nsAString& aValue,
                   bool aRemoveAttribute);
 
   ChangeAttributeTxn();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ChangeAttributeTxn, EditTxn)
 
   NS_DECL_EDITTXN
 
   NS_IMETHOD RedoTransaction();
 
 protected:
 
   /** the editor that created this transaction */
-  nsEditor*  mEditor;
-
+  nsIEditor*  mEditor;
+  
   /** the element to operate upon */
-  nsCOMPtr<mozilla::dom::Element> mElement;
-
+  nsCOMPtr<nsIDOMElement> mElement;
+  
   /** the attribute to change */
   nsString mAttribute;
 
   /** the value to set the attribute to (ignored if mRemoveAttribute==true) */
   nsString mValue;
 
   /** the value to set the attribute to for undo */
   nsString mUndoValue;
--- a/editor/libeditor/base/CreateElementTxn.cpp
+++ b/editor/libeditor/base/CreateElementTxn.cpp
@@ -8,16 +8,17 @@
 #include "CreateElementTxn.h"
 #include "mozilla/dom/Element.h"
 #include "nsAlgorithm.h"
 #include "nsDebug.h"
 #include "nsEditor.h"
 #include "nsError.h"
 #include "nsIContent.h"
 #include "nsIDOMCharacterData.h"
+#include "nsIEditor.h"
 #include "nsINode.h"
 #include "nsISelection.h"
 #include "nsISupportsUtils.h"
 #include "nsMemory.h"
 #include "nsReadableUtils.h"
 #include "nsStringFwd.h"
 #include "nsString.h"
 #include "nsAString.h"
@@ -37,17 +38,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Creat
                                    mRefNode)
 
 NS_IMPL_ADDREF_INHERITED(CreateElementTxn, EditTxn)
 NS_IMPL_RELEASE_INHERITED(CreateElementTxn, EditTxn)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CreateElementTxn)
 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
 NS_IMETHODIMP CreateElementTxn::Init(nsEditor      *aEditor,
                                      const nsAString &aTag,
-                                     nsINode       *aParent,
+                                     nsIDOMNode     *aParent,
                                      uint32_t        aOffsetInParent)
 {
   NS_ASSERTION(aEditor&&aParent, "null args");
   if (!aEditor || !aParent) { return NS_ERROR_NULL_POINTER; }
 
   mEditor = aEditor;
   mTag = aTag;
   mParent = do_QueryInterface(aParent);
@@ -61,45 +62,49 @@ NS_IMETHODIMP CreateElementTxn::DoTransa
   NS_ASSERTION(mEditor && mParent, "bad state");
   NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
 
   ErrorResult rv;
   nsCOMPtr<Element> newContent = mEditor->CreateHTMLContent(mTag, rv);
   NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
   NS_ENSURE_STATE(newContent);
 
-  mNewNode = newContent;
+  mNewNode = newContent->AsDOMNode();
   // Try to insert formatting whitespace for the new node:
   mEditor->MarkNodeDirty(mNewNode);
 
   // insert the new node
   if (CreateElementTxn::eAppend == int32_t(mOffsetInParent)) {
-    mParent->AppendChild(*mNewNode, rv);
-    return rv.ErrorCode();
+    nsCOMPtr<nsIDOMNode> resultNode;
+    return mParent->AppendChild(mNewNode, getter_AddRefs(resultNode));
   }
 
+  nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
+  NS_ENSURE_STATE(parent);
 
-  mOffsetInParent = std::min(mOffsetInParent, mParent->GetChildCount());
+  mOffsetInParent = std::min(mOffsetInParent, parent->GetChildCount());
 
   // note, it's ok for mRefNode to be null.  that means append
-  mRefNode = mParent->GetChildAt(mOffsetInParent);
+  nsIContent* refNode = parent->GetChildAt(mOffsetInParent);
+  mRefNode = refNode ? refNode->AsDOMNode() : nullptr;
 
-  mParent->InsertBefore(*mNewNode, mRefNode, rv);
-  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
+  nsCOMPtr<nsIDOMNode> resultNode;
+  nsresult result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
+  NS_ENSURE_SUCCESS(result, result); 
 
   // only set selection to insertion point if editor gives permission
   bool bAdjustSelection;
   mEditor->ShouldTxnSetSelection(&bAdjustSelection);
   if (!bAdjustSelection) {
     // do nothing - dom range gravity will adjust selection
     return NS_OK;
   }
 
   nsCOMPtr<nsISelection> selection;
-  nsresult result = mEditor->GetSelection(getter_AddRefs(selection));
+  result = mEditor->GetSelection(getter_AddRefs(selection));
   NS_ENSURE_SUCCESS(result, result);
   NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIContent> parentContent = do_QueryInterface(mParent);
   NS_ENSURE_STATE(parentContent);
 
   result = selection->CollapseNative(parentContent,
                                      parentContent->IndexOf(newContent) + 1);
@@ -107,46 +112,44 @@ NS_IMETHODIMP CreateElementTxn::DoTransa
   return result;
 }
 
 NS_IMETHODIMP CreateElementTxn::UndoTransaction(void)
 {
   NS_ASSERTION(mEditor && mParent, "bad state");
   NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
 
-  ErrorResult rv;
-  mParent->RemoveChild(*mNewNode, rv);
-  return rv.ErrorCode();
+  nsCOMPtr<nsIDOMNode> resultNode;
+  return mParent->RemoveChild(mNewNode, getter_AddRefs(resultNode));
 }
 
 NS_IMETHODIMP CreateElementTxn::RedoTransaction(void)
 {
   NS_ASSERTION(mEditor && mParent, "bad state");
   NS_ENSURE_TRUE(mEditor && mParent, NS_ERROR_NOT_INITIALIZED);
 
   // first, reset mNewNode so it has no attributes or content
   nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(mNewNode);
   if (nodeAsText)
   {
     nodeAsText->SetData(EmptyString());
   }
-
+  
   // now, reinsert mNewNode
-  ErrorResult rv;
-  mParent->InsertBefore(*mNewNode, mRefNode, rv);
-  return rv.ErrorCode();
+  nsCOMPtr<nsIDOMNode> resultNode;
+  return mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
 }
 
 NS_IMETHODIMP CreateElementTxn::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("CreateElementTxn: ");
   aString += mTag;
   return NS_OK;
 }
 
-NS_IMETHODIMP CreateElementTxn::GetNewNode(nsINode **aNewNode)
+NS_IMETHODIMP CreateElementTxn::GetNewNode(nsIDOMNode **aNewNode)
 {
   NS_ENSURE_TRUE(aNewNode, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(mNewNode, NS_ERROR_NOT_INITIALIZED);
   *aNewNode = mNewNode;
   NS_ADDREF(*aNewNode);
   return NS_OK;
 }
--- a/editor/libeditor/base/CreateElementTxn.h
+++ b/editor/libeditor/base/CreateElementTxn.h
@@ -4,22 +4,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CreateElementTxn_h__
 #define CreateElementTxn_h__
 
 #include "EditTxn.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIDOMNode.h"
 #include "nsISupportsImpl.h"
 #include "nsString.h"
 #include "nscore.h"
 
 class nsEditor;
-class nsINode;
 
 /**
  * A transaction that creates a new node in the content tree.
  */
 class CreateElementTxn : public EditTxn
 {
 public:
   enum { eAppend=-1 };
@@ -28,44 +28,44 @@ public:
     * @param aEditor the provider of basic editing functionality
     * @param aTag    the tag (P, HR, TABLE, etc.) for the new element
     * @param aParent the node into which the new element will be inserted
     * @param aOffsetInParent the location in aParent to insert the new element
     *                        if eAppend, the new element is appended as the last child
     */
   NS_IMETHOD Init(nsEditor *aEditor,
                   const nsAString& aTag,
-                  nsINode *aParent,
+                  nsIDOMNode *aParent,
                   uint32_t aOffsetInParent);
 
   CreateElementTxn();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CreateElementTxn, EditTxn)
 
   NS_DECL_EDITTXN
 
   NS_IMETHOD RedoTransaction();
 
-  NS_IMETHOD GetNewNode(nsINode **aNewNode);
+  NS_IMETHOD GetNewNode(nsIDOMNode **aNewNode);
 
 protected:
-
+  
   /** the document into which the new node will be inserted */
   nsEditor* mEditor;
-
+  
   /** the tag (mapping to object type) for the new element */
   nsString mTag;
 
   /** the node into which the new node will be inserted */
-  nsCOMPtr<nsINode> mParent;
+  nsCOMPtr<nsIDOMNode> mParent;
 
   /** the index in mParent for the new node */
   uint32_t mOffsetInParent;
 
   /** the new node to insert */
-  nsCOMPtr<nsINode> mNewNode;
+  nsCOMPtr<nsIDOMNode> mNewNode;  
 
   /** the node we will insert mNewNode before.  We compute this ourselves. */
-  nsCOMPtr<nsINode> mRefNode;
+  nsCOMPtr<nsIDOMNode> mRefNode;
 };
 
 #endif
--- a/editor/libeditor/base/InsertElementTxn.cpp
+++ b/editor/libeditor/base/InsertElementTxn.cpp
@@ -28,20 +28,20 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Inser
                                    mNode,
                                    mParent)
 
 NS_IMPL_ADDREF_INHERITED(InsertElementTxn, EditTxn)
 NS_IMPL_RELEASE_INHERITED(InsertElementTxn, EditTxn)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(InsertElementTxn)
 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
 
-NS_IMETHODIMP InsertElementTxn::Init(nsINode *aNode,
-                                     nsINode *aParent,
+NS_IMETHODIMP InsertElementTxn::Init(nsIDOMNode *aNode,
+                                     nsIDOMNode *aParent,
                                      int32_t     aOffset,
-                                     nsEditor  *aEditor)
+                                     nsIEditor  *aEditor)
 {
   NS_ASSERTION(aNode && aParent && aEditor, "bad arg");
   NS_ENSURE_TRUE(aNode && aParent && aEditor, NS_ERROR_NULL_POINTER);
 
   mNode = do_QueryInterface(aNode);
   mParent = do_QueryInterface(aParent);
   mOffset = aOffset;
   mEditor = aEditor;
@@ -60,48 +60,49 @@ NS_IMETHODIMP InsertElementTxn::DoTransa
   uint32_t count = parent->GetChildCount();
   if (mOffset > int32_t(count) || mOffset == -1) {
     // -1 is sentinel value meaning "append at end"
     mOffset = count;
   }
 
   // note, it's ok for refContent to be null.  that means append
   nsCOMPtr<nsIContent> refContent = parent->GetChildAt(mOffset);
+  nsCOMPtr<nsIDOMNode> refNode = refContent ? refContent->AsDOMNode() : nullptr;
 
   mEditor->MarkNodeDirty(mNode);
 
-  ErrorResult rv;
-  mParent->InsertBefore(*mNode, refContent, rv);
-  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
+  nsCOMPtr<nsIDOMNode> resultNode;
+  nsresult result = mParent->InsertBefore(mNode, refNode, getter_AddRefs(resultNode));
+  NS_ENSURE_SUCCESS(result, result);
+  NS_ENSURE_TRUE(resultNode, NS_ERROR_NULL_POINTER);
 
   // only set selection to insertion point if editor gives permission
   bool bAdjustSelection;
   mEditor->ShouldTxnSetSelection(&bAdjustSelection);
   if (bAdjustSelection)
   {
     nsCOMPtr<nsISelection> selection;
-    rv = mEditor->GetSelection(getter_AddRefs(selection));
-    NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
+    result = mEditor->GetSelection(getter_AddRefs(selection));
+    NS_ENSURE_SUCCESS(result, result);
     NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
     // place the selection just after the inserted element
-    selection->Collapse(mParent->AsDOMNode(), mOffset+1);
+    selection->Collapse(mParent, mOffset+1);
   }
   else
   {
     // do nothing - dom range gravity will adjust selection
   }
-  return NS_OK;
+  return result;
 }
 
 NS_IMETHODIMP InsertElementTxn::UndoTransaction(void)
 {
   NS_ENSURE_TRUE(mNode && mParent, NS_ERROR_NOT_INITIALIZED);
 
-  ErrorResult rv;
-  mParent->RemoveChild(*mNode, rv);
-  return rv.ErrorCode();
+  nsCOMPtr<nsIDOMNode> resultNode;
+  return mParent->RemoveChild(mNode, getter_AddRefs(resultNode));
 }
 
 NS_IMETHODIMP InsertElementTxn::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("InsertElementTxn");
   return NS_OK;
 }
--- a/editor/libeditor/base/InsertElementTxn.h
+++ b/editor/libeditor/base/InsertElementTxn.h
@@ -4,53 +4,53 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef InsertElementTxn_h__
 #define InsertElementTxn_h__
 
 #include "EditTxn.h"                    // for EditTxn, NS_DECL_EDITTXN
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsCycleCollectionParticipant.h"
+#include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nsISupportsImpl.h"            // for NS_DECL_ISUPPORTS_INHERITED
 #include "nscore.h"                     // for NS_IMETHOD
 
-class nsEditor;
-class nsINode;
+class nsIEditor;
 
 /**
  * A transaction that inserts a single element
  */
 class InsertElementTxn : public EditTxn
 {
 public:
   /** initialize the transaction.
     * @param aNode   the node to insert
     * @param aParent the node to insert into
     * @param aOffset the offset in aParent to insert aNode
     */
-  NS_IMETHOD Init(nsINode *aNode,
-                  nsINode *aParent,
+  NS_IMETHOD Init(nsIDOMNode *aNode,
+                  nsIDOMNode *aParent,
                   int32_t     aOffset,
-                  nsEditor  *aEditor);
+                  nsIEditor  *aEditor);
 
   InsertElementTxn();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(InsertElementTxn, EditTxn)
 
   NS_DECL_EDITTXN
 
 protected:
-
+  
   /** the element to insert */
-  nsCOMPtr<nsINode> mNode;
+  nsCOMPtr<nsIDOMNode> mNode;
 
   /** the node into which the new node will be inserted */
-  nsCOMPtr<nsINode> mParent;
+  nsCOMPtr<nsIDOMNode> mParent;
 
   /** the editor for this transaction */
-  nsEditor*           mEditor;
+  nsIEditor*           mEditor;
 
   /** the index in mParent for the new node */
   int32_t mOffset;
 };
 
 #endif
--- a/editor/libeditor/base/JoinElementTxn.cpp
+++ b/editor/libeditor/base/JoinElementTxn.cpp
@@ -26,85 +26,95 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinE
                                    mLeftNode,
                                    mRightNode,
                                    mParent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinElementTxn)
 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
 
 NS_IMETHODIMP JoinElementTxn::Init(nsEditor   *aEditor,
-                                   nsINode *aLeftNode,
-                                   nsINode *aRightNode)
+                                   nsIDOMNode *aLeftNode,
+                                   nsIDOMNode *aRightNode)
 {
   NS_PRECONDITION((aEditor && aLeftNode && aRightNode), "null arg");
   if (!aEditor || !aLeftNode || !aRightNode) { return NS_ERROR_NULL_POINTER; }
   mEditor = aEditor;
-  mLeftNode = aLeftNode;
-  nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode();
+  mLeftNode = do_QueryInterface(aLeftNode);
+  nsCOMPtr<nsIDOMNode>leftParent;
+  nsresult result = mLeftNode->GetParentNode(getter_AddRefs(leftParent));
+  NS_ENSURE_SUCCESS(result, result);
   if (!mEditor->IsModifiableNode(leftParent)) {
     return NS_ERROR_FAILURE;
   }
-  mRightNode = aRightNode;
+  mRightNode = do_QueryInterface(aRightNode);
   mOffset = 0;
   return NS_OK;
 }
 
 // After DoTransaction() and RedoTransaction(), the left node is removed from the content tree and right node remains.
 NS_IMETHODIMP JoinElementTxn::DoTransaction(void)
 {
   NS_PRECONDITION((mEditor && mLeftNode && mRightNode), "null arg");
   if (!mEditor || !mLeftNode || !mRightNode) { return NS_ERROR_NOT_INITIALIZED; }
 
   // get the parent node
-  nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode();
+  nsCOMPtr<nsINode> leftNode = do_QueryInterface(mLeftNode);
+  nsCOMPtr<nsINode> leftParent = leftNode->GetParentNode();
   NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER);
 
   // verify that mLeftNode and mRightNode have the same parent
-  nsCOMPtr<nsINode> rightParent = mRightNode->GetParentNode();
+  nsCOMPtr<nsINode> rightNode = do_QueryInterface(mRightNode);
+  nsCOMPtr<nsINode> rightParent = rightNode->GetParentNode();
   NS_ENSURE_TRUE(rightParent, NS_ERROR_NULL_POINTER);
 
   if (leftParent != rightParent) {
     NS_ASSERTION(false, "2 nodes do not have same parent");
     return NS_ERROR_INVALID_ARG;
   }
 
   // set this instance mParent. 
   // Other methods will see a non-null mParent and know all is well
-  mParent = leftParent;
-  mOffset = mLeftNode->Length();
+  mParent = leftParent->AsDOMNode();
+  mOffset = leftNode->Length();
 
-  return mEditor->JoinNodesImpl(mRightNode, mLeftNode, mParent);
+  nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
+  return mEditor->JoinNodesImpl(rightNode, leftNode, parent);
 }
 
 //XXX: what if instead of split, we just deleted the unneeded children of mRight
 //     and re-inserted mLeft?
 NS_IMETHODIMP JoinElementTxn::UndoTransaction(void)
 {
   NS_ASSERTION(mRightNode && mLeftNode && mParent, "bad state");
   if (!mRightNode || !mLeftNode || !mParent) { return NS_ERROR_NOT_INITIALIZED; }
   // first, massage the existing node so it is in its post-split state
+  nsresult result;
+  nsCOMPtr<nsIDOMNode>resultNode;
   nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mRightNode);
-  ErrorResult rv;
   if (rightNodeAsText)
   {
-    rv = rightNodeAsText->DeleteData(0, mOffset);
-    NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
+    result = rightNodeAsText->DeleteData(0, mOffset);
   }
   else
   {
-    for (nsCOMPtr<nsINode> child = mRightNode->GetFirstChild();
-         child;
-         child = child->GetNextSibling())
+    nsCOMPtr<nsIDOMNode>child;
+    result = mRightNode->GetFirstChild(getter_AddRefs(child));
+    nsCOMPtr<nsIDOMNode>nextSibling;
+    uint32_t i;
+    for (i=0; i<mOffset; i++)
     {
-      mLeftNode->AppendChild(*child, rv);
-      NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
+      if (NS_FAILED(result)) {return result;}
+      if (!child) {return NS_ERROR_NULL_POINTER;}
+      child->GetNextSibling(getter_AddRefs(nextSibling));
+      result = mLeftNode->AppendChild(child, getter_AddRefs(resultNode));
+      child = do_QueryInterface(nextSibling);
     }
   }
   // second, re-insert the left node into the tree
-  mParent->InsertBefore(*mLeftNode, mRightNode, rv);
-  return rv.ErrorCode();
+  result = mParent->InsertBefore(mLeftNode, mRightNode, getter_AddRefs(resultNode));
+  return result;
 }
 
 NS_IMETHODIMP JoinElementTxn::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("JoinElementTxn");
   return NS_OK;
 }
--- a/editor/libeditor/base/JoinElementTxn.h
+++ b/editor/libeditor/base/JoinElementTxn.h
@@ -5,59 +5,59 @@
 
 #ifndef JoinElementTxn_h__
 #define JoinElementTxn_h__
 
 #include "EditTxn.h"                    // for EditTxn, NS_DECL_EDITTXN
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsCycleCollectionParticipant.h"
 #include "nsID.h"                       // for REFNSIID
+#include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nscore.h"                     // for NS_IMETHOD
 
 class nsEditor;
-class nsINode;
 
 /**
  * A transaction that joins two elements E1 (left node) and E2 (right node)
- * into a single node E.
+ * into a single node E.  
  * The children of E are the children of E1 followed by the children of E2.
  * After DoTransaction() and RedoTransaction(), E1 is removed from the content
  * tree and E2 remains.
  */
 class JoinElementTxn : public EditTxn
 {
 public:
   /** initialize the transaction
     * @param aEditor    the provider of core editing operations
     * @param aLeftNode  the first of two nodes to join
     * @param aRightNode the second of two nodes to join
     */
   NS_IMETHOD Init(nsEditor   *aEditor,
-                  nsINode    *aLeftNode,
-                  nsINode    *aRightNode);
+                  nsIDOMNode *aLeftNode,
+                  nsIDOMNode *aRightNode);
 
   JoinElementTxn();
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(JoinElementTxn, EditTxn)
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
 
   NS_DECL_EDITTXN
 
 protected:
-
-  /** the elements to operate upon.
+  
+  /** the elements to operate upon.  
     * After the merge, mRightNode remains and mLeftNode is removed from the content tree.
     */
-  nsCOMPtr<nsINode> mLeftNode;
-  nsCOMPtr<nsINode> mRightNode;
+  nsCOMPtr<nsIDOMNode> mLeftNode;
+  nsCOMPtr<nsIDOMNode> mRightNode;
 
   /** the offset into mNode where the children of mElement are split (for undo).<BR>
-    * mOffset is the index of the first child in the right node.
+    * mOffset is the index of the first child in the right node. 
     * -1 means the left node had no children.
     */
   uint32_t  mOffset;
 
   /** the parent node containing mLeftNode and mRightNode */
-  nsCOMPtr<nsINode> mParent;
+  nsCOMPtr<nsIDOMNode> mParent;
   nsEditor*  mEditor;
 };
 
 #endif
--- a/editor/libeditor/base/SplitElementTxn.cpp
+++ b/editor/libeditor/base/SplitElementTxn.cpp
@@ -29,17 +29,17 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(Split
                                    mNewLeftNode)
 
 NS_IMPL_ADDREF_INHERITED(SplitElementTxn, EditTxn)
 NS_IMPL_RELEASE_INHERITED(SplitElementTxn, EditTxn)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SplitElementTxn)
 NS_INTERFACE_MAP_END_INHERITING(EditTxn)
 
 NS_IMETHODIMP SplitElementTxn::Init(nsEditor   *aEditor,
-                                    nsINode    *aNode,
+                                    nsIDOMNode *aNode,
                                     int32_t     aOffset)
 {
   NS_ASSERTION(aEditor && aNode, "bad args");
   if (!aEditor || !aNode) { return NS_ERROR_NOT_INITIALIZED; }
 
   mEditor = aEditor;
   mExistingRightNode = do_QueryInterface(aNode);
   mOffset = aOffset;
@@ -47,43 +47,38 @@ NS_IMETHODIMP SplitElementTxn::Init(nsEd
 }
 
 NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
 {
   NS_ASSERTION(mExistingRightNode && mEditor, "bad state");
   if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
 
   // create a new node
-  ErrorResult rv;
-  mNewLeftNode = mExistingRightNode->CloneNode(false, rv);
-  NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
-  NS_ASSERTION(mNewLeftNode, "could not create element.");
-  NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER);
+  nsresult result = mExistingRightNode->CloneNode(false, 1, getter_AddRefs(mNewLeftNode));
+  NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
+  NS_ENSURE_SUCCESS(result, result);
   mEditor->MarkNodeDirty(mExistingRightNode);
 
   // get the parent node
-  mParent = mExistingRightNode->GetParentNode();
+  result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent));
+  NS_ENSURE_SUCCESS(result, result);
   NS_ENSURE_TRUE(mParent, NS_ERROR_NULL_POINTER);
 
   // insert the new node
-  nsresult result = mEditor->SplitNodeImpl(mExistingRightNode->AsDOMNode(),
-                                           mOffset,
-                                           mNewLeftNode->AsDOMNode(),
-                                           mParent->AsDOMNode());
-  NS_ENSURE_SUCCESS(result, result);
+  result = mEditor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent);
   if (mNewLeftNode) {
     bool bAdjustSelection;
     mEditor->ShouldTxnSetSelection(&bAdjustSelection);
     if (bAdjustSelection)
     {
       nsCOMPtr<nsISelection> selection;
       result = mEditor->GetSelection(getter_AddRefs(selection));
       NS_ENSURE_SUCCESS(result, result);
       NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
-      result = selection->Collapse(mNewLeftNode->AsDOMNode(), mOffset);
+      result = selection->Collapse(mNewLeftNode, mOffset);
     }
     else
     {
       // do nothing - dom range gravity will adjust selection
     }
   }
   return result;
 }
@@ -91,65 +86,72 @@ NS_IMETHODIMP SplitElementTxn::DoTransac
 NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
 {
   NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
   if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   // this assumes Do inserted the new node in front of the prior existing node
-  return mEditor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent);
+  nsCOMPtr<nsINode> right = do_QueryInterface(mExistingRightNode);
+  nsCOMPtr<nsINode> left = do_QueryInterface(mNewLeftNode);
+  nsCOMPtr<nsINode> parent = do_QueryInterface(mParent);
+  return mEditor->JoinNodesImpl(right, left, parent);
 }
 
 /* redo cannot simply resplit the right node, because subsequent transactions
  * on the redo stack may depend on the left node existing in its previous state.
  */
 NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
 {
   NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
   if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
+  nsresult result;
+  nsCOMPtr<nsIDOMNode>resultNode;
   // first, massage the existing node so it is in its post-split state
   nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mExistingRightNode);
   if (rightNodeAsText)
   {
     nsresult result = rightNodeAsText->DeleteData(0, mOffset);
     NS_ENSURE_SUCCESS(result, result);
   }
   else
   {
-    nsCOMPtr<nsINode> child = mExistingRightNode->GetFirstChild();
-    for (int32_t i=0; i<mOffset; i++)
+    nsCOMPtr<nsIDOMNode>child;
+    nsCOMPtr<nsIDOMNode>nextSibling;
+    result = mExistingRightNode->GetFirstChild(getter_AddRefs(child));
+    int32_t i;
+    for (i=0; i<mOffset; i++)
     {
+      if (NS_FAILED(result)) {return result;}
       if (!child) {return NS_ERROR_NULL_POINTER;}
-      ErrorResult rv;
-      mExistingRightNode->RemoveChild(*child, rv);
-      if (NS_SUCCEEDED(rv.ErrorCode()))
+      child->GetNextSibling(getter_AddRefs(nextSibling));
+      result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode));
+      if (NS_SUCCEEDED(result))
       {
-        mNewLeftNode->AppendChild(*child, rv);
-        NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
+        result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode));
       }
-      child = child->GetNextSibling();
+      child = do_QueryInterface(nextSibling);
     }
   }
   // second, re-insert the left node into the tree
-  ErrorResult rv;
-  mParent->InsertBefore(*mNewLeftNode, mExistingRightNode, rv);
-  return rv.ErrorCode();
+  result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode));
+  return result;
 }
 
 
 NS_IMETHODIMP SplitElementTxn::GetTxnDescription(nsAString& aString)
 {
   aString.AssignLiteral("SplitElementTxn");
   return NS_OK;
 }
 
-NS_IMETHODIMP SplitElementTxn::GetNewNode(nsINode **aNewNode)
+NS_IMETHODIMP SplitElementTxn::GetNewNode(nsIDOMNode **aNewNode)
 {
   NS_ENSURE_TRUE(aNewNode, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NOT_INITIALIZED);
   *aNewNode = mNewLeftNode;
   NS_ADDREF(*aNewNode);
   return NS_OK;
 }
--- a/editor/libeditor/base/SplitElementTxn.h
+++ b/editor/libeditor/base/SplitElementTxn.h
@@ -4,63 +4,63 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef SplitElementTxn_h__
 #define SplitElementTxn_h__
 
 #include "EditTxn.h"                    // for EditTxn, NS_DECL_EDITTXN
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsCycleCollectionParticipant.h"
+#include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nsISupportsImpl.h"            // for NS_DECL_ISUPPORTS_INHERITED
 #include "nscore.h"                     // for NS_IMETHOD
 
 class nsEditor;
-class nsINode;
 
 /**
  * A transaction that splits an element E into two identical nodes, E1 and E2
  * with the children of E divided between E1 and E2.
  */
 class SplitElementTxn : public EditTxn
 {
 public:
   /** initialize the transaction.
     * @param aEditor  the provider of core editing operations
     * @param aNode    the node to split
     * @param aOffset  the location within aNode to do the split.
     *                 aOffset may refer to children of aNode, or content of aNode.
     *                 The left node will have child|content 0..aOffset-1.
     */
   NS_IMETHOD Init (nsEditor   *aEditor,
-                   nsINode *aNode,
+                   nsIDOMNode *aNode,
                    int32_t     aOffset);
 
   SplitElementTxn();
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SplitElementTxn, EditTxn)
 
   NS_DECL_EDITTXN
 
   NS_IMETHOD RedoTransaction(void);
 
-  NS_IMETHOD GetNewNode(nsINode **aNewNode);
+  NS_IMETHOD GetNewNode(nsIDOMNode **aNewNode);
 
 protected:
-
+  
   /** the element to operate upon */
-  nsCOMPtr<nsINode> mExistingRightNode;
+  nsCOMPtr<nsIDOMNode> mExistingRightNode;
 
   /** the offset into mElement where the children of mElement are split.<BR>
     * mOffset is the index of the first child in the right node. 
     * -1 means the new node gets no children.
     */
   int32_t  mOffset;
 
   /** the element we create when splitting mElement */
-  nsCOMPtr<nsINode> mNewLeftNode;
+  nsCOMPtr<nsIDOMNode> mNewLeftNode;
 
   /** the parent shared by mExistingRightNode and mNewLeftNode */
-  nsCOMPtr<nsINode> mParent;
+  nsCOMPtr<nsIDOMNode> mParent;
   nsEditor*  mEditor;
 };
 
 #endif
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -1169,25 +1169,24 @@ nsEditor::CanPaste(int32_t aSelectionTyp
 }
 
 NS_IMETHODIMP
 nsEditor::CanPasteTransferable(nsITransferable *aTransferable, bool *aCanPaste)
 {
   return NS_ERROR_NOT_IMPLEMENTED; 
 }
 
-NS_IMETHODIMP
+NS_IMETHODIMP 
 nsEditor::SetAttribute(nsIDOMElement *aElement, const nsAString & aAttribute, const nsAString & aValue)
 {
   nsRefPtr<ChangeAttributeTxn> txn;
-  nsCOMPtr<Element> element = do_QueryInterface(aElement);
-  nsresult result = CreateTxnForSetAttribute(element, aAttribute, aValue,
+  nsresult result = CreateTxnForSetAttribute(aElement, aAttribute, aValue,
                                              getter_AddRefs(txn));
   if (NS_SUCCEEDED(result))  {
-    result = DoTransaction(txn);
+    result = DoTransaction(txn);  
   }
   return result;
 }
 
 NS_IMETHODIMP 
 nsEditor::GetAttributeValue(nsIDOMElement *aElement, 
                             const nsAString & aAttribute, 
                             nsAString & aResultValue, 
@@ -1203,25 +1202,24 @@ nsEditor::GetAttributeValue(nsIDOMElemen
   NS_ENSURE_SUCCESS(rv, rv);
   if (!DOMStringIsNull(value)) {
     *aResultIsSet = true;
     aResultValue = value;
   }
   return rv;
 }
 
-NS_IMETHODIMP
+NS_IMETHODIMP 
 nsEditor::RemoveAttribute(nsIDOMElement *aElement, const nsAString& aAttribute)
 {
   nsRefPtr<ChangeAttributeTxn> txn;
-  nsCOMPtr<Element> element = do_QueryInterface(aElement);
-  nsresult result = CreateTxnForRemoveAttribute(element, aAttribute,
+  nsresult result = CreateTxnForRemoveAttribute(aElement, aAttribute,
                                                 getter_AddRefs(txn));
   if (NS_SUCCEEDED(result))  {
-    result = DoTransaction(txn);
+    result = DoTransaction(txn);  
   }
   return result;
 }
 
 
 bool
 nsEditor::OutputsMozDirty()
 {
@@ -1229,31 +1227,25 @@ nsEditor::OutputsMozDirty()
   // (eEditorMailMask), but false for webpages.
   return !(mFlags & nsIPlaintextEditor::eEditorAllowInteraction) ||
           (mFlags & nsIPlaintextEditor::eEditorMailMask);
 }
 
 
 NS_IMETHODIMP
 nsEditor::MarkNodeDirty(nsIDOMNode* aNode)
-{
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  return MarkNodeDirty(node);
-}
-
-nsresult
-nsEditor::MarkNodeDirty(nsINode* aNode)
-{
+{  
   // Mark the node dirty, but not for webpages (bug 599983)
   if (!OutputsMozDirty()) {
     return NS_OK;
   }
-  if (aNode->IsElement()) {
-    aNode->AsElement()->SetAttr(kNameSpaceID_None, nsEditProperty::mozdirty,
-                                EmptyString(), false);
+  nsCOMPtr<dom::Element> element = do_QueryInterface(aNode);
+  if (element) {
+    element->SetAttr(kNameSpaceID_None, nsEditProperty::mozdirty,
+                     EmptyString(), false);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate,
                                               nsIInlineSpellChecker ** aInlineSpellChecker)
 {
   NS_ENSURE_ARG_POINTER(aInlineSpellChecker);
@@ -1351,27 +1343,24 @@ NS_IMETHODIMP nsEditor::CreateNode(const
   int32_t i;
 
   nsAutoRules beginRulesSniffing(this, EditAction::createNode, nsIEditor::eNext);
 
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->WillCreateNode(aTag, aParent, aPosition);
 
   nsRefPtr<CreateElementTxn> txn;
-  nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
-  nsresult result = CreateTxnForCreateElement(aTag, parent, aPosition,
+  nsresult result = CreateTxnForCreateElement(aTag, aParent, aPosition,
                                               getter_AddRefs(txn));
   if (NS_SUCCEEDED(result))
   {
     result = DoTransaction(txn);
     if (NS_SUCCEEDED(result))
     {
-      nsCOMPtr<nsINode> newNode;
-      result = txn->GetNewNode(getter_AddRefs(newNode));
-      CallQueryInterface(newNode, aNewNode);
+      result = txn->GetNewNode(aNewNode);
       NS_ASSERTION((NS_SUCCEEDED(result)), "GetNewNode can't fail if txn::DoTransaction succeeded.");
     }
   }
 
   mRangeUpdater.SelAdjCreateNode(aParent, aPosition);
 
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->DidCreateNode(aTag, *aNewNode, aParent, aPosition, result);
@@ -1395,18 +1384,18 @@ NS_IMETHODIMP nsEditor::InsertNode(nsIDO
   nsAutoRules beginRulesSniffing(this, EditAction::insertNode, nsIEditor::eNext);
 
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->WillInsertNode(aNode, aParent, aPosition);
 
   nsRefPtr<InsertElementTxn> txn;
   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
   nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
-  nsresult result = CreateTxnForInsertElement(node, parent, aPosition,
-                                              getter_AddRefs(txn));
+  nsresult result = CreateTxnForInsertElement(node->AsDOMNode(), parent->AsDOMNode(),
+                                              aPosition, getter_AddRefs(txn));
   if (NS_SUCCEEDED(result))  {
     result = DoTransaction(txn);
   }
 
   mRangeUpdater.SelAdjInsertNode(aParent, aPosition);
 
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->DidInsertNode(aNode, aParent, aPosition, result);
@@ -1422,26 +1411,23 @@ nsEditor::SplitNode(nsIDOMNode * aNode,
 {
   int32_t i;
   nsAutoRules beginRulesSniffing(this, EditAction::splitNode, nsIEditor::eNext);
 
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->WillSplitNode(aNode, aOffset);
 
   nsRefPtr<SplitElementTxn> txn;
-  nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
-  nsresult result = CreateTxnForSplitNode(node, aOffset, getter_AddRefs(txn));
+  nsresult result = CreateTxnForSplitNode(aNode, aOffset, getter_AddRefs(txn));
   if (NS_SUCCEEDED(result))
   {
     result = DoTransaction(txn);
     if (NS_SUCCEEDED(result))
     {
-      nsCOMPtr<nsINode> leftNode;
-      result = txn->GetNewNode(getter_AddRefs(leftNode));
-      CallQueryInterface(leftNode, aNewLeftNode);
+      result = txn->GetNewNode(aNewLeftNode);
       NS_ASSERTION((NS_SUCCEEDED(result)), "result must succeeded for GetNewNode");
     }
   }
 
   mRangeUpdater.SelAdjSplitNode(aNode, aOffset, *aNewLeftNode);
 
   for (i = 0; i < mActionListeners.Count(); i++)
   {
@@ -1482,25 +1468,23 @@ nsEditor::JoinNodes(nsIDOMNode * aLeftNo
   uint32_t oldLeftNodeLen;
   nsresult result = GetLengthOfDOMNode(aLeftNode, oldLeftNodeLen);
   NS_ENSURE_SUCCESS(result, result);
 
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->WillJoinNodes(aLeftNode, aRightNode, aParent);
 
   nsRefPtr<JoinElementTxn> txn;
-  nsCOMPtr<nsINode> leftNode = do_QueryInterface(aLeftNode);
-  nsCOMPtr<nsINode> rightNode = do_QueryInterface(aRightNode);
-  result = CreateTxnForJoinNode(leftNode, rightNode, getter_AddRefs(txn));
+  result = CreateTxnForJoinNode(aLeftNode, aRightNode, getter_AddRefs(txn));
   if (NS_SUCCEEDED(result))  {
-    result = DoTransaction(txn);
+    result = DoTransaction(txn);  
   }
 
   mRangeUpdater.SelAdjJoinNodes(aLeftNode, aRightNode, aParent, offset, (int32_t)oldLeftNodeLen);
-
+  
   for (i = 0; i < mActionListeners.Count(); i++)
     mActionListeners[i]->DidJoinNodes(aLeftNode, aRightNode, aParent, result);
 
   return result;
 }
 
 
 NS_IMETHODIMP
@@ -2683,35 +2667,35 @@ nsEditor::CreateTxnForDeleteText(nsIDOMC
 
   txn.forget(aTxn);
   return NS_OK;
 }
 
 
 
 
-NS_IMETHODIMP nsEditor::CreateTxnForSplitNode(nsINode *aNode,
+NS_IMETHODIMP nsEditor::CreateTxnForSplitNode(nsIDOMNode *aNode,
                                          uint32_t    aOffset,
                                          SplitElementTxn **aTxn)
 {
   NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
 
   nsRefPtr<SplitElementTxn> txn = new SplitElementTxn();
 
   nsresult rv = txn->Init(this, aNode, aOffset);
   if (NS_SUCCEEDED(rv))
   {
     txn.forget(aTxn);
   }
 
   return rv;
 }
 
-NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsINode  *aLeftNode,
-                                             nsINode  *aRightNode,
+NS_IMETHODIMP nsEditor::CreateTxnForJoinNode(nsIDOMNode  *aLeftNode,
+                                             nsIDOMNode  *aRightNode,
                                              JoinElementTxn **aTxn)
 {
   NS_ENSURE_TRUE(aLeftNode && aRightNode, NS_ERROR_NULL_POINTER);
 
   nsRefPtr<JoinElementTxn> txn = new JoinElementTxn();
 
   nsresult rv = txn->Init(this, aLeftNode, aRightNode);
   if (NS_SUCCEEDED(rv))
@@ -4324,19 +4308,19 @@ nsEditor::DoAfterUndoTransaction()
 void
 nsEditor::DoAfterRedoTransaction()
 {
   // all redoable transactions are non-transient
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     IncrementModificationCount(1)));
 }
 
-NS_IMETHODIMP
-nsEditor::CreateTxnForSetAttribute(Element *aElement,
-                                   const nsAString& aAttribute,
+NS_IMETHODIMP 
+nsEditor::CreateTxnForSetAttribute(nsIDOMElement *aElement, 
+                                   const nsAString& aAttribute, 
                                    const nsAString& aValue,
                                    ChangeAttributeTxn ** aTxn)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
 
   nsRefPtr<ChangeAttributeTxn> txn = new ChangeAttributeTxn();
 
   nsresult rv = txn->Init(this, aElement, aAttribute, aValue, false);
@@ -4344,18 +4328,18 @@ nsEditor::CreateTxnForSetAttribute(Eleme
   {
     txn.forget(aTxn);
   }
 
   return rv;
 }
 
 
-NS_IMETHODIMP
-nsEditor::CreateTxnForRemoveAttribute(Element *aElement,
+NS_IMETHODIMP 
+nsEditor::CreateTxnForRemoveAttribute(nsIDOMElement *aElement, 
                                       const nsAString& aAttribute,
                                       ChangeAttributeTxn ** aTxn)
 {
   NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
 
   nsRefPtr<ChangeAttributeTxn> txn = new ChangeAttributeTxn();
 
   nsresult rv = txn->Init(this, aElement, aAttribute, EmptyString(), true);
@@ -4364,17 +4348,17 @@ nsEditor::CreateTxnForRemoveAttribute(El
     txn.forget(aTxn);
   }
 
   return rv;
 }
 
 
 NS_IMETHODIMP nsEditor::CreateTxnForCreateElement(const nsAString& aTag,
-                                                  nsINode        *aParent,
+                                                  nsIDOMNode     *aParent,
                                                   int32_t         aPosition,
                                                   CreateElementTxn ** aTxn)
 {
   NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
 
   nsRefPtr<CreateElementTxn> txn = new CreateElementTxn();
 
   nsresult rv = txn->Init(this, aTag, aParent, aPosition);
@@ -4382,18 +4366,18 @@ NS_IMETHODIMP nsEditor::CreateTxnForCrea
   {
     txn.forget(aTxn);
   }
 
   return rv;
 }
 
 
-NS_IMETHODIMP nsEditor::CreateTxnForInsertElement(nsINode    * aNode,
-                                                  nsINode    * aParent,
+NS_IMETHODIMP nsEditor::CreateTxnForInsertElement(nsIDOMNode * aNode,
+                                                  nsIDOMNode * aParent,
                                                   int32_t      aPosition,
                                                   InsertElementTxn ** aTxn)
 {
   NS_ENSURE_TRUE(aNode && aParent, NS_ERROR_NULL_POINTER);
 
   nsRefPtr<InsertElementTxn> txn = new InsertElementTxn();
 
   nsresult rv = txn->Init(aNode, aParent, aPosition, this);
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -259,38 +259,38 @@ public:
   void SwitchTextDirectionTo(uint32_t aDirection);
 
 protected:
   nsresult DetermineCurrentDirection();
   void FireInputEvent();
 
   /** create a transaction for setting aAttribute to aValue on aElement
     */
-  NS_IMETHOD CreateTxnForSetAttribute(mozilla::dom::Element *aElement,
+  NS_IMETHOD CreateTxnForSetAttribute(nsIDOMElement *aElement,
                                       const nsAString &  aAttribute,
                                       const nsAString &  aValue,
                                       ChangeAttributeTxn ** aTxn);
 
   /** create a transaction for removing aAttribute on aElement
     */
-  NS_IMETHOD CreateTxnForRemoveAttribute(mozilla::dom::Element *aElement,
+  NS_IMETHOD CreateTxnForRemoveAttribute(nsIDOMElement *aElement,
                                          const nsAString &  aAttribute,
                                          ChangeAttributeTxn ** aTxn);
 
   /** create a transaction for creating a new child node of aParent of type aTag.
     */
   NS_IMETHOD CreateTxnForCreateElement(const nsAString & aTag,
-                                       nsINode         *aParent,
+                                       nsIDOMNode      *aParent,
                                        int32_t         aPosition,
                                        CreateElementTxn ** aTxn);
 
   /** create a transaction for inserting aNode as a child of aParent.
     */
-  NS_IMETHOD CreateTxnForInsertElement(nsINode    * aNode,
-                                       nsINode    * aParent,
+  NS_IMETHOD CreateTxnForInsertElement(nsIDOMNode * aNode,
+                                       nsIDOMNode * aParent,
                                        int32_t      aOffset,
                                        InsertElementTxn ** aTxn);
 
   /** create a transaction for removing aNode from its parent.
     */
   nsresult CreateTxnForDeleteNode(nsINode* aNode, DeleteNodeTxn** aTxn);
 
 
@@ -345,22 +345,22 @@ protected:
                                   uint32_t             aLength,
                                   DeleteTextTxn**      aTxn);
 
   nsresult CreateTxnForDeleteCharacter(nsIDOMCharacterData* aData,
                                        uint32_t             aOffset,
                                        EDirection           aDirection,
                                        DeleteTextTxn**      aTxn);
 	
-  NS_IMETHOD CreateTxnForSplitNode(nsINode *aNode,
+  NS_IMETHOD CreateTxnForSplitNode(nsIDOMNode *aNode,
                                    uint32_t    aOffset,
                                    SplitElementTxn **aTxn);
 
-  NS_IMETHOD CreateTxnForJoinNode(nsINode  *aLeftNode,
-                                  nsINode  *aRightNode,
+  NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode  *aLeftNode,
+                                  nsIDOMNode  *aRightNode,
                                   JoinElementTxn **aTxn);
 
   /**
    * This method first deletes the selection, if it's not collapsed.  Then if
    * the selection lies in a CharacterData node, it splits it.  If the
    * selection is at this point collapsed in a CharacterData node, it's
    * adjusted to be collapsed right before or after the node instead (which is
    * always possible, since the node was split).
--- a/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
+++ b/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
@@ -266,20 +266,21 @@ function runTests()
 
     reset("a");
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Shift+Tab");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab)");
 
-    // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
+    // Ctrl+Tab should be consumed by tabbrowser at keydown, so, keypress
+    // event should never be fired.
     reset("a");
     synthesizeKey("VK_TAB", { ctrlKey: true });
-    check(aDescription + "Ctrl+Tab", true, true, false);
+    check(aDescription + "Ctrl+Tab", false, false, false);
     is(aElement.innerHTML, "a", aDescription + "Ctrl+Tab");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Ctrl+Tab)");
 
     reset("a");
     synthesizeKey("VK_TAB", { altKey: true });
     check(aDescription + "Alt+Tab", true, true, false);
     is(aElement.innerHTML, "a", aDescription + "Alt+Tab");
@@ -331,20 +332,21 @@ function runTests()
           true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
     is(aElement.innerHTML,
        aIsReadonly || aIsTabbable || aIsPlaintext ?
          "<ul><li id=\"target\">ul list item</li></ul>" : "ul list item",
        aDescription + "Shift+Tab on UL");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab on UL)");
 
-    // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
+    // Ctrl+Tab should be consumed by tabbrowser at keydown, so, keypress
+    // event should never be fired.
     resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
     synthesizeKey("VK_TAB", { ctrlKey: true });
-    check(aDescription + "Ctrl+Tab on UL", true, true, false);
+    check(aDescription + "Ctrl+Tab on UL", false, false, false);
     is(aElement.innerHTML, "<ul><li id=\"target\">ul list item</li></ul>",
        aDescription + "Ctrl+Tab on UL");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Ctrl+Tab on UL)");
 
     resetForIndent("<ul><li id=\"target\">ul list item</li></ul>");
     synthesizeKey("VK_TAB", { altKey: true });
     check(aDescription + "Alt+Tab on UL", true, true, false);
@@ -399,20 +401,21 @@ function runTests()
           true, true, !aIsTabbable && !aIsReadonly && !aIsPlaintext);
     is(aElement.innerHTML,
        aIsReadonly || aIsTabbable || aIsPlaintext ?
          "<ol><li id=\"target\">ol list item</li></ol>" : "ol list item",
        aDescription + "Shfit+Tab on OL");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab on OL)");
 
-    // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
+    // Ctrl+Tab should be consumed by tabbrowser at keydown, so, keypress
+    // event should never be fired.
     resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
     synthesizeKey("VK_TAB", { ctrlKey: true });
-    check(aDescription + "Ctrl+Tab on OL", true, true, false);
+    check(aDescription + "Ctrl+Tab on OL", false, false, false);
     is(aElement.innerHTML, "<ol><li id=\"target\">ol list item</li></ol>",
        aDescription + "Ctrl+Tab on OL");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Ctrl+Tab on OL)");
 
     resetForIndent("<ol><li id=\"target\">ol list item</li></ol>");
     synthesizeKey("VK_TAB", { altKey: true });
     check(aDescription + "Alt+Tab on OL", true, true, false);
@@ -466,20 +469,21 @@ function runTests()
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab on TD", true, true, false);
     is(aElement.innerHTML,
        "<table><tbody><tr><td id=\"target\">td</td></tr></tbody></table>",
        aDescription + "Shift+Tab on TD");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab on TD)");
 
-    // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
+    // Ctrl+Tab should be consumed by tabbrowser at keydown, so, keypress
+    // event should never be fired.
     resetForIndent("<table><tr><td id=\"target\">td</td></tr></table>");
     synthesizeKey("VK_TAB", { ctrlKey: true });
-    check(aDescription + "Ctrl+Tab on TD", true, true, false);
+    check(aDescription + "Ctrl+Tab on TD", false, false, false);
     is(aElement.innerHTML,
        "<table><tbody><tr><td id=\"target\">td</td></tr></tbody></table>",
        aDescription + "Ctrl+Tab on TD");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Ctrl+Tab on TD)");
 
     resetForIndent("<table><tr><td id=\"target\">td</td></tr></table>");
     synthesizeKey("VK_TAB", { altKey: true });
@@ -537,20 +541,21 @@ function runTests()
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab on TH", true, true, false);
     is(aElement.innerHTML,
        "<table><tbody><tr><th id=\"target\">th</th></tr></tbody></table>",
        aDescription + "Shift+Tab on TH");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab on TH)");
 
-    // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
+    // Ctrl+Tab should be consumed by tabbrowser at keydown, so, keypress
+    // event should never be fired.
     resetForIndent("<table><tr><th id=\"target\">th</th></tr></table>");
     synthesizeKey("VK_TAB", { ctrlKey: true });
-    check(aDescription + "Ctrl+Tab on TH", true, true, false);
+    check(aDescription + "Ctrl+Tab on TH", false, false, false);
     is(aElement.innerHTML,
        "<table><tbody><tr><th id=\"target\">th</th></tr></tbody></table>",
        aDescription + "Ctrl+Tab on TH");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Ctrl+Tab on TH)");
 
     resetForIndent("<table><tr><th id=\"target\">th</th></tr></table>");
     synthesizeKey("VK_TAB", { altKey: true });
--- a/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
+++ b/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
@@ -287,20 +287,21 @@ function runTests()
 
     reset("a");
     synthesizeKey("VK_TAB", { shiftKey: true });
     check(aDescription + "Shift+Tab", true, true, false);
     is(aElement.value, "a", aDescription + "Shift+Tab");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Shift+Tab)");
 
-    // Ctrl+Tab may be consumed by tabbrowser but editor shouldn't consume this.
+    // Ctrl+Tab should be consumed by tabbrowser at keydown, so, keypress
+    // event should never be fired.
     reset("a");
     synthesizeKey("VK_TAB", { ctrlKey: true });
-    check(aDescription + "Ctrl+Tab", true, true, false);
+    check(aDescription + "Ctrl+Tab", false, false, false);
     is(aElement.value, "a", aDescription + "Ctrl+Tab");
     is(SpecialPowers.unwrap(fm.focusedElement), aElement,
        aDescription + "focus moved unexpectedly (Ctrl+Tab)");
 
     reset("a");
     synthesizeKey("VK_TAB", { altKey: true });
     check(aDescription + "Alt+Tab", true, true, false);
     is(aElement.value, "a", aDescription + "Alt+Tab");
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -342,20 +342,21 @@ void
 ContentClientRemoteBuffer::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
 {
   mFrontAndBackBufferDiffer = true;
 }
 
 void
 ContentClientDoubleBuffered::DestroyFrontBuffer()
 {
-  MOZ_ASSERT(mFrontClient);
+  if (mFrontClient) {
+    mOldTextures.AppendElement(mFrontClient);
+    mFrontClient = nullptr;
+  }
 
-  mOldTextures.AppendElement(mFrontClient);
-  mFrontClient = nullptr;
   if (mFrontClientOnWhite) {
     mOldTextures.AppendElement(mFrontClientOnWhite);
     mFrontClientOnWhite = nullptr;
   }
 }
 
 void
 ContentClientDoubleBuffered::Updated(const nsIntRegion& aRegionToDraw,
@@ -453,16 +454,19 @@ ContentClientDoubleBuffered::FinalizeFra
     MOZ_ASSERT(locked);
   }
 
   if (!mFrontAndBackBufferDiffer) {
     MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
     return;
   }
   MOZ_ASSERT(mFrontClient);
+  if (!mFrontClient) {
+    return;
+  }
 
   MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
                   this,
                   mFrontUpdatedRegion.GetBounds().x,
                   mFrontUpdatedRegion.GetBounds().y,
                   mFrontUpdatedRegion.GetBounds().width,
                   mFrontUpdatedRegion.GetBounds().height));
 
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -78,18 +78,18 @@ ImageClient::RemoveTexture(TextureClient
 
 void
 ImageClient::RemoveTextureWithTracker(TextureClient* aTexture,
                                       AsyncTransactionTracker* aAsyncTransactionTracker)
 {
 #ifdef MOZ_WIDGET_GONK
   // AsyncTransactionTracker is supported only on ImageBridge.
   // Use AsyncTransactionTracker only when TextureClient is recyeled.
-  if (GetForwarder()->IsImageBridgeChild() &&
-      aTexture->HasRecycleCallback()) {
+  if (aAsyncTransactionTracker ||
+      (GetForwarder()->IsImageBridgeChild() && aTexture->HasRecycleCallback())) {
     RefPtr<AsyncTransactionTracker> request = aAsyncTransactionTracker;
     if (!request) {
       // Create AsyncTransactionTracker if it is not provided as argument.
       request = new RemoveTextureFromCompositableTracker(this);
     }
     // Hold TextureClient until the transaction complete to postpone
     // the TextureClient recycle.
     request->SetTextureClient(aTexture);
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -605,16 +605,22 @@ LayerIsContainerForScrollbarTarget(Layer
   return true;
 }
 
 static void
 ApplyAsyncTransformToScrollbarForContent(TimeStamp aCurrentFrame, ContainerLayer* aScrollbar,
                                          Layer* aContent, bool aScrollbarIsChild)
 {
   ContainerLayer* content = aContent->AsContainerLayer();
+
+  // We only apply the transform if the scroll-target layer has non-container
+  // children (i.e. when it has some possibly-visible content). This is to
+  // avoid moving scroll-bars in the situation that only a scroll information
+  // layer has been built for a scroll frame, as this would result in a
+  // disparity between scrollbars and visible content.
   if (!LayerHasNonContainerDescendants(content)) {
     return;
   }
 
   const FrameMetrics& metrics = content->GetFrameMetrics();
   AsyncPanZoomController* apzc = content->GetAsyncPanZoomController();
 
   if (aScrollbarIsChild) {
@@ -678,45 +684,57 @@ ApplyAsyncTransformToScrollbarForContent
                   1.0f/aScrollbar->GetPreYScale(),
                   1);
   transform = transform * Matrix4x4().Scale(1.0f/aScrollbar->GetPostXScale(),
                                             1.0f/aScrollbar->GetPostYScale(),
                                             1);
   aScrollbar->AsLayerComposite()->SetShadowTransform(transform);
 }
 
+static Layer*
+FindScrolledLayerForScrollbar(ContainerLayer* aLayer, bool* aOutIsAncestor)
+{
+  // Search all siblings of aLayer and of its ancestors.
+  for (Layer* ancestor = aLayer; ancestor; ancestor = ancestor->GetParent()) {
+    for (Layer* scrollTarget = ancestor;
+         scrollTarget;
+         scrollTarget = scrollTarget->GetPrevSibling()) {
+      if (scrollTarget != aLayer &&
+          LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
+        *aOutIsAncestor = (scrollTarget == ancestor);
+        return scrollTarget;
+      }
+    }
+    for (Layer* scrollTarget = ancestor->GetNextSibling();
+         scrollTarget;
+         scrollTarget = scrollTarget->GetNextSibling()) {
+      if (LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
+        *aOutIsAncestor = false;
+        return scrollTarget;
+      }
+    }
+  }
+  return nullptr;
+}
+
 void
 AsyncCompositionManager::ApplyAsyncTransformToScrollbar(TimeStamp aCurrentFrame, ContainerLayer* aLayer)
 {
   // If this layer corresponds to a scrollbar, then there should be a layer that
   // is a previous sibling or a parent that has a matching ViewID on its FrameMetrics.
   // That is the content that this scrollbar is for. We pick up the transient
   // async transform from that layer and use it to update the scrollbar position.
   // Note that it is possible that the content layer is no longer there; in
   // this case we don't need to do anything because there can't be an async
   // transform on the content.
-  // We only apply the transform if the scroll-target layer has non-container
-  // children (i.e. when it has some possibly-visible content). This is to
-  // avoid moving scroll-bars in the situation that only a scroll information
-  // layer has been built for a scroll frame, as this would result in a
-  // disparity between scrollbars and visible content.
-  for (Layer* scrollTarget = aLayer->GetPrevSibling();
-       scrollTarget;
-       scrollTarget = scrollTarget->GetPrevSibling()) {
-    if (LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
-      // Found a sibling that matches our criteria
-      ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, false);
-      return;
-    }
-  }
-
-  // If we didn't find a sibling, look for a parent
-  Layer* scrollTarget = aLayer->GetParent();
-  if (scrollTarget && LayerIsContainerForScrollbarTarget(scrollTarget, aLayer)) {
-    ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget, true);
+  bool isAncestor = false;
+  Layer* scrollTarget = FindScrolledLayerForScrollbar(aLayer, &isAncestor);
+  if (scrollTarget) {
+    ApplyAsyncTransformToScrollbarForContent(aCurrentFrame, aLayer, scrollTarget,
+                                             isAncestor);
   }
 }
 
 void
 AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
 {
   LayerComposite* layerComposite = aLayer->AsLayerComposite();
   ContainerLayer* container = aLayer->AsContainerLayer();
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -791,16 +791,18 @@ TEST_F(AsyncPanZoomControllerTester, Fli
   // Fling down. Each step scroll further down
   ApzcPan(apzc, tm, time, touchStart, touchEnd);
   ScreenPoint lastPoint;
   for (int i = 1; i < 50; i+=1) {
     apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(i), &viewTransformOut, pointOut);
     EXPECT_GT(pointOut.y, lastPoint.y);
     lastPoint = pointOut;
   }
+
+  apzc->Destroy();
 }
 
 TEST_F(AsyncPanZoomControllerTester, OverScrollPanning) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
@@ -818,16 +820,18 @@ TEST_F(AsyncPanZoomControllerTester, Ove
   int touchEnd = 10;
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
 
   // Pan down
   ApzcPan(apzc, tm, time, touchStart, touchEnd);
   apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut);
   EXPECT_EQ(ScreenPoint(0, 90), pointOut);
+
+  apzc->Destroy();
 }
 
 TEST_F(AsyncPanZoomControllerTester, ShortPress) {
   nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
     0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -164,16 +164,17 @@ private:
 
   DECL_GFX_PREF(Once, "layers.acceleration.disabled",          LayersAccelerationDisabled, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-video.enabled",            AsyncVideoEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-video-oop.enabled",        AsyncVideoOOPEnabled, bool, false);
+  DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled",         AsyncPanZoomEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.bench.enabled",                  LayersBenchEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.bufferrotation.enabled",         BufferRotationEnabled, bool, true);
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
   // If MOZ_GFX_OPTIMIZE_MOBILE is defined, we force component alpha off
   // and ignore the preference.
   DECL_GFX_PREF(Skip, "layers.componentalpha.enabled",         ComponentAlphaEnabled, bool, false);
 #else
   // If MOZ_GFX_OPTIMIZE_MOBILE is not defined, we actually take the
--- a/gfx/thebes/gfxQuartzNativeDrawing.cpp
+++ b/gfx/thebes/gfxQuartzNativeDrawing.cpp
@@ -3,170 +3,87 @@
  * 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 "gfxQuartzNativeDrawing.h"
 #include "gfxQuartzSurface.h"
 #include "gfxPlatform.h"
 #include "cairo-quartz.h"
 
-// see cairo-quartz-surface.c for the complete list of these
-enum {
-    kPrivateCGCompositeSourceOver = 2
-};
-
 using namespace mozilla::gfx;
 using namespace mozilla;
 
-// private Quartz routine needed here
-extern "C" {
-    CG_EXTERN void CGContextSetCompositeOperation(CGContextRef, int);
-}
-
 gfxQuartzNativeDrawing::gfxQuartzNativeDrawing(gfxContext* ctx,
                                                const gfxRect& nativeRect,
                                                gfxFloat aBackingScale)
-    : mContext(ctx)
-    , mNativeRect(nativeRect)
-    , mBackingScale(aBackingScale)
+  : mContext(ctx)
+  , mNativeRect(nativeRect)
+  , mBackingScale(aBackingScale)
+  , mCGContext(nullptr)
 {
-    mNativeRect.RoundOut();
+  mNativeRect.RoundOut();
 }
 
 CGContextRef
 gfxQuartzNativeDrawing::BeginNativeDrawing()
 {
-    NS_ASSERTION(!mQuartzSurface, "BeginNativeDrawing called when drawing already in progress");
-
-    gfxPoint deviceOffset;
-    nsRefPtr<gfxASurface> surf;
-
-    if (!mContext->IsCairo()) {
-      DrawTarget *dt = mContext->GetDrawTarget();
-      if (dt->GetType() == BackendType::COREGRAPHICS) {
-        if (dt->IsDualDrawTarget()) {
-          IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
-                              NSToIntFloor(mNativeRect.height * mBackingScale));
-
-         if (backingSize.IsEmpty())
-            return nullptr;
-
-          mDrawTarget = Factory::CreateDrawTarget(BackendType::COREGRAPHICS, backingSize, SurfaceFormat::B8G8R8A8);
-
-          Matrix transform;
-          transform.Scale(mBackingScale, mBackingScale);
-          transform.Translate(-mNativeRect.x, -mNativeRect.y);
-
-          mDrawTarget->SetTransform(transform);
-          dt = mDrawTarget;
-        }
-
-        mCGContext = mBorrowedContext.Init(dt);
-        MOZ_ASSERT(mCGContext);
-        return mCGContext;
-      }
-      surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(dt);
-    } else {
-      surf = mContext->CurrentSurface(&deviceOffset.x, &deviceOffset.y);
-    }
-    if (!surf || surf->CairoStatus())
-        return nullptr;
+  NS_ASSERTION(!mCGContext, "BeginNativeDrawing called when drawing already in progress");
 
-    // if this is a native Quartz surface, we don't have to redirect
-    // rendering to our own CGContextRef; in most cases, we are able to
-    // use the CGContextRef from the surface directly.  we can extend
-    // this to support offscreen drawing fairly easily in the future.
-    if (surf->GetType() == gfxSurfaceType::Quartz &&
-        (surf->GetContentType() == gfxContentType::COLOR ||
-         (surf->GetContentType() == gfxContentType::COLOR_ALPHA))) {
-        mQuartzSurface = static_cast<gfxQuartzSurface*>(surf.get());
-        mSurfaceContext = mContext;
-
-        // grab the CGContextRef
-        mCGContext = cairo_quartz_get_cg_context_with_clip(mSurfaceContext->GetCairo());
-        if (!mCGContext)
-            return nullptr;
-
-        gfxMatrix m = mContext->CurrentMatrix();
-        CGContextTranslateCTM(mCGContext, deviceOffset.x, deviceOffset.y);
-
-        // I -think- that this context will always have an identity
-        // transform (since we don't maintain a transform on it in
-        // cairo-land, and instead push/pop as needed)
-
-        gfxFloat x0 = m.x0;
-        gfxFloat y0 = m.y0;
+  if (mContext->IsCairo()) {
+    // We're past that now. Any callers that still supply a Cairo context
+    // don't deserve native theming.
+    NS_WARNING("gfxQuartzNativeDrawing being used with a gfxContext that is not backed by a DrawTarget");
+    return nullptr;
+  }
 
-        // We round x0/y0 if we don't have a scale, because otherwise things get
-        // rendered badly
-        // XXX how should we be rounding x0/y0?
-        if (!m.HasNonTranslationOrFlip()) {
-            x0 = floor(x0 + 0.5);
-            y0 = floor(y0 + 0.5);
-        }
-
-        CGContextConcatCTM(mCGContext, CGAffineTransformMake(m.xx, m.yx,
-                                                             m.xy, m.yy,
-                                                             x0, y0));
+  DrawTarget *dt = mContext->GetDrawTarget();
+  if (dt->GetType() != BackendType::COREGRAPHICS || dt->IsDualDrawTarget()) {
+    IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
+                        NSToIntFloor(mNativeRect.height * mBackingScale));
 
-        // bug 382049 - need to explicity set the composite operation to sourceOver
-        CGContextSetCompositeOperation(mCGContext, kPrivateCGCompositeSourceOver);
-    } else {
-        nsIntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
-                              NSToIntFloor(mNativeRect.height * mBackingScale));
-        mQuartzSurface = new gfxQuartzSurface(backingSize,
-                                              gfxImageFormat::ARGB32);
-        if (mQuartzSurface->CairoStatus())
-            return nullptr;
-        mSurfaceContext = new gfxContext(mQuartzSurface);
-
-        // grab the CGContextRef
-        mCGContext = cairo_quartz_get_cg_context_with_clip(mSurfaceContext->GetCairo());
-        CGContextScaleCTM(mCGContext, mBackingScale, mBackingScale);
-        CGContextTranslateCTM(mCGContext, -mNativeRect.X(), -mNativeRect.Y());
+    if (backingSize.IsEmpty()) {
+      return nullptr;
     }
 
-    return mCGContext;
+    mDrawTarget = Factory::CreateDrawTarget(BackendType::COREGRAPHICS, backingSize, SurfaceFormat::B8G8R8A8);
+
+    Matrix transform;
+    transform.Scale(mBackingScale, mBackingScale);
+    transform.Translate(-mNativeRect.x, -mNativeRect.y);
+
+    mDrawTarget->SetTransform(transform);
+    dt = mDrawTarget;
+  }
+
+  mCGContext = mBorrowedContext.Init(dt);
+  MOZ_ASSERT(mCGContext);
+  return mCGContext;
 }
 
 void
 gfxQuartzNativeDrawing::EndNativeDrawing()
 {
-    NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
+  NS_ASSERTION(mCGContext, "EndNativeDrawing called without BeginNativeDrawing");
+  MOZ_ASSERT(!mContext->IsCairo(), "BeginNativeDrawing succeeded with cairo context?");
 
-    if (mBorrowedContext.cg) {
-        MOZ_ASSERT(!mContext->IsCairo());
-        mBorrowedContext.Finish();
-        if (mDrawTarget) {
-          DrawTarget *dest = mContext->GetDrawTarget();
-          RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
+  mBorrowedContext.Finish();
+  if (mDrawTarget) {
+    DrawTarget *dest = mContext->GetDrawTarget();
+    RefPtr<SourceSurface> source = mDrawTarget->Snapshot();
+
+    IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
+                        NSToIntFloor(mNativeRect.height * mBackingScale));
 
-          IntSize backingSize(NSToIntFloor(mNativeRect.width * mBackingScale),
-                              NSToIntFloor(mNativeRect.height * mBackingScale));
+    Matrix oldTransform = dest->GetTransform();
+    Matrix newTransform = oldTransform;
+    newTransform.Translate(mNativeRect.x, mNativeRect.y);
+    newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
 
-          Matrix oldTransform = dest->GetTransform();
-          Matrix newTransform = oldTransform;
-          newTransform.Translate(mNativeRect.x, mNativeRect.y);
-          newTransform.Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
+    dest->SetTransform(newTransform);
 
-          dest->SetTransform(newTransform);
-
-          dest->DrawSurface(source,
-                            gfx::Rect(0, 0, backingSize.width, backingSize.height),
-                            gfx::Rect(0, 0, backingSize.width, backingSize.height));
+    dest->DrawSurface(source,
+                      gfx::Rect(0, 0, backingSize.width, backingSize.height),
+                      gfx::Rect(0, 0, backingSize.width, backingSize.height));
 
 
-          dest->SetTransform(oldTransform);
-        }
-        return;
-    }
-
-    cairo_quartz_finish_cg_context_with_clip(mSurfaceContext->GetCairo());
-    mQuartzSurface->MarkDirty();
-    if (mSurfaceContext != mContext) {
-        gfxContextMatrixAutoSaveRestore save(mContext);
-
-        // Copy back to destination
-        mContext->Translate(mNativeRect.TopLeft());
-        mContext->Scale(1.0f / mBackingScale, 1.0f / mBackingScale);
-        mContext->DrawSurface(mQuartzSurface, mQuartzSurface->GetSize());
-    }
+    dest->SetTransform(oldTransform);
+  }
 }
--- a/gfx/thebes/gfxQuartzNativeDrawing.h
+++ b/gfx/thebes/gfxQuartzNativeDrawing.h
@@ -53,25 +53,20 @@ public:
     /* Marks the end of native drawing */
     void EndNativeDrawing();
 
 private:
     // don't allow copying via construction or assignment
     gfxQuartzNativeDrawing(const gfxQuartzNativeDrawing&) MOZ_DELETE;
     const gfxQuartzNativeDrawing& operator=(const gfxQuartzNativeDrawing&) MOZ_DELETE;
 
-
     // Final destination context
     nsRefPtr<gfxContext> mContext;
     mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
     mozilla::gfx::BorrowedCGContext mBorrowedContext;
-    // context that draws to mQuartzSurface; can be different from mContext
-    // if mContext is not drawing to Quartz
-    nsRefPtr<gfxContext> mSurfaceContext;
     gfxRect mNativeRect;
     gfxFloat mBackingScale;
 
     // saved state
-    nsRefPtr<gfxQuartzSurface> mQuartzSurface;
     CGContextRef mCGContext;
 };
 
 #endif
--- a/ipc/chromium/src/base/basictypes.h
+++ b/ipc/chromium/src/base/basictypes.h
@@ -149,16 +149,25 @@ char (&ArraySizeHelper(const T (&array)[
 // implicit_cast would have been part of the C++ standard library,
 // but the proposal was submitted too late.  It will probably make
 // its way into the language in the future.
 template<typename To, typename From>
 inline To implicit_cast(From const &f) {
   return f;
 }
 
+// The COMPILE_ASSERT macro (below) creates an otherwise-unused typedef.  This
+// triggers compiler warnings with gcc 4.8 and higher, so mark the typedef
+// as permissibly-unused to disable the warnings.
+#  if defined(__GNUC__)
+#    define COMPILE_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
+#  else
+#    define COMPILE_ASSERT_UNUSED_ATTRIBUTE /* nothing */
+#  endif
+
 // The COMPILE_ASSERT macro can be used to verify that a compile time
 // expression is true. For example, you could use it to verify the
 // size of a static array:
 //
 //   COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES,
 //                  content_type_names_incorrect_size);
 //
 // or to make sure a struct is smaller than a certain size:
@@ -171,17 +180,18 @@ inline To implicit_cast(From const &f) {
 
 // Avoid multiple definitions for webrtc
 #if !defined(COMPILE_ASSERT)
 template <bool>
 struct CompileAssert {
 };
 
 #define COMPILE_ASSERT(expr, msg) \
-  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] \
+  COMPILE_ASSERT_UNUSED_ATTRIBUTE
 #endif
 
 // Implementation details of COMPILE_ASSERT:
 //
 // - COMPILE_ASSERT works by defining an array type that has -1
 //   elements (and thus is invalid) when the expression is false.
 //
 // - The simpler definition
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -484,16 +484,79 @@ function ArrayFindIndex(predicate/*, thi
                 return k;
         }
     }
 
     /* Step 10. */
     return -1;
 }
 
+/* ES6 draft 2013-09-27 22.1.3.3. */
+function ArrayCopyWithin(target, start, end = undefined) {
+    /* Steps 1-2. */
+    var O = ToObject(this);
+
+    /* Steps 3-5. */
+    var len = ToInteger(O.length);
+
+    /* Steps 6-8. */
+    var relativeTarget = ToInteger(target);
+
+    var to = relativeTarget < 0 ? std_Math_max(len + relativeTarget, 0)
+                                : std_Math_min(relativeTarget, len);
+
+    /* Steps 9-11. */
+    var relativeStart = ToInteger(start);
+
+    var from = relativeStart < 0 ? std_Math_max(len + relativeStart, 0)
+                                 : std_Math_min(relativeStart, len);
+
+    /* Steps 12-14. */
+    var relativeEnd = end === undefined ? len
+                                        : ToInteger(end);
+
+    var final = relativeEnd < 0 ? std_Math_max(len + relativeEnd, 0)
+                                : std_Math_min(relativeEnd, len);
+
+    /* Step 15. */
+    var count = std_Math_min(final - from, len - to);
+
+    /* Steps 16-17. */
+    if (from < to && to < (from + count)) {
+        from = from + count - 1;
+        to = to + count - 1;
+        /* Step 18. */
+        while (count > 0) {
+            if (from in O)
+                O[to] = O[from];
+            else
+                delete O[to];
+
+            from--;
+            to--;
+            count--;
+        }
+    } else {
+        /* Step 18. */
+        while (count > 0) {
+            if (from in O)
+                O[to] = O[from];
+            else
+                delete O[to];
+
+            from++;
+            to++;
+            count--;
+        }
+    }
+
+    /* Step 19. */
+    return O;
+}
+
 // ES6 draft 2014-04-05 22.1.3.6
 function ArrayFill(value, start = 0, end = undefined) {
     // Steps 1-2.
     var O = ToObject(this);
 
     // Steps 3-5.
     // FIXME: Array operations should use ToLength (bug 924058).
     var len = ToInteger(O.length);
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1044,16 +1044,17 @@ EnableSPSProfiling(JSContext *cx, unsign
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 EnableSPSProfilingWithSlowAssertions(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
+    args.rval().setUndefined();
 
     if (cx->runtime()->spsProfiler.enabled()) {
         // If profiling already enabled with slow assertions disabled,
         // this is a no-op.
         if (cx->runtime()->spsProfiler.slowAssertionsEnabled())
             return true;
 
         // Slow assertions are off.  Disable profiling before re-enabling
@@ -1065,25 +1066,26 @@ EnableSPSProfilingWithSlowAssertions(JSC
     if (cx->runtime()->spsProfiler.installed())
         cx->runtime()->spsProfiler.enable(false);
 
     SetRuntimeProfilingStack(cx->runtime(), SPS_PROFILING_STACK, &SPS_PROFILING_STACK_SIZE,
                              SPS_PROFILING_STACK_MAX_SIZE);
     cx->runtime()->spsProfiler.enableSlowAssertions(true);
     cx->runtime()->spsProfiler.enable(true);
 
-    args.rval().setUndefined();
     return true;
 }
 
 static bool
 DisableSPSProfiling(JSContext *cx, unsigned argc, jsval *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
     if (cx->runtime()->spsProfiler.installed())
         cx->runtime()->spsProfiler.enable(false);
+    args.rval().setUndefined();
     return true;
 }
 
 static bool
 EnableOsiPointRegisterChecks(JSContext *, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 #if defined(JS_ION) && defined(CHECK_OSIPOINT_REGISTERS)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -4376,16 +4376,36 @@ EmitWith(ExclusiveContext *cx, BytecodeE
         return false;
     if (!EmitTree(cx, bce, pn->pn_right))
         return false;
     if (!LeaveNestedScope(cx, bce, &stmtInfo))
         return false;
     return true;
 }
 
+/**
+ * EmitIterator expects the iterable to already be on the stack.
+ * It will replace that stack value with the corresponding iterator
+ */
+static bool
+EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce)
+{
+    // Convert iterable to iterator.
+    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // OBJ OBJ
+        return false;
+    if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // OBJ @@ITERATOR
+        return false;
+    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
+        return false;
+    if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
+        return false;
+    CheckTypeSet(cx, bce, JSOP_CALL);
+    return true;
+}
+
 static bool
 EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
     ParseNode *pn1 = forHead->pn_kid1;
     bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
@@ -4404,26 +4424,18 @@ EmitForOf(ExclusiveContext *cx, Bytecode
 
     // For-of loops run with two values on the stack: the iterator and the
     // current result object.
 
     // Compile the object expression to the right of 'of'.
     if (!EmitTree(cx, bce, forHead->pn_kid3))
         return false;
 
-    // Convert iterable to iterator.
-    if (Emit1(cx, bce, JSOP_DUP) < 0)                          // OBJ OBJ
-        return false;
-    if (!EmitAtomOp(cx, cx->names().std_iterator, JSOP_CALLPROP, bce)) // OBJ @@ITERATOR
-        return false;
-    if (Emit1(cx, bce, JSOP_SWAP) < 0)                         // @@ITERATOR OBJ
-        return false;
-    if (EmitCall(cx, bce, JSOP_CALL, 0) < 0)                   // ITER
-        return false;
-    CheckTypeSet(cx, bce, JSOP_CALL);
+    if (!EmitIterator(cx, bce))
+        return false;
 
     // Push a dummy result so that we properly enter iteration midstream.
     if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)                    // ITER RESULT
         return false;
 
     // Enter the block before the loop body, after evaluating the obj.
     StmtInfoBCE letStmt(cx);
     if (letDecl) {
@@ -6062,44 +6074,50 @@ EmitArray(ExclusiveContext *cx, Bytecode
     jsbytecode *pc = bce->code(off);
 
     // For arrays with spread, this is a very pessimistic allocation, the
     // minimum possible final size.
     SET_UINT24(pc, count - nspread);
 
     ParseNode *pn2 = pn;
     jsatomid atomIndex;
-    if (nspread && !EmitNumberOp(cx, 0, bce))
-        return false;
+    bool afterSpread = false;
     for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
+        if (!afterSpread && pn2->isKind(PNK_SPREAD)) {
+            afterSpread = true;
+            if (!EmitNumberOp(cx, atomIndex, bce))
+                return false;
+        }
         if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
             return false;
         if (pn2->isKind(PNK_ELISION)) {
             if (Emit1(cx, bce, JSOP_HOLE) < 0)
                 return false;
         } else {
             ParseNode *expr = pn2->isKind(PNK_SPREAD) ? pn2->pn_kid : pn2;
             if (!EmitTree(cx, bce, expr))
                 return false;
         }
         if (pn2->isKind(PNK_SPREAD)) {
+            if (!EmitIterator(cx, bce))
+                return false;
             if (Emit1(cx, bce, JSOP_SPREAD) < 0)
                 return false;
-        } else if (nspread) {
+        } else if (afterSpread) {
             if (Emit1(cx, bce, JSOP_INITELEM_INC) < 0)
                 return false;
         } else {
             off = EmitN(cx, bce, JSOP_INITELEM_ARRAY, 3);
             if (off < 0)
                 return false;
             SET_UINT24(bce->code(off), atomIndex);
         }
     }
     JS_ASSERT(atomIndex == count);
-    if (nspread) {
+    if (afterSpread) {
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
     }
 
     /* Emit an op to finish the array and aid in decompilation. */
     return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
 }
 
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1623,17 +1623,17 @@ GCMarker::processMarkStackTop(SliceBudge
 bool
 GCMarker::drainMarkStack(SliceBudget &budget)
 {
 #ifdef DEBUG
     JSRuntime *rt = runtime();
 
     struct AutoCheckCompartment {
         JSRuntime *runtime;
-        AutoCheckCompartment(JSRuntime *rt) : runtime(rt) {
+        explicit AutoCheckCompartment(JSRuntime *rt) : runtime(rt) {
             JS_ASSERT(!rt->gc.strictCompartmentChecking);
             runtime->gc.strictCompartmentChecking = true;
         }
         ~AutoCheckCompartment() { runtime->gc.strictCompartmentChecking = false; }
     } acc(rt);
 #endif
 
     if (budget.isOverBudget())
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -21,17 +21,16 @@
 #include "frontend/BytecodeCompiler.h"
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #ifdef JS_ION
 # include "jit/IonMacroAssembler.h"
 #endif
 #include "js/HashTable.h"
 #include "vm/Debugger.h"
-#include "vm/PropDesc.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::ArrayEnd;
@@ -60,17 +59,16 @@ MarkExactStackRoot(JSTracer *trc, Rooted
       case THING_ROOT_BASE_SHAPE:  MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact-baseshape"); break;
       case THING_ROOT_TYPE:        MarkTypeRoot(trc, (types::Type *)addr, "exact-type"); break;
       case THING_ROOT_TYPE_OBJECT: MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact-typeobject"); break;
       case THING_ROOT_JIT_CODE:    MarkJitCodeRoot(trc, (jit::JitCode **)addr, "exact-jitcode"); break;
       case THING_ROOT_VALUE:       MarkValueRoot(trc, (Value *)addr, "exact-value"); break;
       case THING_ROOT_ID:          MarkIdRoot(trc, (jsid *)addr, "exact-id"); break;
       case THING_ROOT_BINDINGS:    ((Bindings *)addr)->trace(trc); break;
       case THING_ROOT_PROPERTY_DESCRIPTOR: ((JSPropertyDescriptor *)addr)->trace(trc); break;
-      case THING_ROOT_PROP_DESC:   ((PropDesc *)addr)->trace(trc); break;
       case THING_ROOT_CUSTOM: {
           // 'rooter' is a member within a class containing a vtable. Back up
           // to the vtable and call trace() through it.
           const size_t rooterOffset = offsetof(RootedGeneric<void*>, rooter);
           reinterpret_cast< RootedGeneric<void*>* >(uintptr_t(rooter) - rooterOffset)->trace(trc);
           break;
       }
       default: MOZ_ASSUME_UNREACHABLE("Invalid THING_ROOT kind"); break;
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -202,17 +202,17 @@ struct AutoPhase
 
     Statistics &stats;
     Phase phase;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 struct MaybeAutoPhase
 {
-    MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+    explicit MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
       : stats(nullptr)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
     void construct(Statistics &statsArg, Phase phaseArg)
     {
         JS_ASSERT(!stats);
         stats = &statsArg;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/array-copyWithin.js
@@ -0,0 +1,182 @@
+// Tests for Array#copyWithin
+
+load(libdir + "asserts.js");
+
+assertEq(Array.prototype.copyWithin.length, 2);
+
+// works with two arguments
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, 3), [4, 5, 3, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(1, 3), [1, 4, 5, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(1, 2), [1, 3, 4, 5, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(2, 2), [1, 2, 3, 4, 5]);
+
+// works with three arguments
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, 3, 4), [4, 2, 3, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(1, 3, 4), [1, 4, 3, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(1, 2, 4), [1, 3, 4, 4, 5]);
+
+// works with negative arguments
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, -2), [4, 5, 3, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, -2, -1), [4, 2, 3, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(-4, -3, -2), [1, 3, 3, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(-4, -3, -1), [1, 3, 4, 4, 5]);
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(-4, -3), [1, 3, 4, 5, 5]);
+
+// works with array-like objects
+var args = (function () { return Array.prototype.slice.call(arguments); }(1, 2, 3));
+var argsClass = Object.prototype.toString.call(args);
+assertDeepEq(args, [1, 2, 3]);
+Array.prototype.copyWithin.call(args, -2, 0);
+assertDeepEq(args, [1, 1, 2]);
+assertDeepEq(Object.prototype.toString.call(args), argsClass);
+
+// throws on null/undefined values
+assertThrowsInstanceOf(function() {
+  Array.prototype.copyWithin.call(null, 0, 3);
+}, TypeError, "Assert that copyWithin fails if this value is null");
+
+assertThrowsInstanceOf(function() {
+  Array.prototype.copyWithin.call(undefined, 0, 3);
+}, TypeError, "Assert that copyWithin fails if this value is undefined");
+
+// test with this value as string
+assertThrowsInstanceOf(function() {
+  Array.prototype.copyWithin.call("hello world", 0, 3);
+}, TypeError, "Assert that copyWithin fails if this value is string");
+
+// test with this value as number
+assertDeepEq(Array.prototype.copyWithin.call(34, 0, 3), new Number(34));
+
+// test with this value as TypedArray
+var buffer = new ArrayBuffer(16);
+var int32View = new Int32Array(buffer);
+for (var i=0; i<int32View.length; i++) {
+  int32View[i] = i*2;
+}
+assertDeepEq(Array.prototype.copyWithin.call(int32View, 0, 1), new Int32Array([2, 4, 6, 6]));
+
+// if arguments object is sloppy, copyWithin must move the arguments around
+function f(a, b, c, d, e) {
+  [].copyWithin.call(arguments, 1, 3);
+  return [a, b, c, d, e];
+}
+assertDeepEq(f(1, 2, 3, 4, 5), [1, 4, 5, 4, 5]);
+
+// test with target > start on 2 arguments
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(3, 0), [1, 2, 3, 1, 2]);
+
+// test with target > start on 3 arguments
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(3, 0, 4), [1, 2, 3, 1, 2]);
+
+// test on array with holes
+var arr = new Array(6);
+for (var i = 0; i < arr.length; i += 2) {
+  arr[i] = i;
+}
+assertDeepEq(arr.copyWithin(0, 3), [, 4, , , 4, , ]);
+
+// test on fractional arguments
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0.2, 3.9), [4, 5, 3, 4, 5]);
+
+// test with -0
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(-0, 3), [4, 5, 3, 4, 5]);
+
+// test with arguments more than this.length
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, 7), [1, 2, 3, 4, 5]);
+
+// test with arguments less than -this.length
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(-7, 0), [1, 2, 3, 4, 5]);
+
+// test with arguments equal to -this.length
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(-5, 0), [1, 2, 3, 4, 5]);
+
+// test on empty array
+assertDeepEq([].copyWithin(0, 3), []);
+
+// test with target range being shorter than end - start
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(2, 1, 4), [1, 2, 2, 3, 4]);
+
+// test overlapping ranges
+arr = [1, 2, 3, 4, 5];
+arr.copyWithin(2, 1, 4);
+assertDeepEq(arr.copyWithin(2, 1, 4), [1, 2, 2, 2, 3]);
+
+// check that delete is strict
+arr = [1, , 3, , 4, 5];
+Object.freeze(arr);
+assertThrowsInstanceOf(function() {
+  arr.copyWithin(2, 1, 4);
+}, TypeError, "Assert that delete is strict in copyWithin");
+
+// test with a proxy object
+var proxyObj = {
+  get: function(recipient, name) {
+    return recipient[name] + 2;
+  }
+};
+
+var p = new Proxy([1, 2, 3, 4, 5], proxyObj);
+assertDeepEq(Array.prototype.copyWithin.call(p, 0, 3), [6, 7, , , 5]);
+
+// test if we throw in between
+arr = [1, 2, 3, 4, 5];
+Object.defineProperty(arr, 1, {
+  set: function () {
+    throw new Error("Boom!");
+  }
+});
+
+assertThrowsInstanceOf(function() {
+  arr.copyWithin(1, 3);
+}, Error, "Throwing in between.");
+assertEq(arr[0], 1);
+assertEq(arr[1], undefined);
+assertEq(arr[2], 3);
+assertEq(arr[3], 4);
+assertEq(arr[4], 5);
+
+// undefined as third argument
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, 3, undefined), [4, 5, 3, 4, 5]);
+
+// test that this.length is called only once
+arr = {0: 1, 1: 2, 2: 3, 3: 4, 4: 5};
+var count = 0;
+Object.defineProperty(arr, "length", {
+  get: function () {
+    count++;
+  }
+});
+Array.prototype.copyWithin.call(arr, 1, 3);
+assertEq(count, 1);
+
+count = 0;
+Array.prototype.copyWithin.call(arr, 1, 3, 4);
+assertEq(count, 1);
+
+var large = 10000;
+
+// test on a large array
+arr = new Array(large);
+assertDeepEq(arr.copyWithin(45, 900), arr);
+
+// test on floating point numbers
+for (var i = 0; i < large; i++) {
+  arr[i] = Math.random();
+}
+arr.copyWithin(45, 900);
+
+// test on array of objects
+for (var i = 0; i < large; i++) {
+  arr[i] = { num: Math.random() };
+}
+arr.copyWithin(45, 900);
+
+// test array length remains same
+assertEq(arr.length, large);
+
+// test null on third argument is handled correctly
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, 3, null), [1, 2, 3, 4, 5]);
+
+// tamper the global Object prototype and test this works
+Object.prototype[2] = 1;
+assertDeepEq([1, 2, 3, 4, 5].copyWithin(0, 3), [4, 5, 3, 4, 5]);
--- a/js/src/jit-test/tests/basic/spread-array.js
+++ b/js/src/jit-test/tests/basic/spread-array.js
@@ -6,16 +6,17 @@ assertEqArray([...[1, 2, 3]], [1, 2, 3])
 assertEqArray([1, ...[2, 3, 4], 5], [1, 2, 3, 4, 5]);
 assertEqArray([1, ...[], 2], [1, 2]);
 assertEqArray([1, ...[2, 3], 4, ...[5, 6]], [1, 2, 3, 4, 5, 6]);
 assertEqArray([1, ...[], 2], [1, 2]);
 assertEqArray([1,, ...[2]], [1,, 2]);
 assertEqArray([1,, ...[2],, 3,, 4,], [1,, 2,, 3,, 4,]);
 assertEqArray([...[1, 2, 3],,,,], [1, 2, 3,,,,]);
 assertEqArray([,,...[1, 2, 3],,,,], [,,1,2,3,,,,]);
+assertEqArray([...[1, 2, 3],,,,...[]], [1,2,3,,,,]);
 
 assertEqArray([...[undefined]], [undefined]);
 
 // other iterable objects
 assertEqArray([...new Int32Array([1, 2, 3])], [1, 2, 3]);
 assertEqArray([..."abc"], ["a", "b", "c"]);
 assertEqArray([...[1, 2, 3][std_iterator]()], [1, 2, 3]);
 assertEqArray([...Set([1, 2, 3])], [1, 2, 3]);
@@ -37,16 +38,13 @@ function* gen() {
     for (let i = 1; i < 4; i ++)
         yield i;
 }
 assertEqArray([...gen()], [1, 2, 3]);
 
 let a, b = [1, 2, 3];
 assertEqArray([...a=b], [1, 2, 3]);
 
-// According to the draft spec, null and undefined are to be treated as empty
-// arrays. However, they are not iterable. If the spec is not changed to be in
-// terms of iterables, these tests should be fixed.
-//assertEqArray([1, ...null, 2], [1, 2]);
-//assertEqArray([1, ...undefined, 2], [1, 2]);
+// 12.2.4.1.2 Runtime Semantics: ArrayAccumulation
+// If Type(spreadObj) is not Object, then throw a TypeError exception.
 assertThrowsInstanceOf(() => [...null], TypeError);
 assertThrowsInstanceOf(() => [...undefined], TypeError);
 
--- a/js/src/jit-test/tests/basic/spread-call-eval.js
+++ b/js/src/jit-test/tests/basic/spread-call-eval.js
@@ -43,15 +43,12 @@ assertEq(eval(...itr), 11);
 function* gen() {
     yield "a + b";
 }
 assertEq(eval(...gen()), 11);
 
 let c = ["C"], d = "D";
 assertEq(eval(...c=["c[0] + d"]), "c[0] + dD");
 
-// According to the draft spec, null and undefined are to be treated as empty
-// arrays. However, they are not iterable. If the spec is not changed to be in
-// terms of iterables, these tests should be fixed.
-//assertEq(eval("a + b", ...null), 11);
-//assertEq(eval("a + b", ...undefined), 11);
+// 12.2.4.1.2 Runtime Semantics: ArrayAccumulation
+// If Type(spreadObj) is not Object, then throw a TypeError exception.
 assertThrowsInstanceOf(() => eval("a + b", ...null), TypeError);
 assertThrowsInstanceOf(() => eval("a + b", ...undefined), TypeError);
--- a/js/src/jit-test/tests/basic/spread-call-funapply.js
+++ b/js/src/jit-test/tests/basic/spread-call-funapply.js
@@ -31,21 +31,18 @@ function checkCommon(f) {
       yield null;
       yield [1, 2, 3];
   }
   assertEqArray(f.apply(...gen()), [1, 2, 3]);
 
   let a;
   assertEqArray(f.apply(null, ...a=[[1, 2, 3]]), [1, 2, 3]);
 
-  // According to the draft spec, null and undefined are to be treated as empty
-  // arrays. However, they are not iterable. If the spec is not changed to be in
-  // terms of iterables, these tests should be fixed.
-  //assertEqArray(f.apply(null, ...null, [1, 2, 3]), [1, 2, 3]);
-  //assertEqArray(f.apply(null, ...undefined, [1, 2, 3]), [1, 2, 3]);
+  // 12.2.4.1.2 Runtime Semantics: ArrayAccumulation
+  // If Type(spreadObj) is not Object, then throw a TypeError exception.
   assertThrowsInstanceOf(() => f.apply(null, ...null, [1, 2, 3]), TypeError);
   assertThrowsInstanceOf(() => f.apply(null, ...undefined, [1, 2, 3]), TypeError);
 }
 
 function checkNormal(f) {
   checkCommon(f);
 
   assertEqArray(f.apply(null, ...[[]]), [undefined, undefined, undefined]);
--- a/js/src/jit-test/tests/basic/spread-call.js
+++ b/js/src/jit-test/tests/basic/spread-call.js
@@ -35,21 +35,18 @@ function checkCommon(f, makeFn) {
   function gen() {
       for (let i = 1; i < 4; i ++)
           yield i;
   }
   assertEqArray(makeFn("...arg")(f, gen()), [1, 2, 3]);
 
   assertEqArray(makeFn("...arg=[1, 2, 3]")(f), [1, 2, 3]);
 
-  // According to the draft spec, null and undefined are to be treated as empty
-  // arrays. However, they are not iterable. If the spec is not changed to be in
-  // terms of iterables, these tests should be fixed.
-  //assertEqArray(makeFn(1, ...null, 2, 3)(f), [1, 2, 3]);
-  //assertEqArray(makeFn(1, ...undefined, 2, 3)(f), [1, 2, 3]);
+  // 12.2.4.1.2 Runtime Semantics: ArrayAccumulation
+  // If Type(spreadObj) is not Object, then throw a TypeError exception.
   assertThrowsInstanceOf(makeFn("1, ...null, 2, 3"), TypeError);
   assertThrowsInstanceOf(makeFn("1, ...undefined, 2, 3"), TypeError);
 }
 
 function checkNormal(f, makeFn) {
   checkCommon(f, makeFn);
 
   assertEqArray(makeFn("...[]")(f), [undefined, undefined, undefined]);
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -1262,16 +1262,23 @@ struct ScopedCacheEntryOpenedForWrite
     }
 };
 
 bool
 js::StoreAsmJSModuleInCache(AsmJSParser &parser,
                             const AsmJSModule &module,
                             ExclusiveContext *cx)
 {
+    // Don't serialize modules with information about basic block hit counts
+    // compiled in, which both affects code speed and uses absolute addresses
+    // that can't be serialized. (This is separate from normal profiling and
+    // requires an addon to activate).
+    if (module.numFunctionCounts())
+        return false;
+
     MachineId machineId;
     if (!machineId.extractCurrentState(cx))
         return false;
 
     ModuleCharsForStore moduleChars;
     if (!moduleChars.init(parser))
         return false;
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -2372,17 +2372,17 @@ BaselineCompiler::emit_JSOP_INITELEM_INC
 
 typedef bool (*SpreadFn)(JSContext *, HandleObject, HandleValue,
                          HandleValue, MutableHandleValue);
 static const VMFunction SpreadInfo = FunctionInfo<SpreadFn>(js::SpreadOperation);
 
 bool
 BaselineCompiler::emit_JSOP_SPREAD()
 {
-    // Load index and iterable in R0 and R1, but keep values on the stack for
+    // Load index and iterator in R0 and R1, but keep values on the stack for
     // the decompiler.
     frame.syncStack(0);
     masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
     masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
 
     prepareVMCall();
 
     pushArg(R1);
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1196,32 +1196,34 @@ jit::BuildDominatorTree(MIRGraph &graph)
     // of a definition is visited before the def itself. Since a def
     // dominates its uses, by the time we reach a particular
     // block, we have processed all of its dominated children, so
     // block->numDominated() is accurate.
     for (PostorderIterator i(graph.poBegin()); i != graph.poEnd(); i++) {
         MBasicBlock *child = *i;
         MBasicBlock *parent = child->immediateDominator();
 
+        // Domininace is defined such that blocks always dominate themselves.
+        child->addNumDominated(1);
+
         // If the block only self-dominates, it has no definite parent.
         if (child == parent)
             continue;
 
         if (!parent->addImmediatelyDominatedBlock(child))
             return false;
 
-        // An additional +1 for the child block.
-        parent->addNumDominated(child->numDominated() + 1);
+        parent->addNumDominated(child->numDominated());
     }
 
 #ifdef DEBUG
     // If compiling with OSR, many blocks will self-dominate.
     // Without OSR, there is only one root block which dominates all.
     if (!graph.osrBlock())
-        JS_ASSERT(graph.entryBlock()->numDominated() == graph.numBlocks() - 1);
+        JS_ASSERT(graph.entryBlock()->numDominated() == graph.numBlocks());
 #endif
     // Now, iterate through the dominator tree and annotate every
     // block with its index in the pre-order traversal of the
     // dominator tree.
     Vector<MBasicBlock *, 1, IonAllocPolicy> worklist(graph.alloc());
 
     // The index of the current block in the CFG traversal.
     size_t index = 0;
@@ -1426,45 +1428,47 @@ AssertReversePostOrder(MIRGraph &graph)
 #ifdef DEBUG
 static void
 AssertDominatorTree(MIRGraph &graph)
 {
     // Check dominators.
     size_t i = graph.numBlocks();
     size_t totalNumDominated = 0;
     for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
+        JS_ASSERT(block->dominates(*block));
+
         MBasicBlock *idom = block->immediateDominator();
         JS_ASSERT(idom->dominates(*block));
         JS_ASSERT(idom == *block || idom->id() < block->id());
 
         if (idom == *block) {
-            totalNumDominated += block->numDominated() + 1;
+            totalNumDominated += block->numDominated();
         } else {
             bool foundInParent = false;
             for (size_t j = 0; j < idom->numImmediatelyDominatedBlocks(); j++) {
                 if (idom->getImmediatelyDominatedBlock(j) == *block) {
                     foundInParent = true;
                     break;
                 }
             }
             JS_ASSERT(foundInParent);
         }
 
-        size_t numDominated = 0;
+        size_t numDominated = 1;
         for (size_t j = 0; j < block->numImmediatelyDominatedBlocks(); j++) {
             MBasicBlock *dom = block->getImmediatelyDominatedBlock(j);
             JS_ASSERT(block->dominates(dom));
             JS_ASSERT(dom->id() > block->id());
             JS_ASSERT(dom->immediateDominator() == *block);
 
-            numDominated += dom->numDominated() + 1;
+            numDominated += dom->numDominated();
         }
         JS_ASSERT(block->numDominated() == numDominated);
-        JS_ASSERT(block->numDominated() + 1 <= i);
-        JS_ASSERT(block->numSuccessors() != 0 || block->numDominated() == 0);
+        JS_ASSERT(block->numDominated() <= i);
+        JS_ASSERT(block->numSuccessors() != 0 || block->numDominated() == 1);
         i--;
     }
     JS_ASSERT(i == 0);
     JS_ASSERT(totalNumDominated == graph.numBlocks());
 }
 #endif
 
 void
@@ -1527,17 +1531,17 @@ jit::AssertExtendedGraphCoherency(MIRGra
     AssertDominatorTree(graph);
 #endif
 }
 
 
 struct BoundsCheckInfo
 {
     MBoundsCheck *check;
-    uint32_t validUntil;
+    uint32_t validEnd;
 };
 
 typedef HashMap<uint32_t,
                 BoundsCheckInfo,
                 DefaultHasher<uint32_t>,
                 IonAllocPolicy> BoundsCheckMap;
 
 // Compute a hash for bounds checks which ignores constant offsets in the index.
@@ -1551,21 +1555,21 @@ BoundsCheckHashIgnoreOffset(MBoundsCheck
 }
 
 static MBoundsCheck *
 FindDominatingBoundsCheck(BoundsCheckMap &checks, MBoundsCheck *check, size_t index)
 {
     // See the comment in ValueNumberer::findDominatingDef.
     HashNumber hash = BoundsCheckHashIgnoreOffset(check);
     BoundsCheckMap::Ptr p = checks.lookup(hash);
-    if (!p || index > p->value().validUntil) {
+    if (!p || index >= p->value().validEnd) {
         // We didn't find a dominating bounds check.
         BoundsCheckInfo info;
         info.check = check;
-        info.validUntil = index + check->block()->numDominated();
+        info.validEnd = index + check->block()->numDominated();
 
         if(!checks.put(hash, info))
             return nullptr;
 
         return check;
     }
 
     return p->value().check;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4623,17 +4623,16 @@ IonBuilder::inlineCalls(CallInfo &callIn
         InliningStatus status = inlineSingleCall(inlineInfo, target);
         if (status == InliningStatus_Error)
             return false;
 
         // Natives may veto inlining.
         if (status == InliningStatus_NotInlined) {
             JS_ASSERT(target->isNative());
             JS_ASSERT(current == inlineBlock);
-            inlineBlock->discardAllResumePoints();
             graph().removeBlock(inlineBlock);
             choiceSet[i] = false;
             continue;
         }
 
         // inlineSingleCall() changed |current| to the inline return block.
         MBasicBlock *inlineReturnBlock = current;
         setCurrent(dispatchBlock);
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1895,19 +1895,18 @@ MacroAssembler::branchIfNotInterpretedCo
     branchTest32(Assembler::Zero, scratch, Imm32(bits), &done);
     {
         // The callee is either Function.prototype, an arrow function or
         // self-hosted. None of these are constructible, except self-hosted
         // constructors, so branch to |label| if SELF_HOSTED_CTOR is not set.
         branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::SELF_HOSTED_CTOR << 16), label);
 
 #ifdef DEBUG
-        // Function.prototype should not have the SELF_HOSTED_CTOR flag.
         branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::IS_FUN_PROTO << 16), &done);
-        breakpoint();
+        assumeUnreachable("Function.prototype should not have the SELF_HOSTED_CTOR flag");
 #endif
     }
     bind(&done);
 }
 
 void
 MacroAssembler::branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, Register tag,
                                         Label *label)
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -900,16 +900,17 @@ class MacroAssembler : public MacroAssem
     }
 
     void link(JitCode *code) {
         JS_ASSERT(!oom());
         // If this code can transition to C++ code and witness a GC, then we need to store
         // the JitCode onto the stack in order to GC it correctly.  exitCodePatch should
         // be unset if the code never needed to push its JitCode*.
         if (hasEnteredExitFrame()) {
+            exitCodePatch_.fixup(this);
             patchDataWithValueCheck(CodeLocationLabel(code, exitCodePatch_),
                                     ImmPtr(code),
                                     ImmPtr((void*)-1));
         }
 
     }
 
     // Generates code used to complete a bailout.
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -4801,28 +4801,28 @@ class LFloorF : public LInstructionHelpe
 };
 
 // Take the ceiling of a double precision number. Implements Math.ceil().
 class LCeil : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(Ceil)
 
-    LCeil(const LAllocation &num) {
+    explicit LCeil(const LAllocation &num) {
         setOperand(0, num);
     }
 };
 
 // Take the ceiling of a single precision number. Implements Math.ceil().
 class LCeilF : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(CeilF)
 
-    LCeilF(const LAllocation &num) {
+    explicit LCeilF(const LAllocation &num) {
         setOperand(0, num);
     }
 };
 
 // Round a double precision number. Implements Math.round().
 class LRound : public LInstructionHelper<1, 1, 1>
 {
   public:
@@ -5576,26 +5576,27 @@ class LGuardClass : public LInstructionH
 class MPhi;
 
 // Phi is a pseudo-instruction that emits no code, and is an annotation for the
 // register allocator. Like its equivalent in MIR, phis are collected at the
 // top of blocks and are meant to be executed in parallel, choosing the input
 // corresponding to the predecessor taken in the control flow graph.
 class LPhi MOZ_FINAL : public LInstruction
 {
-    LAllocation *inputs_;
+    LAllocation *const inputs_;
     LDefinition def_;
 
-    LPhi()
-    { }
-
   public:
     LIR_HEADER(Phi)
 
-    static LPhi *New(MIRGenerator *gen, MPhi *phi);
+    LPhi(MPhi *ins, LAllocation *inputs)
+        : inputs_(inputs)
+    {
+        setMir(ins);
+    }
 
     size_t numDefs() const {
         return 1;
     }
     LDefinition *getDef(size_t index) {
         JS_ASSERT(index == 0);
         return &def_;
     }
--- a/js/src/jit/LIR.cpp
+++ b/js/src/jit/LIR.cpp
@@ -13,27 +13,26 @@
 #include "jit/IonSpewer.h"
 #include "jit/MIR.h"
 #include "jit/MIRGenerator.h"
 
 using namespace js;
 using namespace js::jit;
 
 LIRGraph::LIRGraph(MIRGraph *mir)
-  : blocks_(mir->alloc()),
+  : blocks_(),
     constantPool_(mir->alloc()),
     constantPoolMap_(mir->alloc()),
     safepoints_(mir->alloc()),
     nonCallSafepoints_(mir->alloc()),
     numVirtualRegisters_(0),
     numInstructions_(1), // First id is 1.
     localSlotCount_(0),
     argumentSlotCount_(0),
     entrySnapshot_(nullptr),
-    osrBlock_(nullptr),
     mir_(*mir)
 {
 }
 
 bool
 LIRGraph::addConstantToPool(const Value &v, uint32_t *index)
 {
     JS_ASSERT(constantPoolMap_.initialized());
@@ -53,41 +52,75 @@ LIRGraph::noteNeedsSafepoint(LInstructio
     // Instructions with safepoints must be in linear order.
     JS_ASSERT_IF(!safepoints_.empty(), safepoints_.back()->id() < ins->id());
     if (!ins->isCall() && !nonCallSafepoints_.append(ins))
         return false;
     return safepoints_.append(ins);
 }
 
 void
-LIRGraph::removeBlock(size_t i)
-{
-    blocks_.erase(blocks_.begin() + i);
-}
-
-void
 LIRGraph::dump(FILE *fp) const
 {
     for (size_t i = 0; i < numBlocks(); i++) {
         getBlock(i)->dump(fp);
         fprintf(fp, "\n");
     }
 }
 
 void
 LIRGraph::dump() const
 {
     dump(stderr);
 }
 
+LBlock *
+LBlock::New(TempAllocator &alloc, MBasicBlock *from)
+{
+    LBlock *block = new(alloc) LBlock(from);
+    if (!block)
+        return nullptr;
+
+    // Count the number of LPhis we'll need.
+    size_t numLPhis = 0;
+    for (MPhiIterator i(from->phisBegin()), e(from->phisEnd()); i != e; ++i) {
+        MPhi *phi = *i;
+        numLPhis += (phi->type() == MIRType_Value) ? BOX_PIECES : 1;
+    }
+
+    // Allocate space for the LPhis.
+    if (!block->phis_.init(alloc, numLPhis))
+        return nullptr;
+
+    // For each MIR phi, set up LIR phis as appropriate. We'll fill in their
+    // operands on each incoming edge, and set their definitions at the start of
+    // their defining block.
+    size_t phiIndex = 0;
+    size_t numPreds = from->numPredecessors();
+    for (MPhiIterator i(from->phisBegin()), e(from->phisEnd()); i != e; ++i) {
+        MPhi *phi = *i;
+        MOZ_ASSERT(phi->numOperands() == numPreds);
+
+        int numPhis = (phi->type() == MIRType_Value) ? BOX_PIECES : 1;
+        for (int i = 0; i < numPhis; i++) {
+            void *array = alloc.allocateArray<sizeof(LAllocation)>(numPreds);
+            LAllocation *inputs = static_cast<LAllocation *>(array);
+            if (!inputs)
+                return nullptr;
+
+            new (&block->phis_[phiIndex++]) LPhi(phi, inputs);
+        }
+    }
+    return block;
+}
+
 uint32_t
 LBlock::firstId()
 {
     if (phis_.length()) {
-        return phis_[0]->id();
+        return phis_[0].id();
     } else {
         for (LInstructionIterator i(instructions_.begin()); i != instructions_.end(); i++) {
             if (i->id())
                 return i->id();
         }
     }
     return 0;
 }
@@ -271,29 +304,16 @@ LSnapshot::rewriteRecoveredInput(LUse in
     // Mark any operands to this snapshot with the same value as input as being
     // equal to the instruction's result.
     for (size_t i = 0; i < numEntries(); i++) {
         if (getEntry(i)->isUse() && getEntry(i)->toUse()->virtualRegister() == input.virtualRegister())
             setEntry(i, LUse(input.virtualRegister(), LUse::RECOVERED_INPUT));
     }
 }
 
-LPhi *
-LPhi::New(MIRGenerator *gen, MPhi *ins)
-{
-    LPhi *phi = new (gen->alloc()) LPhi();
-    LAllocation *inputs = gen->allocate<LAllocation>(ins->numOperands());
-    if (!inputs)
-        return nullptr;
-
-    phi->inputs_ = inputs;
-    phi->setMir(ins);
-    return phi;
-}
-
 void
 LInstruction::printName(FILE *fp, Opcode op)
 {
     static const char * const names[] =
     {
 #define LIROP(x) #x,
         LIR_OPCODE_LIST(LIROP)
 #undef LIROP
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -724,50 +724,39 @@ class LInstructionVisitor
 typedef InlineList<LInstruction>::iterator LInstructionIterator;
 typedef InlineList<LInstruction>::reverse_iterator LInstructionReverseIterator;
 
 class LPhi;
 class LMoveGroup;
 class LBlock : public TempObject
 {
     MBasicBlock *block_;
-    Vector<LPhi *, 4, IonAllocPolicy> phis_;
+    FixedList<LPhi> phis_;
     InlineList<LInstruction> instructions_;
     LMoveGroup *entryMoveGroup_;
     LMoveGroup *exitMoveGroup_;
     Label label_;
 
-    LBlock(TempAllocator &alloc, MBasicBlock *block)
+    explicit LBlock(MBasicBlock *block)
       : block_(block),
-        phis_(alloc),
+        phis_(),
         entryMoveGroup_(nullptr),
         exitMoveGroup_(nullptr)
     { }
 
   public:
-    static LBlock *New(TempAllocator &alloc, MBasicBlock *from) {
-        return new(alloc) LBlock(alloc, from);
-    }
+    static LBlock *New(TempAllocator &alloc, MBasicBlock *from);
     void add(LInstruction *ins) {
         instructions_.pushBack(ins);
     }
-    bool addPhi(LPhi *phi) {
-        return phis_.append(phi);
-    }
     size_t numPhis() const {
         return phis_.length();
     }
-    LPhi *getPhi(size_t index) const {
-        return phis_[index];
-    }
-    void removePhi(size_t index) {
-        phis_.erase(&phis_[index]);
-    }
-    void clearPhis() {
-        phis_.clear();
+    LPhi *getPhi(size_t index) {
+        return &phis_[index];
     }
     MBasicBlock *mir() const {
         return block_;
     }
     LInstructionIterator begin() {
         return instructions_.begin();
     }
     LInstructionIterator begin(LInstruction *at) {
@@ -1477,59 +1466,55 @@ class LIRGraph
         static HashNumber hash(const Value &v) {
             return HashNumber(v.asRawBits());
         }
         static bool match(const Value &lhs, const Value &rhs) {
             return lhs == rhs;
         }
     };
 
-
-    Vector<LBlock *, 16, IonAllocPolicy> blocks_;
+    FixedList<LBlock *> blocks_;
     Vector<Value, 0, IonAllocPolicy> constantPool_;
     typedef HashMap<Value, uint32_t, ValueHasher, IonAllocPolicy> ConstantPoolMap;
     ConstantPoolMap constantPoolMap_;
     Vector<LInstruction *, 0, IonAllocPolicy> safepoints_;
     Vector<LInstruction *, 0, IonAllocPolicy> nonCallSafepoints_;
     uint32_t numVirtualRegisters_;
     uint32_t numInstructions_;
 
     // Number of stack slots needed for local spills.
     uint32_t localSlotCount_;
     // Number of stack slots needed for argument construction for calls.
     uint32_t argumentSlotCount_;
 
     // Snapshot taken before any LIR has been lowered.
     LSnapshot *entrySnapshot_;
 
-    // LBlock containing LOsrEntry, or nullptr.
-    LBlock *osrBlock_;
-
     MIRGraph &mir_;
 
   public:
     explicit LIRGraph(MIRGraph *mir);
 
     bool init() {
-        return constantPoolMap_.init();
+        return constantPoolMap_.init() && blocks_.init(mir_.alloc(), mir_.numBlocks());
     }
     MIRGraph &mir() const {
         return mir_;
     }
     size_t numBlocks() const {
         return blocks_.length();
     }
     LBlock *getBlock(size_t i) const {
         return blocks_[i];
     }
     uint32_t numBlockIds() const {
         return mir_.numBlockIds();
     }
-    bool addBlock(LBlock *block) {
-        return blocks_.append(block);
+    void setBlock(size_t index, LBlock *block) {
+        blocks_[index] = block;
     }
     uint32_t getVirtualRegister() {
         numVirtualRegisters_ += VREG_INCREMENT;
         return numVirtualRegisters_;
     }
     uint32_t numVirtualRegisters() const {
         // Virtual registers are 1-based, not 0-based, so add one as a
         // convenience for 0-based arrays.
@@ -1584,37 +1569,29 @@ class LIRGraph
         JS_ASSERT(snapshot->bailoutKind() == Bailout_Normal);
         snapshot->setBailoutKind(Bailout_ArgumentCheck);
         entrySnapshot_ = snapshot;
     }
     LSnapshot *entrySnapshot() const {
         JS_ASSERT(entrySnapshot_);
         return entrySnapshot_;
     }
-    void setOsrBlock(LBlock *block) {
-        JS_ASSERT(!osrBlock_);
-        osrBlock_ = block;
-    }
-    LBlock *osrBlock() const {
-        return osrBlock_;
-    }
     bool noteNeedsSafepoint(LInstruction *ins);
     size_t numNonCallSafepoints() const {
         return nonCallSafepoints_.length();
     }
     LInstruction *getNonCallSafepoint(size_t i) const {
         return nonCallSafepoints_[i];
     }
     size_t numSafepoints() const {
         return safepoints_.length();
     }
     LInstruction *getSafepoint(size_t i) const {
         return safepoints_[i];
     }
-    void removeBlock(size_t i);
 
     void dump(FILE *fp) const;
     void dump() const;
 };
 
 LAllocation::LAllocation(AnyRegister reg)
 {
     if (reg.isFloat())
--- a/js/src/jit/LiveRangeAllocator.cpp
+++ b/js/src/jit/LiveRangeAllocator.cpp
@@ -813,24 +813,25 @@ LiveRangeAllocator<VREG, forLSRA>::build
                     }
                 }
 
                 // Terminate loop if out of work.
                 if (loopWorkList.empty())
                     break;
 
                 // Grab the next block off the work list, skipping any OSR block.
+                MBasicBlock *osrBlock = graph.mir().osrBlock();
                 while (!loopWorkList.empty()) {
                     loopBlock = loopWorkList.popCopy();
-                    if (loopBlock->lir() != graph.osrBlock())
+                    if (loopBlock != osrBlock)
                         break;
                 }
 
                 // If end is reached without finding a non-OSR block, then no more work items were found.
-                if (loopBlock->lir() == graph.osrBlock()) {
+                if (loopBlock == osrBlock) {
                     JS_ASSERT(loopWorkList.empty());
                     break;
                 }
             }
 
             // Clear the done set for other loops
             loopDone->clear();
         }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3712,59 +3712,33 @@ LIRGenerator::visitBlock(MBasicBlock *bl
     // Now emit the last instruction, which is some form of branch.
     if (!visitInstruction(block->lastIns()))
         return false;
 
     return true;
 }
 
 bool
-LIRGenerator::precreatePhi(LBlock *block, MPhi *phi)
-{
-    LPhi *lir = LPhi::New(gen, phi);
-    if (!lir)
-        return false;
-    if (!block->addPhi(lir))
-        return false;
-    return true;
-}
-
-bool
 LIRGenerator::generate()
 {
     // Create all blocks and prep all phis beforehand.
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
         if (gen->shouldCancel("Lowering (preparation loop)"))
             return false;
 
         current = LBlock::New(alloc(), *block);
         if (!current)
             return false;
-        if (!lirGraph_.addBlock(current))
-            return false;
+        lirGraph_.setBlock(block->id(), current);
         block->assignLir(current);
-
-        // For each MIR phi, add LIR phis as appropriate. We'll fill in their
-        // operands on each incoming edge, and set their definitions at the
-        // start of their defining block.
-        for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
-            int numPhis = (phi->type() == MIRType_Value) ? BOX_PIECES : 1;
-            for (int i = 0; i < numPhis; i++) {
-                if (!precreatePhi(block->lir(), *phi))
-                    return false;
-            }
-        }
     }
 
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd()