Merge m-c to fx-team, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 22 Sep 2015 16:48:10 -0700
changeset 263971 0f7d12dd725225796ef2011843d4e9ff8e86d674
parent 263970 81cb24e420d1e6e4eb7969075ac0879600c558b1 (current diff)
parent 263866 05a7ee49d40a4cfabf2479337fd5e1312e178b6d (diff)
child 263972 3450ce49c7d74dcee0b9272a62d0e861b44b2a46
push id65484
push usercbook@mozilla.com
push dateWed, 23 Sep 2015 10:47:13 +0000
treeherdermozilla-inbound@88067e5193f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team, a=merge
dom/webidl/CSS2PropertiesProps.h
editor/composer/test/test_abug697981.html
modules/brotli/dec/safe_malloc.c
modules/brotli/dec/safe_malloc.h
--- a/b2g/components/test/mochitest/test_permission_deny.html
+++ b/b2g/components/test/mochitest/test_permission_deny.html
@@ -38,17 +38,17 @@ function runNext() {
   if (gTests.length > 0) {
     // Put the requested permission in query string
     let requestedType = gTests.shift();
     info('getUserMedia for ' + JSON.stringify(requestedType));
     navigator.mozGetUserMedia(requestedType, function success() {
       ok(false, 'unexpected success, permission request should be denied');
       runNext();
     }, function failure(err) {
-      is(err.name, 'PermissionDeniedError', 'expected permission denied');
+      is(err.name, 'SecurityError', 'expected permission denied');
       runNext();
     });
   } else {
     info('test finished, teardown');
     gScript.sendAsyncMessage('teardown', '');
     gScript.destroy();
     SimpleTest.finish();
   }
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,21 +14,21 @@
   <!--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="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <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="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="12ff7481566587aa4198cf1287598acb3a999973"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
--- 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="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <!-- 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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,21 +14,21 @@
   <!--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="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <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="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="27eb2f04e149fc2c9976d881b1b5984bbe7ee089"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="067c08fb3e5744b42b68d1f861245f7d507109bc"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="12ff7481566587aa4198cf1287598acb3a999973"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "68361828ae88dffd04b250121b5f2472a63f4bf0", 
+        "git_revision": "864500d40633bbf0e9a83c92a03cea46bb901906", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "0a2a22652bcff3cde717b1073dd6b287003a4ed2", 
+    "revision": "7ba01d2c6e7edec8a5dc823ccf34cb26eb62169a", 
     "repo_path": "integration/gaia-central"
 }
--- 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="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <!-- 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/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="68361828ae88dffd04b250121b5f2472a63f4bf0"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="864500d40633bbf0e9a83c92a03cea46bb901906"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="9465d16f95ab87636b2ae07538ee88e5aeff2d7d"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="2782648aabf0af464dd9c4202b367b408898546d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f004530b30a63c08a16d82536858600446b2abf5"/>
--- a/browser/base/content/test/general/browser_devices_get_user_media.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media.js
@@ -218,17 +218,17 @@ function* checkNotSharing() {
   is(getMediaCaptureState(), "none", "expected nothing to be shared");
 
   ok(!PopupNotifications.getNotification("webRTC-sharingDevices"),
      "no webRTC-sharingDevices popup notification");
 
   yield* assertWebRTCIndicatorStatus(null);
 }
 
-const permissionError = "error: PermissionDeniedError: The user did not grant permission for the operation.";
+const permissionError = "error: SecurityError: The operation is insecure.";
 
 var gTests = [
 
 {
   desc: "getUserMedia audio+video",
   run: function checkAudioVideo() {
     yield promisePopupNotificationShown("webRTC-shareDevices", () => {
       info("requesting devices");
--- a/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js
@@ -226,17 +226,17 @@ registerCleanupFunction(function() {
   gBrowser.removeCurrentTab();
   kObservedTopics.forEach(topic => {
     Services.obs.removeObserver(observer, topic);
   });
   Services.prefs.clearUserPref(PREF_PERMISSION_FAKE);
   Services.prefs.setCharPref(PREF_LOOP_CSP, originalLoopCsp);
 });
 
-const permissionError = "error: PermissionDeniedError: The user did not grant permission for the operation.";
+const permissionError = "error: SecurityError: The operation is insecure.";
 
 var gTests = [
 
 {
   desc: "getUserMedia about:loopconversation shouldn't prompt",
   run: function checkAudioVideoLoop() {
     Services.prefs.setCharPref(PREF_LOOP_CSP, "default-src 'unsafe-inline'");
 
--- a/browser/base/content/test/general/browser_devices_get_user_media_in_frame.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media_in_frame.js
@@ -216,18 +216,16 @@ function* checkNotSharing() {
 
   yield* assertWebRTCIndicatorStatus(null);
 }
 
 function getFrameGlobal(aFrameId) {
   return content.wrappedJSObject.document.getElementById(aFrameId).contentWindow;
 }
 
-const permissionError = "error: PermissionDeniedError: The user did not grant permission for the operation.";
-
 var gTests = [
 
 {
   desc: "getUserMedia audio+video",
   run: function checkAudioVideo() {
     let global = getFrameGlobal("frame1");
     yield promisePopupNotificationShown("webRTC-shareDevices", () => {
       info("requesting devices");
--- a/browser/components/migration/nsEdgeReadingListExtractor.cpp
+++ b/browser/components/migration/nsEdgeReadingListExtractor.cpp
@@ -39,38 +39,41 @@ nsEdgeReadingListExtractor::Extract(cons
   JET_ERR err;
   JET_INSTANCE instance;
   JET_SESID sesid;
   JET_DBID dbid;
   JET_TABLEID tableid;
   JET_COLUMNDEF urlColumnInfo = { 0 };
   JET_COLUMNDEF titleColumnInfo = { 0 };
   JET_COLUMNDEF addedDateColumnInfo = { 0 };
+  FILETIME addedDate;
+  wchar_t urlBuffer[MAX_URL_LENGTH] = { 0 };
+  wchar_t titleBuffer[MAX_TITLE_LENGTH] = { 0 };
 
   // Need to ensure this happens before we skip ahead to CloseDB,
   // otherwise the compiler complains.
   nsCOMPtr<nsIMutableArray> items = do_CreateInstance(NS_ARRAY_CONTRACTID);
 
   // JET does not throw exceptions, and so error handling and ensuring we close
   // the DB is a bit finnicky. Keep track of how far we got so we guarantee closing
   // the right things
   bool instanceCreated, sessionCreated, dbOpened, tableOpened;
 
   // Check for the right page size and initialize with that
   unsigned long pageSize;
   err = JetGetDatabaseFileInfoW(static_cast<char16ptr_t>(aDBPath.BeginReading()),
                                 &pageSize, sizeof(pageSize), JET_DbInfoPageSize);
   NS_HANDLE_JET_ERROR(err)
-  err = JetSetSystemParameter(&instance, NULL, JET_paramDatabasePageSize, pageSize, NULL);
+  err = JetSetSystemParameter(&instance, 0, JET_paramDatabasePageSize, pageSize, NULL);
   NS_HANDLE_JET_ERROR(err)
 
   // Turn off recovery, because otherwise we will create log files in either the cwd or
   // overwrite Edge's own logfiles, which is useless at best and at worst might mess with
   // Edge actually using the DB
-  err = JetSetSystemParameter(&instance, NULL, JET_paramRecovery, NULL, "Off");
+  err = JetSetSystemParameter(&instance, 0, JET_paramRecovery, 0, "Off");
   NS_HANDLE_JET_ERROR(err)
 
   // Start our session:
   err = JetCreateInstance(&instance, "edge_readinglist_migration");
   NS_HANDLE_JET_ERROR(err)
   instanceCreated = true;
 
   err = JetInit(&instance);
@@ -117,43 +120,36 @@ nsEdgeReadingListExtractor::Extract(cons
   // verify the column types are what we expect:
   if (urlColumnInfo.coltyp != JET_coltypLongText ||
       titleColumnInfo.coltyp != JET_coltypLongText ||
       addedDateColumnInfo.coltyp != JET_coltypLongLong) {
     rv = NS_ERROR_NOT_IMPLEMENTED;
     goto CloseDB;
   }
 
-  JET_COLUMNID urlColumnId = urlColumnInfo.columnid;
-  JET_COLUMNID titleColumnId = titleColumnInfo.columnid;
-  JET_COLUMNID addedDateColumnId = addedDateColumnInfo.columnid;
-
   // If we got here, we've found our table and column information
 
   err = JetMove(sesid, tableid, JET_MoveFirst, 0);
   // It's possible there are 0 items in this table, in which case we want to
   // not fail:
   if (err == JET_errNoCurrentRecord) {
     items.forget(aItems);
     goto CloseDB;
   }
   // Check for any other errors
   NS_HANDLE_JET_ERROR(err)
 
-  FILETIME addedDate;
-  wchar_t urlBuffer[MAX_URL_LENGTH] = { 0 };
-  wchar_t titleBuffer[MAX_TITLE_LENGTH] = { 0 };
   do {
-    err = JetRetrieveColumn(sesid, tableid, urlColumnId, &urlBuffer,
+    err = JetRetrieveColumn(sesid, tableid, urlColumnInfo.columnid, &urlBuffer,
                             sizeof(urlBuffer), NULL, 0, NULL);
     NS_HANDLE_JET_ERROR(err)
-    err = JetRetrieveColumn(sesid, tableid, titleColumnId, &titleBuffer,
+    err = JetRetrieveColumn(sesid, tableid, titleColumnInfo.columnid, &titleBuffer,
                             sizeof(titleBuffer), NULL, 0, NULL);
     NS_HANDLE_JET_ERROR(err)
-    err = JetRetrieveColumn(sesid, tableid, addedDateColumnId, &addedDate,
+    err = JetRetrieveColumn(sesid, tableid, addedDateColumnInfo.columnid, &addedDate,
                             sizeof(addedDate), NULL, 0, NULL);
     NS_HANDLE_JET_ERROR(err)
     nsCOMPtr<nsIWritablePropertyBag2> pbag = do_CreateInstance("@mozilla.org/hash-property-bag;1");
     bool dateIsValid;
     PRTime prAddedDate = WinMigrationFileTimeToPRTime(&addedDate, &dateIsValid);
     nsDependentString url(urlBuffer);
     nsDependentString title(titleBuffer);
     pbag->SetPropertyAsAString(NS_LITERAL_STRING("uri"), url);
--- a/browser/config/mozconfigs/linux64/debug-static-analysis-clang
+++ b/browser/config/mozconfigs/linux64/debug-static-analysis-clang
@@ -19,8 +19,9 @@ ac_add_options --enable-warnings-as-erro
 
 # Avoid dependency on libstdc++ 4.7
 ac_add_options --enable-stdcxx-compat
 
 export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
 . $topsrcdir/build/unix/mozconfig.gtk
 
 . "$topsrcdir/build/mozconfig.common.override"
+. "$topsrcdir/build/mozconfig.cache"
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/linux64/opt-static-analysis-clang
@@ -0,0 +1,26 @@
+MOZ_AUTOMATION_BUILD_SYMBOLS=0
+MOZ_AUTOMATION_PACKAGE_TESTS=0
+MOZ_AUTOMATION_L10N_CHECK=0
+
+. "$topsrcdir/build/mozconfig.common"
+
+ac_add_options --enable-dmd
+
+# Use Clang as specified in manifest
+CC="$topsrcdir/clang/bin/clang"
+CXX="$topsrcdir/clang/bin/clang++"
+
+# Add the static checker
+ac_add_options --enable-clang-plugin
+
+# Treat warnings as errors (modulo ALLOW_COMPILER_WARNINGS).
+ac_add_options --enable-warnings-as-errors
+
+# Avoid dependency on libstdc++ 4.7
+ac_add_options --enable-stdcxx-compat
+
+export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig
+. $topsrcdir/build/unix/mozconfig.gtk
+
+. "$topsrcdir/build/mozconfig.common.override"
+. "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -1,19 +1,26 @@
 [
 {
 "clang_version": "r241406"
 }, 
 {
-"size": 100307285, 
-"digest": "4d147d0072a928945fc1e938f39a5d0a9d3c676399c09e092c8750b2f973cdbbebda8d94d4d05805fae74a5c49c54263dc22b8b443c23c9a0ae830a261d3cf30", 
-"algorithm": "sha512", 
-"filename": "clang.tar.bz2",
+"size": 83297360,
+"digest": "18e3deaf608b58a9153d647e1acbe6e93b7d6461bd4f86f24d13f4b6818b048a65063200d7acb100fa41eb5a7e66dfe6bdc89770c15c87e32a3e9a50d97094c6",
+"algorithm": "sha512",
+"filename": "clang.tar.xz",
 "unpack": true
 },
 {
 "size": 12057960,
 "digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "unpack": true
+},
+{
+"size": 167175,
+"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
+"algorithm": "sha512",
+"filename": "sccache.tar.bz2",
+"unpack": true
 }
 ]
new file mode 100644
--- /dev/null
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest.centos6
@@ -0,0 +1,19 @@
+[
+{
+"clang_version": "r241406"
+},
+{
+"size": 83297360,
+"digest": "18e3deaf608b58a9153d647e1acbe6e93b7d6461bd4f86f24d13f4b6818b048a65063200d7acb100fa41eb5a7e66dfe6bdc89770c15c87e32a3e9a50d97094c6",
+"algorithm": "sha512",
+"filename": "clang.tar.xz",
+"unpack": true
+},
+{
+"size": 12057960,
+"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"algorithm": "sha512",
+"filename": "gtk3.tar.xz",
+"unpack": true
+}
+]
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -524,17 +524,18 @@ class Automation(object):
 
   def checkForCrashes(self, minidumpDir, symbolsPath):
     return mozcrash.check_for_crashes(minidumpDir, symbolsPath, test_name=self.lastTestSeen)
 
   def runApp(self, testURL, env, app, profileDir, extraArgs, utilityPath = None,
              xrePath = None, certPath = None,
              debuggerInfo = None, symbolsPath = None,
              timeout = -1, maxTime = None, onLaunch = None,
-             detectShutdownLeaks = False, screenshotOnFail=False, testPath=None, bisectChunk=None):
+             detectShutdownLeaks = False, screenshotOnFail=False, testPath=None, bisectChunk=None,
+             valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
     """
     Run the app, log the duration it took to execute, return the status code.
     Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
     """
 
     if utilityPath == None:
       utilityPath = self.DIST_BIN
     if xrePath == None:
--- a/build/unix/build-clang/build-clang.py
+++ b/build/unix/build-clang/build-clang.py
@@ -5,16 +5,20 @@
 
 import os
 import os.path
 import shutil
 import subprocess
 import platform
 import json
 import argparse
+import tempfile
+import glob
+import errno
+from contextlib import contextmanager
 
 centOS6 = False
 
 
 def check_run(args):
     r = subprocess.call(args)
     assert r == 0
 
@@ -37,37 +41,88 @@ def build_package(package_source_dir, pa
     if not os.path.exists(package_build_dir):
         os.mkdir(package_build_dir)
     run_in(package_build_dir,
            ["%s/configure" % package_source_dir] + configure_args)
     run_in(package_build_dir, ["make", "-j4"] + make_args)
     run_in(package_build_dir, ["make", "install"])
 
 
-def with_env(env, f):
+@contextmanager
+def updated_env(env):
     old_env = os.environ.copy()
     os.environ.update(env)
-    f()
+    yield
     os.environ.clear()
     os.environ.update(old_env)
 
 
 def build_tar_package(tar, name, base, directory):
     name = os.path.realpath(name)
-    run_in(base, [tar, "-cjf", name, directory])
+    run_in(base, [tar, "-cJf", name, directory])
+
+
+def copy_dir_contents(src, dest):
+    for f in glob.glob("%s/*" % src):
+        try:
+            destname = "%s/%s" % (dest, os.path.basename(f))
+            shutil.copytree(f, destname)
+        except OSError as e:
+            if e.errno == errno.ENOTDIR:
+                shutil.copy2(f, destname)
+            elif e.errno == errno.EEXIST:
+                if os.path.isdir(f):
+                    copy_dir_contents(f, destname)
+                else:
+                    os.remove(destname)
+                    shutil.copy2(f, destname)
+            else:
+                raise Exception('Directory not copied. Error: %s' % e)
+
+
+def mkdir_p(path):
+    try:
+        os.makedirs(path)
+    except OSError as e:
+        if e.errno != errno.EEXIST or not os.path.isdir(path):
+            raise
+
+
+def build_and_use_libgcc(env, clang_dir):
+    with updated_env(env):
+        tempdir = tempfile.mkdtemp()
+        gcc_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                               "..", "build-gcc")
+        run_in(gcc_dir, ["./build-gcc.sh", tempdir, "libgcc"])
+        run_in(tempdir, ["tar", "-xf", "gcc.tar.xz"])
+        libgcc_dir = glob.glob(os.path.join(tempdir,
+                                            "gcc", "lib", "gcc",
+                                            "x86_64-unknown-linux-gnu",
+                                            "[0-9]*"))[0]
+        clang_lib_dir = os.path.join(clang_dir, "lib", "gcc",
+                                     "x86_64-unknown-linux-gnu",
+                                     os.path.basename(libgcc_dir))
+        mkdir_p(clang_lib_dir)
+        copy_dir_contents(libgcc_dir, clang_lib_dir)
+        libgcc_dir = os.path.join(tempdir, "gcc", "lib64")
+        clang_lib_dir = os.path.join(clang_dir, "lib")
+        copy_dir_contents(libgcc_dir, clang_lib_dir)
+        include_dir = os.path.join(tempdir, "gcc", "include")
+        clang_include_dir = os.path.join(clang_dir, "include")
+        copy_dir_contents(include_dir, clang_include_dir)
+        shutil.rmtree(tempdir)
 
 
 def svn_co(url, directory, revision):
     check_run(["svn", "co", "-r", revision, url, directory])
 
 
-def build_one_stage(env, stage_dir, llvm_source_dir, gcc_toolchain_dir):
-    def f():
-        build_one_stage_aux(stage_dir, llvm_source_dir, gcc_toolchain_dir)
-    with_env(env, f)
+def build_one_stage(env, stage_dir, llvm_source_dir):
+    with updated_env(env):
+        build_one_stage_aux(stage_dir, llvm_source_dir)
 
 
 def get_platform():
     p = platform.system()
     if p == "Darwin":
         return "macosx64"
     elif p == "Linux":
         if platform.processor() == "x86_64":
@@ -77,17 +132,17 @@ def get_platform():
     else:
         raise NotImplementedError("Not supported platform")
 
 
 def is_darwin():
     return platform.system() == "Darwin"
 
 
-def build_one_stage_aux(stage_dir, llvm_source_dir, gcc_toolchain_dir):
+def build_one_stage_aux(stage_dir, llvm_source_dir):
     os.mkdir(stage_dir)
 
     build_dir = stage_dir + "/build"
     inst_dir = stage_dir + "/clang"
 
     targets = ["x86", "x86_64"]
     # The Darwin equivalents of binutils appear to have intermittent problems
     # with objects in compiler-rt that are compiled for arm.  Since the arm
@@ -103,17 +158,16 @@ def build_one_stage_aux(stage_dir, llvm_
         python_path = "/usr/local/bin/python2.7"
 
     configure_opts = ["--enable-optimized",
                       "--enable-targets=" + ",".join(targets),
                       "--disable-assertions",
                       "--disable-libedit",
                       "--with-python=%s" % python_path,
                       "--prefix=%s" % inst_dir,
-                      "--with-gcc-toolchain=%s" % gcc_toolchain_dir,
                       "--disable-compiler-version-checks"]
     build_package(llvm_source_dir, build_dir, configure_opts, [])
 
 if __name__ == "__main__":
     # The directories end up in the debug info, so the easy way of getting
     # a reproducible build is to run it in a know absolute directory.
     # We use a directory in /builds/slave because the mozilla infrastructure
     # cleans it up automatically.
@@ -175,30 +229,37 @@ if __name__ == "__main__":
         extra_cxxflags = "-stdlib=libc++"
         extra_cflags2 = ""
         extra_cxxflags2 = "-stdlib=libc++"
         cc = "/usr/bin/clang"
         cxx = "/usr/bin/clang++"
     else:
         extra_cflags = ""
         extra_cxxflags = ""
-        extra_cflags2 = "-static-libgcc"
-        extra_cxxflags2 = "-static-libgcc -static-libstdc++"
+        extra_cflags2 = "-static-libgcc --gcc-toolchain=%s" % gcc_dir
+        extra_cxxflags2 = "-static-libgcc -static-libstdc++ --gcc-toolchain=%s" % gcc_dir
         cc = gcc_dir + "/bin/gcc"
         cxx = gcc_dir + "/bin/g++"
 
     if os.environ.has_key('LD_LIBRARY_PATH'):
         os.environ['LD_LIBRARY_PATH'] = '%s/lib64/:%s' % (gcc_dir, os.environ['LD_LIBRARY_PATH']);
     else:
         os.environ['LD_LIBRARY_PATH'] = '%s/lib64/' % gcc_dir
 
     build_one_stage(
         {"CC": cc + " %s" % extra_cflags,
          "CXX": cxx + " %s" % extra_cxxflags},
-        stage1_dir, llvm_source_dir, gcc_dir)
+        stage1_dir, llvm_source_dir)
 
     stage2_dir = build_dir + '/stage2'
     build_one_stage(
         {"CC": stage1_inst_dir + "/bin/clang %s" % extra_cflags2,
          "CXX": stage1_inst_dir + "/bin/clang++ %s" % extra_cxxflags2},
-        stage2_dir, llvm_source_dir, gcc_dir)
+        stage2_dir, llvm_source_dir)
 
-    build_tar_package("tar", "clang.tar.bz2", stage2_dir, "clang")
+    if not is_darwin():
+        stage2_inst_dir = stage2_dir + '/clang'
+        build_and_use_libgcc(
+            {"CC": cc + " %s" % extra_cflags,
+             "CXX": cxx + " %s" % extra_cxxflags},
+            stage2_inst_dir)
+
+    build_tar_package("tar", "clang.tar.xz", stage2_dir, "clang")
--- a/build/unix/build-gcc/build-gcc.sh
+++ b/build/unix/build-gcc/build-gcc.sh
@@ -2,28 +2,33 @@
 
 gcc_version=4.7.3
 binutils_version=2.23.1
 this_path=$(readlink -f $(dirname $0))
 gcc_bt_patch=${this_path}/gcc-bt.patch
 gcc_pr55650_patch=${this_path}/gcc48-pr55650.patch
 make_flags='-j12'
 
-root_dir=$(mktemp -d)
+root_dir="$1"
+if [ -z "$root_dir" -o ! -d "$root_dir" ]; then
+  root_dir=$(mktemp -d)
+fi
 cd $root_dir
 
 if test -z $TMPDIR; then
   TMPDIR=/tmp/
 fi
 
 wget -c -P $TMPDIR ftp://ftp.gnu.org/gnu/binutils/binutils-$binutils_version.tar.bz2 || exit 1
 tar xjf $TMPDIR/binutils-$binutils_version.tar.bz2
 mkdir binutils-objdir
 cd binutils-objdir
-../binutils-$binutils_version/configure --prefix /tools/gcc/ --enable-gold  --enable-plugins --disable-nls || exit 1
+# gold is disabled because we don't use it on automation, and also we ran into
+# some issues with it using this script in build-clang.py.
+../binutils-$binutils_version/configure --prefix /tools/gcc/ --disable-gold --enable-plugins --disable-nls || exit 1
 make $make_flags || exit 1
 make install $make_flags DESTDIR=$root_dir || exit 1
 cd ..
 
 case "$gcc_version" in
 *-*)
   wget -c -P $TMPDIR ftp://gcc.gnu.org/pub/gcc/snapshots/$gcc_version/gcc-$gcc_version.tar.bz2 || exit 1
   ;;
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -57,16 +57,20 @@ OriginAttributes::CreateSuffix(nsACStrin
   }
 
   if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
     value.Truncate();
     value.AppendInt(mUserContextId);
     params->Set(NS_LITERAL_STRING("userContextId"), value);
   }
 
+  if (!mSignedPkg.IsEmpty()) {
+    params->Set(NS_LITERAL_STRING("signedPkg"), mSignedPkg);
+  }
+
   aStr.Truncate();
 
   params->Serialize(value);
   if (!value.IsEmpty()) {
     aStr.AppendLiteral("^");
     aStr.Append(NS_ConvertUTF16toUTF8(value));
   }
 
@@ -127,16 +131,22 @@ public:
       mOriginAttributes->mUserContextId = aValue.ToInteger(&rv);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return false;
       }
 
       return true;
     }
 
+    if (aName.EqualsLiteral("signedPkg")) {
+      MOZ_RELEASE_ASSERT(mOriginAttributes->mSignedPkg.IsEmpty());
+      mOriginAttributes->mSignedPkg.Assign(aValue);
+      return true;
+    }
+
     // No other attributes are supported.
     return false;
   }
 
 private:
   OriginAttributes* mOriginAttributes;
 };
 
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -31,17 +31,18 @@ public:
   explicit OriginAttributes(const OriginAttributesDictionary& aOther)
     : OriginAttributesDictionary(aOther) {}
 
   bool operator==(const OriginAttributes& aOther) const
   {
     return mAppId == aOther.mAppId &&
            mInBrowser == aOther.mInBrowser &&
            mAddonId == aOther.mAddonId &&
-           mUserContextId == aOther.mUserContextId;
+           mUserContextId == aOther.mUserContextId &&
+           mSignedPkg == aOther.mSignedPkg;
   }
   bool operator!=(const OriginAttributes& aOther) const
   {
     return !(*this == aOther);
   }
 
   // Serializes/Deserializes non-default values into the suffix format, i.e.
   // |!key1=value1&key2=value2|. If there are no non-default attributes, this
@@ -83,16 +84,20 @@ public:
     if (mAddonId.WasPassed() && mAddonId.Value() != aAttrs.mAddonId) {
       return false;
     }
 
     if (mUserContextId.WasPassed() && mUserContextId.Value() != aAttrs.mUserContextId) {
       return false;
     }
 
+    if (mSignedPkg.WasPassed() && mSignedPkg.Value() != aAttrs.mSignedPkg) {
+      return false;
+    }
+
     return true;
   }
 };
 
 /*
  * Base class from which all nsIPrincipal implementations inherit. Use this for
  * default implementations and other commonalities between principal
  * implementations.
--- a/caps/tests/unit/test_origin.js
+++ b/caps/tests/unit/test_origin.js
@@ -131,22 +131,38 @@ function run_test() {
 
   // UserContext and App.
   var exampleOrg_userContextApp = ssm.createCodebasePrincipal(makeURI('http://example.org'), {appId: 24, userContextId: 42});
   var nullPrin_userContextApp = ssm.createNullPrincipal({appId: 24, userContextId: 42});
   checkOriginAttributes(exampleOrg_userContextApp, {appId: 24, userContextId: 42}, '^appId=24&userContextId=42');
   checkOriginAttributes(nullPrin_userContextApp, {appId: 24, userContextId: 42}, '^appId=24&userContextId=42');
   do_check_eq(exampleOrg_userContextApp.origin, 'http://example.org^appId=24&userContextId=42');
 
+  // Just signedPkg
+  var exampleOrg_signedPkg = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever'});
+  checkOriginAttributes(exampleOrg_signedPkg, { signedPkg: 'id' }, '^signedPkg=whatever');
+  do_check_eq(exampleOrg_signedPkg.origin, 'http://example.org^signedPkg=whatever');
+
+  // signedPkg and browser
+  var exampleOrg_signedPkg_browser = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatever', inBrowser: true});
+  checkOriginAttributes(exampleOrg_signedPkg_browser, { signedPkg: 'whatever', inBrowser: true }, '^inBrowser=1&signedPkg=whatever');
+  do_check_eq(exampleOrg_signedPkg_browser.origin, 'http://example.org^inBrowser=1&signedPkg=whatever');
+
+  // Just signedPkg (but different value from 'exampleOrg_signedPkg_app')
+  var exampleOrg_signedPkg_another = ssm.createCodebasePrincipal(makeURI('http://example.org'), {signedPkg: 'whatup'});
+
   // Check that all of the above are cross-origin.
   checkCrossOrigin(exampleOrg_app, exampleOrg);
   checkCrossOrigin(exampleOrg_app, nullPrin_app);
   checkCrossOrigin(exampleOrg_browser, exampleOrg_app);
   checkCrossOrigin(exampleOrg_browser, nullPrin_browser);
   checkCrossOrigin(exampleOrg_appBrowser, exampleOrg_app);
   checkCrossOrigin(exampleOrg_appBrowser, nullPrin_appBrowser);
   checkCrossOrigin(exampleOrg_appBrowser, exampleCom_appBrowser);
   checkCrossOrigin(exampleOrg_addon, exampleOrg);
   checkCrossOrigin(exampleOrg_userContext, exampleOrg);
   checkCrossOrigin(exampleOrg_userContextAddon, exampleOrg);
   checkCrossOrigin(exampleOrg_userContext, exampleOrg_userContextAddon);
   checkCrossOrigin(exampleOrg_userContext, exampleOrg_userContextApp);
+  checkCrossOrigin(exampleOrg_signedPkg, exampleOrg);
+  checkCrossOrigin(exampleOrg_signedPkg, exampleOrg_signedPkg_browser);
+  checkCrossOrigin(exampleOrg_signedPkg, exampleOrg_signedPkg_another);
 }
--- a/configure.in
+++ b/configure.in
@@ -1990,16 +1990,17 @@ case "$target" in
                                    ac_cv_ios_target="no")])
     if test "$ac_cv_ios_target" = "yes" -a -z $MOZ_IOS; then
        AC_MSG_ERROR([targeting iOS but not using an iOS SDK?])
     fi
     if test -n "$MOZ_IOS"; then
         AC_DEFINE(XP_IOS)
         AC_DEFINE(XP_DARWIN)
         _PLATFORM_DEFAULT_TOOLKIT='cairo-uikit'
+        direct_nspr_config=1
     else
         AC_DEFINE(XP_MACOSX)
         AC_DEFINE(XP_DARWIN)
         _PLATFORM_DEFAULT_TOOLKIT='cairo-cocoa'
         # The ExceptionHandling framework is needed for Objective-C exception
         # logging code in nsObjCExceptions.h. Currently we only use that in debug
         # builds.
         MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling";
--- a/devtools/client/netmonitor/har/test/browser_net_har_post_data.js
+++ b/devtools/client/netmonitor/har/test/browser_net_har_post_data.js
@@ -24,16 +24,16 @@ add_task(function*() {
   let har = JSON.parse(jsonString);
 
   // Check out the HAR log.
   isnot(har.log, null, "The HAR log must exist");
   is(har.log.pages.length, 1, "There must be one page");
   is(har.log.entries.length, 1, "There must be one request");
 
   let entry = har.log.entries[0];
-  is(entry.request.postData.mimeType, "application/json; charset=UTF-8",
+  is(entry.request.postData.mimeType, "application/json",
     "Check post data content type");
   is(entry.request.postData.text, "{'first': 'John', 'last': 'Doe'}",
     "Check post data payload");
 
   // Clean up
   teardown(aMonitor).then(finish);
 });
--- a/dom/base/Attr.cpp
+++ b/dom/base/Attr.cpp
@@ -157,39 +157,22 @@ Attr::SetOwnerDocument(nsIDocument* aDoc
 
 NS_IMETHODIMP
 Attr::GetName(nsAString& aName)
 {
   aName = NodeName();
   return NS_OK;
 }
 
-already_AddRefed<nsIAtom>
-Attr::GetNameAtom(nsIContent* aContent)
-{
-  if (!mNsAware &&
-      mNodeInfo->NamespaceID() == kNameSpaceID_None &&
-      aContent->IsInHTMLDocument() &&
-      aContent->IsHTMLElement()) {
-    nsString name;
-    mNodeInfo->GetName(name);
-    nsAutoString lowercaseName;
-    nsContentUtils::ASCIIToLower(name, lowercaseName);
-    return do_GetAtom(lowercaseName);
-  }
-  nsCOMPtr<nsIAtom> nameAtom = mNodeInfo->NameAtom();
-  return nameAtom.forget();
-}
-
 NS_IMETHODIMP
 Attr::GetValue(nsAString& aValue)
 {
   Element* element = GetElement();
   if (element) {
-    nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(element);
+    nsCOMPtr<nsIAtom> nameAtom = mNodeInfo->NameAtom();
     element->GetAttr(mNodeInfo->NamespaceID(), nameAtom, aValue);
   }
   else {
     aValue = mValue;
   }
 
   return NS_OK;
 }
@@ -198,17 +181,17 @@ void
 Attr::SetValue(const nsAString& aValue, ErrorResult& aRv)
 {
   Element* element = GetElement();
   if (!element) {
     mValue = aValue;
     return;
   }
 
-  nsCOMPtr<nsIAtom> nameAtom = GetNameAtom(element);
+  nsCOMPtr<nsIAtom> nameAtom = mNodeInfo->NameAtom();
   aRv = element->SetAttr(mNodeInfo->NamespaceID(),
                          nameAtom,
                          mNodeInfo->GetPrefixAtom(),
                          aValue,
                          true);
 }
 
 NS_IMETHODIMP
--- a/dom/base/Attr.h
+++ b/dom/base/Attr.h
@@ -102,17 +102,15 @@ protected:
   virtual Element* GetNameSpaceElement() override
   {
     return GetElement();
   }
 
   static bool sInitialized;
 
 private:
-  already_AddRefed<nsIAtom> GetNameAtom(nsIContent* aContent);
-
   nsString mValue;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_Attr_h */
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1233,17 +1233,19 @@ Element::RemoveAttributeNode(Attr& aAttr
 {
   Element *elem = aAttribute.GetElement();
   if (elem != this) {
     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     return nullptr;
   }
 
   OwnerDoc()->WarnOnceAbout(nsIDocument::eRemoveAttributeNode);
-  return Attributes()->RemoveNamedItem(aAttribute.NodeName(), aError);
+  nsAutoString nameSpaceURI;
+  aAttribute.NodeInfo()->GetNamespaceURI(nameSpaceURI);
+  return Attributes()->RemoveNamedItemNS(nameSpaceURI, aAttribute.NodeInfo()->LocalName(), aError);
 }
 
 void
 Element::GetAttributeNS(const nsAString& aNamespaceURI,
                         const nsAString& aLocalName,
                         nsAString& aReturn)
 {
   int32_t nsid =
--- a/dom/base/StructuredCloneHelper.cpp
+++ b/dom/base/StructuredCloneHelper.cpp
@@ -427,24 +427,35 @@ StructuredCloneHelper::ReadFullySerializ
     } else {
       uint32_t appId = aIndex;
 
       uint32_t isInBrowserElement, specLength;
       if (!JS_ReadUint32Pair(aReader, &isInBrowserElement, &specLength)) {
         return nullptr;
       }
 
+      uint32_t signedPkgLength, dummy;
+      if (!JS_ReadUint32Pair(aReader, &signedPkgLength, &dummy)) {
+        return nullptr;
+      }
+
       nsAutoCString spec;
       spec.SetLength(specLength);
       if (!JS_ReadBytes(aReader, spec.BeginWriting(), specLength)) {
         return nullptr;
       }
 
+      nsAutoCString signedPkg;
+      signedPkg.SetLength(signedPkgLength);
+      if (!JS_ReadBytes(aReader, signedPkg.BeginWriting(), signedPkgLength)) {
+        return nullptr;
+      }
+
       info = mozilla::ipc::ContentPrincipalInfo(appId, isInBrowserElement,
-                                                spec);
+                                                spec, signedPkg);
     }
 
     nsresult rv;
     nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(info, &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
       return nullptr;
     }
@@ -565,17 +576,19 @@ StructuredCloneHelper::WriteFullySeriali
       }
 
       MOZ_ASSERT(info.type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo);
       const mozilla::ipc::ContentPrincipalInfo& cInfo = info;
       return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL,
                                 cInfo.appId()) &&
              JS_WriteUint32Pair(aWriter, cInfo.isInBrowserElement(),
                                 cInfo.spec().Length()) &&
-             JS_WriteBytes(aWriter, cInfo.spec().get(), cInfo.spec().Length());
+             JS_WriteUint32Pair(aWriter, cInfo.signedPkg().Length(), 0) &&
+             JS_WriteBytes(aWriter, cInfo.spec().get(), cInfo.spec().Length()) &&
+             JS_WriteBytes(aWriter, cInfo.signedPkg().get(), cInfo.signedPkg().Length());
     }
   }
 
 #ifdef MOZ_NFC
   {
     MozNDEFRecord* ndefRecord;
     if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, aObj, ndefRecord))) {
       MOZ_ASSERT(NS_IsMainThread());
--- a/dom/base/nsDOMAttributeMap.cpp
+++ b/dom/base/nsDOMAttributeMap.cpp
@@ -295,72 +295,104 @@ nsDOMAttributeMap::SetNamedItemInternal(
     if (aError.Failed()) {
       return nullptr;
     }
 
     NS_ASSERTION(adoptedNode == &aAttr, "Uh, adopt node changed nodes?");
   }
 
   // Get nodeinfo and preexisting attribute (if it exists)
-  nsAutoString name;
-  nsRefPtr<mozilla::dom::NodeInfo> ni;
+  nsRefPtr<NodeInfo> oldNi;
+
+  if (!aWithNS) {
+    nsAutoString name;
+    aAttr.GetName(name);
+    oldNi = mContent->GetExistingAttrNameFromQName(name);
+  } else {
+    uint32_t i, count = mContent->GetAttrCount();
+    for (i = 0; i < count; ++i) {
+      const nsAttrName* name = mContent->GetAttrNameAt(i);
+      int32_t attrNS = name->NamespaceID();
+      nsIAtom* nameAtom = name->LocalName();
+
+      // we're purposefully ignoring the prefix.
+      if (aAttr.NodeInfo()->Equals(nameAtom, attrNS)) {
+        oldNi = mContent->NodeInfo()->NodeInfoManager()->
+          GetNodeInfo(nameAtom, name->GetPrefix(), aAttr.NodeInfo()->NamespaceID(),
+                      nsIDOMNode::ATTRIBUTE_NODE);
+        break;
+      }
+    }
+  }
 
   nsRefPtr<Attr> attr;
-  // SetNamedItemNS()
-  if (aWithNS) {
-    // Return existing attribute, if present
-    ni = aAttr.NodeInfo();
+
+  if (oldNi) {
+    nsRefPtr<Attr> oldAttr = GetAttribute(oldNi, true);
 
-    if (mContent->HasAttr(ni->NamespaceID(), ni->NameAtom())) {
-      attr = RemoveAttribute(ni);
+    if (oldAttr == &aAttr) {
+      return oldAttr.forget();
     }
-  } else { // SetNamedItem()
-    aAttr.GetName(name);
+
+    if (oldAttr) {
+      attr = RemoveNamedItem(oldNi, aError);
+      NS_ASSERTION(attr->NodeInfo()->NameAndNamespaceEquals(oldNi),
+        "RemoveNamedItem() called, attr->NodeInfo() should be equal to oldNi!");
 
-    // get node-info of old attribute
-    ni = mContent->GetExistingAttrNameFromQName(name);
-    if (ni) {
-      attr = RemoveAttribute(ni);
-    }
-    else {
-      if (mContent->IsInHTMLDocument() &&
-          mContent->IsHTMLElement()) {
-        nsContentUtils::ASCIIToLower(name);
-      }
+      // That might have run mutation event listeners, so re-verify
+      // our assumptions.
+      nsDOMAttributeMap* newOwner = aAttr.GetMap();
+      if (newOwner) {
+        if (newOwner == this) {
+          // OK, we're just done here.
+          return attr.forget();
+        }
 
-      rv = mContent->NodeInfo()->NodeInfoManager()->
-        GetNodeInfo(name, nullptr, kNameSpaceID_None,
-                    nsIDOMNode::ATTRIBUTE_NODE, getter_AddRefs(ni));
-      if (NS_FAILED(rv)) {
-        aError.Throw(rv);
+        // The attr we're trying to set got stuck on some other
+        // element.  Just throw, for lack of anything better to do.
+        aError.Throw(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR);
+        return nullptr;
+      } else if (mContent->OwnerDoc() != aAttr.OwnerDoc()) {
+        // Got moved into a different document, boo.
+        aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
         return nullptr;
       }
-      // value is already empty
     }
   }
 
   nsAutoString value;
   aAttr.GetValue(value);
 
+  nsRefPtr<NodeInfo> ni = aAttr.NodeInfo();
+
   // Add the new attribute to the attribute map before updating
   // its value in the element. @see bug 364413.
   nsAttrKey attrkey(ni->NamespaceID(), ni->NameAtom());
   mAttributeCache.Put(attrkey, &aAttr);
   aAttr.SetMap(this);
 
   rv = mContent->SetAttr(ni->NamespaceID(), ni->NameAtom(),
                          ni->GetPrefixAtom(), value, true);
   if (NS_FAILED(rv)) {
     aError.Throw(rv);
     DropAttribute(ni->NamespaceID(), ni->NameAtom());
   }
 
   return attr.forget();
 }
 
+already_AddRefed<Attr>
+nsDOMAttributeMap::RemoveNamedItem(NodeInfo* aNodeInfo, ErrorResult& aError)
+{
+  nsRefPtr<Attr> attribute = GetAttribute(aNodeInfo, true);
+  // This removes the attribute node from the attribute map.
+  aError = mContent->UnsetAttr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom(), true);
+  return attribute.forget();
+}
+
 NS_IMETHODIMP
 nsDOMAttributeMap::RemoveNamedItem(const nsAString& aName,
                                    nsIDOMAttr** aReturn)
 {
   NS_ENSURE_ARG_POINTER(aReturn);
 
   ErrorResult rv;
   *aReturn = RemoveNamedItem(aName, rv).take();
@@ -376,21 +408,17 @@ nsDOMAttributeMap::RemoveNamedItem(const
   }
 
   nsRefPtr<mozilla::dom::NodeInfo> ni = mContent->GetExistingAttrNameFromQName(aName);
   if (!ni) {
     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     return nullptr;
   }
 
-  nsRefPtr<Attr> attribute = GetAttribute(ni, true);
-
-  // This removes the attribute node from the attribute map.
-  aError = mContent->UnsetAttr(ni->NamespaceID(), ni->NameAtom(), true);
-  return attribute.forget();
+  return RemoveNamedItem(ni, aError);
 }
 
 
 Attr*
 nsDOMAttributeMap::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
   aFound = false;
   NS_ENSURE_TRUE(mContent, nullptr);
@@ -478,16 +506,17 @@ nsDOMAttributeMap::GetAttrNodeInfo(const
   }
 
   uint32_t i, count = mContent->GetAttrCount();
   for (i = 0; i < count; ++i) {
     const nsAttrName* name = mContent->GetAttrNameAt(i);
     int32_t attrNS = name->NamespaceID();
     nsIAtom* nameAtom = name->LocalName();
 
+    // we're purposefully ignoring the prefix.
     if (nameSpaceID == attrNS &&
         nameAtom->Equals(aLocalName)) {
       nsRefPtr<mozilla::dom::NodeInfo> ni;
       ni = mContent->NodeInfo()->NodeInfoManager()->
         GetNodeInfo(nameAtom, name->GetPrefix(), nameSpaceID,
                     nsIDOMNode::ATTRIBUTE_NODE);
 
       return ni.forget();
@@ -514,21 +543,17 @@ nsDOMAttributeMap::RemoveNamedItemNS(con
                                      ErrorResult& aError)
 {
   nsRefPtr<mozilla::dom::NodeInfo> ni = GetAttrNodeInfo(aNamespaceURI, aLocalName);
   if (!ni) {
     aError.Throw(NS_ERROR_DOM_NOT_FOUND_ERR);
     return nullptr;
   }
 
-  nsRefPtr<Attr> attr = RemoveAttribute(ni);
-  mozilla::dom::NodeInfo* attrNi = attr->NodeInfo();
-  mContent->UnsetAttr(attrNi->NamespaceID(), attrNi->NameAtom(), true);
-
-  return attr.forget();
+  return RemoveNamedItem(ni, aError);
 }
 
 uint32_t
 nsDOMAttributeMap::Count() const
 {
   return mAttributeCache.Count();
 }
 
--- a/dom/base/nsDOMAttributeMap.h
+++ b/dom/base/nsDOMAttributeMap.h
@@ -147,16 +147,18 @@ public:
   Attr* NamedGetter(const nsAString& aAttrName, bool& aFound);
   bool NameIsEnumerable(const nsAString& aName);
   already_AddRefed<Attr>
   SetNamedItem(Attr& aAttr, ErrorResult& aError)
   {
     return SetNamedItemInternal(aAttr, false, aError);
   }
   already_AddRefed<Attr>
+  RemoveNamedItem(mozilla::dom::NodeInfo* aNodeInfo, ErrorResult& aError);
+  already_AddRefed<Attr>
   RemoveNamedItem(const nsAString& aName, ErrorResult& aError);
  
   Attr* Item(uint32_t aIndex);
   Attr* IndexedGetter(uint32_t aIndex, bool& aFound);
   uint32_t Length() const;
 
   Attr*
   GetNamedItemNS(const nsAString& aNamespaceURI,
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -2822,17 +2822,17 @@ nsObjectLoadingContent::ScriptRequestPlu
   //
   // NB: Sometimes there's a null cx on the stack, in which case |cx| is the
   // safe JS context. But in that case, IsCallerChrome() will return true,
   // so the ensuing expression is short-circuited.
   MOZ_ASSERT_IF(nsContentUtils::GetCurrentJSContext(),
                 aCx == nsContentUtils::GetCurrentJSContext());
   bool callerIsContentJS = (!nsContentUtils::IsCallerChrome() &&
                             !nsContentUtils::IsCallerContentXBL() &&
-                            js::IsContextRunningJS(aCx));
+                            JS_IsRunning(aCx));
 
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   *aResult = nullptr;
 
   // The first time content script attempts to access placeholder content, fire
   // an event.  Fallback types >= eFallbackClickToPlay are plugin-replacement
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -2698,27 +2698,34 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
       // If no content type header was set by the client, we set it to
       // application/xml.
       nsAutoCString contentType;
       if (NS_FAILED(httpChannel->
                       GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"),
                                        contentType)) ||
           contentType.IsEmpty()) {
         contentType = defaultContentType;
+
+        if (!charset.IsEmpty()) {
+          // If we are providing the default content type, then we also need to
+          // provide a charset declaration.
+          contentType.Append(NS_LITERAL_CSTRING(";charset="));
+          contentType.Append(charset);
+        }
       }
 
       // We don't want to set a charset for streams.
       if (!charset.IsEmpty()) {
         nsAutoCString specifiedCharset;
         bool haveCharset;
         int32_t charsetStart, charsetEnd;
         rv = NS_ExtractCharsetFromContentType(contentType, specifiedCharset,
                                               &haveCharset, &charsetStart,
                                               &charsetEnd);
-        if (NS_SUCCEEDED(rv)) {
+        while (NS_SUCCEEDED(rv) && haveCharset) {
           // special case: the extracted charset is quoted with single quotes
           // -- for the purpose of preserving what was set we want to handle
           // them as delimiters (although they aren't really)
           if (specifiedCharset.Length() >= 2 &&
               specifiedCharset.First() == '\'' &&
               specifiedCharset.Last() == '\'') {
             specifiedCharset = Substring(specifiedCharset, 1,
                                          specifiedCharset.Length() - 2);
@@ -2728,21 +2735,36 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
           // and it's the same charset, up to case, as |charset|, just send the
           // page-set content-type header.  Apparently at least
           // google-web-toolkit is broken and relies on the exact case of its
           // charset parameter, which makes things break if we use |charset|
           // (which is always a fully resolved charset per our charset alias
           // table, hence might be differently cased).
           if (!specifiedCharset.Equals(charset,
                                        nsCaseInsensitiveCStringComparator())) {
-            nsAutoCString newCharset("; charset=");
-            newCharset.Append(charset);
-            contentType.Replace(charsetStart, charsetEnd - charsetStart,
-                                newCharset);
+            // Find the start of the actual charset declaration, skipping the
+            // "; charset=" to avoid modifying whitespace.
+            int32_t charIdx =
+              Substring(contentType, charsetStart,
+                        charsetEnd - charsetStart).FindChar('=') + 1;
+            MOZ_ASSERT(charIdx != -1);
+
+            contentType.Replace(charsetStart + charIdx,
+                                charsetEnd - charsetStart - charIdx,
+                                charset);
           }
+
+          // Look for another charset declaration in the string, limiting the
+          // search to only look for charsets before the current charset, to
+          // prevent finding the same charset twice.
+          nsDependentCSubstring interestingSection =
+            Substring(contentType, 0, charsetStart);
+          rv = NS_ExtractCharsetFromContentType(interestingSection,
+                                                specifiedCharset, &haveCharset,
+                                                &charsetStart, &charsetEnd);
         }
       }
 
       // If necessary, wrap the stream in a buffered stream so as to guarantee
       // support for our upload when calling ExplicitSetUploadStream.
       if (!NS_InputStreamIsBuffered(postDataStream)) {
         nsCOMPtr<nsIInputStream> bufferedStream;
         rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -279,16 +279,17 @@ skip-if = buildapp == 'mulet'
 [test_bug913761.html]
 [test_bug976673.html]
 [test_bug978522.html]
 [test_bug979109.html]
 [test_bug989665.html]
 [test_bug999456.html]
 [test_bug1022229.html]
 [test_bug1043106.html]
+[test_bug1060938.html]
 [test_bug1064481.html]
 [test_clearTimeoutIntervalNoArg.html]
 [test_consoleEmptyStack.html]
 [test_constructor-assignment.html]
 [test_constructor.html]
 [test_dialogArguments.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s
 [test_document.all_unqualified.html]
@@ -697,16 +698,17 @@ skip-if = buildapp == 'mulet' || buildap
 [test_bug895974.html]
 [test_bug902847.html]
 [test_bug907892.html]
 [test_bug922681.html]
 [test_bug927196.html]
 [test_bug982153.html]
 [test_bug1057176.html]
 [test_bug1070015.html]
+[test_bug1075702.html]
 [test_bug1101364.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
 [test_bug1163743.html]
 support-files = referrerHelper.js
 [test_bug1165501.html]
 support-files = referrerHelper.js
 [test_img_referrer.html]
 [test_anchor_area_referrer.html]
--- a/dom/base/test/test_XHRSendData.html
+++ b/dom/base/test/test_XHRSendData.html
@@ -89,74 +89,74 @@ function createFileWithDataExt(fileData,
 tests = [{ body: null,
            resBody: "",
          },
          { body: undefined,
            resBody: "",
          },
          { body: "hi",
            resBody: "hi",
-           resContentType: "text/plain; charset=UTF-8",
+           resContentType: "text/plain;charset=UTF-8",
          },
          { body: "r\xe4ksm\xf6rg\xe5s",
            resBody: "r\xc3\xa4ksm\xc3\xb6rg\xc3\xa5s",
-           resContentType: "text/plain; charset=UTF-8",
+           resContentType: "text/plain;charset=UTF-8",
          },
          { body: "hi",
            contentType: "",
            resBody: "hi",
-           resContentType: "text/plain; charset=UTF-8",
+           resContentType: "text/plain;charset=UTF-8",
          },
          { body: "hi",
            contentType: "foo/bar",
            resBody: "hi",
-           resContentType: "foo/bar; charset=UTF-8",
+           resContentType: "foo/bar",
          },
          { body: "hi",
            contentType: "foo/bar; baz=bin",
            resBody: "hi",
-           resContentType: "foo/bar; charset=UTF-8; baz=bin",
+           resContentType: "foo/bar; baz=bin",
          },
          { body: "hi",
            contentType: "foo/bar; charset=ascii; baz=bin",
            resBody: "hi",
            resContentType: "foo/bar; charset=UTF-8; baz=bin",
          },
          { body: "hi",
            contentType: "foo/bar; charset=uTf-8",
            resBody: "hi",
            resContentType: "foo/bar; charset=uTf-8",
          },
          { body: testDoc1,
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "application/xml; charset=UTF-8",
+           resContentType: "application/xml;charset=UTF-8",
          },
          { body: testDoc1,
            contentType: "foo/bar",
            resBody: "<!-- comment -->\n<out>hi</out>",
-           resContentType: "foo/bar; charset=UTF-8",
+           resContentType: "foo/bar",
          },
          { body: testDoc1,
            contentType: "foo/bar; charset=ascii; baz=bin",
            resBody: "<!-- comment -->\n<out>hi</out>",
            resContentType: "foo/bar; charset=UTF-8; baz=bin",
          },
          { body: testDoc1,
            contentType: "foo/bar; charset=wIndows-1252",
            resBody: "<!-- comment -->\n<out>hi</out>",
            resContentType: "foo/bar; charset=UTF-8",
          },
          { body: testDoc2,
            resBody: "<!-- doc 2 -->\n<res>text</res>",
-           resContentType: "application/xml; charset=UTF-8",
+           resContentType: "application/xml;charset=UTF-8",
          },
          { body: testDoc2,
            contentType: "foo/bar",
            resBody: "<!-- doc 2 -->\n<res>text</res>",
-           resContentType: "foo/bar; charset=UTF-8",
+           resContentType: "foo/bar",
          },
          { body: testDoc2,
            contentType: "foo/bar; charset=ascii; baz=bin",
            resBody: "<!-- doc 2 -->\n<res>text</res>",
            resContentType: "foo/bar; charset=UTF-8; baz=bin",
          },
          { body: testDoc2,
            contentType: "foo/bar; charset=uTf-8",
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1060938.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1060938
+-->
+  <head>
+    <meta charset="utf-8">
+    <title> Test for Bug 1060938 </title>
+    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"> </script>
+    <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"> </script>
+    <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  </head>
+  <body>
+  <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1060938"> Mozilla Bug 1060938 </a>
+  <p id="display"></p>
+
+  <pre id="test">
+  <script type="application/javascript">
+
+    /** Test for Bug 1060938 **/
+    // test: Element.removeAttributeNode()
+
+    parent = document.getElementsByTagName("p")[0];
+    parent.setAttributeNS("www.test1.com", "ID", "Test1");
+    parent.setAttributeNS("www.test2.com", "Class", "Test2");
+    parent.setAttribute("id", "www.test3.com");
+    parent.className = "www.test4.com";
+
+    allAttributes = parent.attributes;
+
+    function removeAttr(iter){
+      var removed_attribute = allAttributes[0];
+      is(removed_attribute, parent.removeAttributeNode(removed_attribute),
+          "(" + iter + ")" + " Returned attribute and remove attribute should be same.");
+    }
+
+    removeAttr(1);
+    removeAttr(2);
+    removeAttr(3);
+    removeAttr(4);
+
+  </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_bug1075702.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1075702
+-->
+<head>
+  <meta charset="utf-8">
+  <title> Test for Bug 1075702 </title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"> </script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"> </script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1075702"> Mozilla Bug 1075702 </a>
+<p id="display"></p>
+
+<pre id="test">
+<script type="application/javascript">
+
+  /** Test for Bug 1075702 **/
+  // test: Element.removeAttributeNode()
+
+  var a1 = document.createAttribute("aa");
+  a1.nodeValue = "lowercase";
+
+  var a2 = document.createAttributeNS("", "AA");
+  a2.nodeValue = "UPPERCASE";
+
+  document.documentElement.setAttributeNode(a1);
+  document.documentElement.setAttributeNode(a2);
+
+  is(document.documentElement.getAttributeNS("", "aa"), null, "Should be NULL!");
+  is(document.documentElement.getAttributeNS("", "AA"), "UPPERCASE", "Should be UPPERCASE!");
+
+  var a3 = document.createAttribute("AA");
+  a3.nodeValue = "UPPERCASE AGAIN";
+  document.documentElement.setAttributeNode(a3);
+
+  is(document.documentElement.getAttributeNS("", "aa"), "UPPERCASE AGAIN",
+  "Should be UPPERCASE AGAIN!");
+  is(document.documentElement.getAttributeNS("", "AA"), "UPPERCASE", "Should be UPPERCASE!");
+
+  var removedNodeAccordingToEvent;
+
+  function mutationHandler(aEvent) {
+    removedNodeAccordingToEvent = aEvent.relatedNode;
+  }
+
+  var test1 = document.createElement("div");
+  test1.setAttribute("x", "y");
+  removedNodeAccordingToEvent = null;
+
+  function testremoveNamedItemNS() {
+    test1.addEventListener("DOMAttrModified", mutationHandler, true);
+    var removedNodeAccordingToRemoveNamedItemNS = test1.attributes.removeNamedItemNS(null, "x");
+    test1.removeEventListener("DOMAttrModified", mutationHandler, true);
+    is(removedNodeAccordingToEvent, removedNodeAccordingToRemoveNamedItemNS, "Node removed according to event is not same as node removed by removeNamedItemNS.");
+  }
+
+  testremoveNamedItemNS();
+
+  var test2 = document.createElement("div");
+  test2.setAttribute("x", "y");
+  removedNodeAccordingToEvent = null;
+
+  function testremoveNamedItem() {
+    test2.addEventListener("DOMAttrModified", mutationHandler, true);
+    var removedNodeAccordingToRemoveNamedItem = test2.attributes.removeNamedItem("x");
+    test2.removeEventListener("DOMAttrModified", mutationHandler, true);
+    is(removedNodeAccordingToEvent, removedNodeAccordingToRemoveNamedItem, "Node removed according to event is not same as node removed by removeNamedItem.");
+  }
+
+  testremoveNamedItem();
+
+</script>
+</body>
+</html>
--- a/dom/base/test/test_bug413974.html
+++ b/dom/base/test/test_bug413974.html
@@ -21,15 +21,15 @@ https://bugzilla.mozilla.org/show_bug.cg
 var req = new XMLHttpRequest();
 req.open("POST", window.location.href);
 req.setRequestHeader("Content-Type", "text/plain; boundary=01234567890");
 req.send("Some text");
 
 is(SpecialPowers.wrap(req).channel
       .QueryInterface(SpecialPowers.Ci.nsIHttpChannel)
       .getRequestHeader("Content-Type"),
-   "text/plain; charset=UTF-8; boundary=01234567890",
+   "text/plain; boundary=01234567890",
    "Charset should come before boundary");
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/base/test/test_bug431701.html
+++ b/dom/base/test/test_bug431701.html
@@ -100,17 +100,17 @@ function startTest() {
   }
 
   // Now check what xhr does
   var xhr = new XMLHttpRequest();
   xhr.open("POST", document.location.href);
   xhr.send(createDoc());
   is(SpecialPowers.wrap(xhr).channel.QueryInterface(SpecialPowers.Ci.nsIHttpChannel)
                 .getRequestHeader("Content-Type"),
-     "application/xml; charset=UTF-8", "Testing correct type on the wire");
+     "application/xml;charset=UTF-8", "Testing correct type on the wire");
   xhr.abort();
                      
   SimpleTest.finish();
 };
 
 
 
 
--- a/dom/base/test/test_bug469304.html
+++ b/dom/base/test/test_bug469304.html
@@ -15,72 +15,72 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 469304 **/
 function testGetAttribute() {
-  var a1 = document.createAttribute("aa");
+  var a1 = document.createAttributeNS("", "aa");
   a1.nodeValue = "lowercase";
-  var a2 = document.createAttribute("AA");
+  var a2 = document.createAttributeNS("", "AA");
   a2.nodeValue = "UPPERCASE";
   document.body.setAttributeNode(a1);
   document.body.setAttributeNode(a2);
   var log = document.getElementById("log");
-  is(document.body.getAttribute('aa'), "UPPERCASE", "Wrong value (1)");
-  is(document.body.getAttribute('AA'), "UPPERCASE", "Wrong value (2)");
+  is(document.body.getAttribute('aa'), null, "Attribute has the localName AA and not aa.");
+  is(document.body.getAttribute('AA'), null, "Attribute has the localName AA and not aa.");
+  is(document.body.getAttributeNS("", "aa"), null, "Attribute should have localName AA.");
+  is(document.body.getAttributeNS("", "AA"), "UPPERCASE", "Attribute should have value UPPERCASE!");
 
   var s = "";
   for (var i = 0; i < document.body.attributes.length; ++i) {
     s += document.body.attributes[i].nodeName + "=" +
          document.body.attributes[i].nodeValue;
   }
-  is(s, "aa=UPPERCASE", "Wrong attribute!");
+  is(s, "AA=UPPERCASE", "Wrong attribute!");
 
   is(document.body.getAttributeNode("aa"), document.body.getAttributeNode("AA"),
      "Wrong node!");
 
-  document.body.getAttributeNode("AA").nodeValue = "FOO";
-  is(document.body.getAttribute("AA"), "FOO", "Wrong value!");
+  document.body.getAttributeNodeNS("", "AA").nodeValue = "FOO";
+  is(document.body.getAttributeNS("", "AA"), "FOO", "Wrong value!");
 
-  document.body.removeAttributeNode(document.body.getAttributeNode("AA"));
-  ok(!document.body.hasAttribute("AA"), "Should not have attribute!");
+  document.body.removeAttributeNode(document.body.getAttributeNodeNS("", "AA"));
   ok(!document.body.getAttributeNode("AA"), "Should not have attribute node!");
-  ok(!document.body.hasAttribute("aa"), "Should not have attribute!");
   ok(!document.body.getAttributeNode("aa"), "Should not have attribute node!");
 
   is(a2.nodeValue, "FOO", "Wrong value!");
   a2.nodeValue = "UPPERCASE";
   is(a2.nodeValue, "UPPERCASE", "Wrong value!");
 
   document.body.setAttributeNode(a2);
-  is(document.body.getAttribute("AA"), "UPPERCASE", "wrong value!");
-  ok(document.body.getAttributeNode("AA"), "Should have attribute node!");
-  is(document.body.getAttribute("aa"), "UPPERCASE", "wrong value!");
-  ok(document.body.getAttributeNode("aa"), "Should have attribute node!");
+  is(document.body.getAttributeNS("", "AA"), "UPPERCASE", "Wrong value!");
+  ok(document.body.getAttributeNodeNS("", "AA"), "Should have attribute node!");
+  is(document.body.getAttributeNS("", "aa"), null, "No attribute has the localName aa.");
+  ok(!document.body.getAttributeNodeNS("", "aa"), "Should not have attribute node!");
 }
 testGetAttribute();
 
 // A bit modified testcases from WebKit.
 function testGetAttributeCaseInsensitive() {
   var div = document.createElement('div');
   div.setAttribute("mixedCaseAttrib", "x");
   // Do original case lookup, and lowercase lookup.
   return div.getAttribute("mixedcaseattrib");
 }
 is(testGetAttributeCaseInsensitive(), "x", "(1)");
 
 function testGetAttributeNodeMixedCase() {
   var div = document.createElement('div');
-  var a = div.ownerDocument.createAttribute("mixedCaseAttrib");
+  var a = div.ownerDocument.createAttributeNS("", "mixedCaseAttrib");
   a.nodeValue = "x";
   div.setAttributeNode(a);
-  return div.getAttribute("mixedCaseAttrib");
+  return div.getAttributeNS("", "mixedCaseAttrib");
 }
 is(testGetAttributeNodeMixedCase(), "x", "(2)");
 
 function testGetAttributeNodeLowerCase(div) {
   var div = document.createElement('div');
   var a = div.ownerDocument.createAttribute("lowercaseattrib");
   a.nodeValue = "x";
   div.setAttributeNode(a);
@@ -109,37 +109,37 @@ function testAttribNodeNameFoldsCase() {
 }
 is(testAttribNodeNameFoldsCase(), "a,a", "(5)");
 
 function testAttribNodeNameFoldsCaseGetNode() {
   var body = document.body;
   var a = body.ownerDocument.createAttribute("A");
   a.nodeValue = "x";
   body.setAttributeNode(a);
-  a = document.body.getAttributeNode("A");
+  a = document.body.getAttributeNodeNS("", "a");
   if (!a)
       return "FAIL";
   var result = [ a.name, a.nodeName ];
   return result.join(",");
 }
 is(testAttribNodeNameFoldsCaseGetNode(), "a,a", "(6)");
 
 function testAttribNodeNameFoldsCaseGetNode2() {
   var body = document.body;
   var a = body.ownerDocument.createAttribute("B");
   a.nodeValue = "x";
   body.setAttributeNode(a);
-  a = document.body.getAttributeNode("B");
+  a = document.body.getAttributeNodeNS("", "b");
   if (!a)
       return "FAIL";
   // Now create node second time
   a = body.ownerDocument.createAttribute("B");
   a.nodeValue = "x";
   body.setAttributeNode(a);
-  a = document.body.getAttributeNode("B");
+  a = document.body.getAttributeNodeNS("", "b");
   var result = [ a.name, a.nodeName ];
   return result.join(",");
 }
 is(testAttribNodeNameFoldsCaseGetNode2(), "b,b", "(7)");
 
 function testAttribNodeNameGetMutate() {
   var body = document.body;
   var a = body.ownerDocument.createAttribute("c");
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -2,17 +2,19 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import sys
 import string
 
 propList = eval(sys.stdin.read())
 props = ""
-for [name, prop, id, flags, pref] in propList:
+for [name, prop, id, flags, pref, proptype] in propList:
+    if "CSS_PROPERTY_INTERNAL" in flags:
+        continue
     extendedAttrs = ["Throws", "TreatNullAs=EmptyString"]
     if pref is not "":
         extendedAttrs.append('Pref="%s"' % pref)
     if not prop.startswith("Moz"):
         prop = prop[0].lower() + prop[1:]
     # Unfortunately, even some of the getters here are fallible
     # (e.g. on nsComputedDOMStyle).
     props += "  [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -27,24 +27,24 @@ LOCAL_INCLUDES += -I$(DIST)/include/mozi
 include $(topsrcdir)/config/rules.mk
 
 # TODO This list should be emitted to a .pp file via
 # GenerateCSS2PropertiesWebIDL.py.
 css2properties_dependencies = \
   $(topsrcdir)/layout/style/nsCSSPropList.h \
   $(topsrcdir)/layout/style/nsCSSPropAliasList.h \
   $(webidl_base)/CSS2Properties.webidl.in \
-  $(webidl_base)/CSS2PropertiesProps.h \
+  $(topsrcdir)/layout/style/PythonCSSProps.h \
   $(srcdir)/GenerateCSS2PropertiesWebIDL.py \
   $(GLOBAL_DEPS) \
   $(NULL)
 
 CSS2Properties.webidl: $(css2properties_dependencies)
 	$(CPP) $(DEFINES) $(ACDEFINES) -I$(topsrcdir)/layout/style \
-	  $(webidl_base)/CSS2PropertiesProps.h | \
+	  $(topsrcdir)/layout/style/PythonCSSProps.h | \
 	    PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
 	      $(srcdir)/GenerateCSS2PropertiesWebIDL.py \
 	      $(webidl_base)/CSS2Properties.webidl.in > $@
 
 # Most of the logic for dependencies lives inside Python so it can be
 # used by multiple build backends. We simply have rules to generate
 # and include the .pp file.
 #
--- a/dom/bindings/Nullable.h
+++ b/dom/bindings/Nullable.h
@@ -24,38 +24,51 @@ struct Nullable
 private:
   Maybe<T> mValue;
 
 public:
   Nullable()
     : mValue()
   {}
 
-  explicit Nullable(T aValue)
+  explicit Nullable(const T& aValue)
     : mValue()
   {
     mValue.emplace(aValue);
   }
 
+  explicit Nullable(T&& aValue)
+    : mValue()
+  {
+    mValue.emplace(mozilla::Move(aValue));
+  }
+
   Nullable(Nullable<T>&& aOther)
     : mValue(mozilla::Move(aOther.mValue))
   {}
 
   Nullable(const Nullable<T>& aOther)
     : mValue(aOther.mValue)
   {}
 
   void operator=(const Nullable<T>& aOther)
   {
     mValue = aOther.mValue;
   }
 
-  void SetValue(T aValue) {
+  void SetValue(const T& aArgs)
+  {
     mValue.reset();
-    mValue.emplace(aValue);
+    mValue.emplace(aArgs);
+  }
+
+  void SetValue(T&& aArgs)
+  {
+    mValue.reset();
+    mValue.emplace(mozilla::Move(aArgs));
   }
 
   // For cases when |T| is some type with nontrivial copy behavior, we may want
   // to get a reference to our internal copy of T and work with it directly
   // instead of relying on the copying version of SetValue().
   T& SetValue() {
     if (mValue.isNothing()) {
       mValue.emplace();
--- a/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.cpp
@@ -221,28 +221,28 @@ BluetoothDaemonCoreModule::SetRemoteDevi
     return rv;
   }
   unused << pdu.forget();
   return rv;
 }
 
 nsresult
 BluetoothDaemonCoreModule::GetRemoteServiceRecordCmd(
-  const nsAString& aRemoteAddr, const uint8_t aUuid[16],
+  const nsAString& aRemoteAddr, const BluetoothUuid& aUuid,
   BluetoothResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<DaemonSocketPDU> pdu(
     new DaemonSocketPDU(SERVICE_ID, OPCODE_GET_REMOTE_SERVICE_RECORD,
                         0));
 
   nsresult rv = PackPDU(
     PackConversion<nsAString, BluetoothAddress>(aRemoteAddr),
-    PackArray<uint8_t>(aUuid, 16), *pdu);
+    aUuid, *pdu);
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
--- a/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonCoreInterface.h
@@ -92,17 +92,17 @@ public:
                                       const nsAString& aName,
                                       BluetoothResultHandler* aRes);
 
   nsresult SetRemoteDevicePropertyCmd(const nsAString& aRemoteAddr,
                                       const BluetoothNamedValue& aProperty,
                                       BluetoothResultHandler* aRes);
 
   nsresult GetRemoteServiceRecordCmd(const nsAString& aRemoteAddr,
-                                     const uint8_t aUuid[16],
+                                     const BluetoothUuid& aUuid,
                                      BluetoothResultHandler* aRes);
 
   nsresult GetRemoteServicesCmd(const nsAString& aRemoteAddr,
                                 BluetoothResultHandler* aRes);
 
   nsresult StartDiscoveryCmd(BluetoothResultHandler* aRes);
 
   nsresult CancelDiscoveryCmd(BluetoothResultHandler* aRes);
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
@@ -699,17 +699,17 @@ BluetoothDaemonInterface::SetRemoteDevic
     DispatchError(aRes, rv);
   }
 }
 
 /* Remote Services */
 
 void
 BluetoothDaemonInterface::GetRemoteServiceRecord(const nsAString& aRemoteAddr,
-                                                 const uint8_t aUuid[16],
+                                                 const BluetoothUuid& aUuid,
                                                  BluetoothResultHandler* aRes)
 {
   nsresult rv = static_cast<BluetoothDaemonCoreModule*>
     (mProtocol)->GetRemoteServiceRecordCmd(aRemoteAddr, aUuid, aRes);
   if (NS_FAILED(rv)) {
     DispatchError(aRes, rv);
   }
 }
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
@@ -69,17 +69,17 @@ public:
                                BluetoothResultHandler* aRes) override;
   void SetRemoteDeviceProperty(const nsAString& aRemoteAddr,
                                const BluetoothNamedValue& aProperty,
                                BluetoothResultHandler* aRes) override;
 
   /* Remote Services */
 
   void GetRemoteServiceRecord(const nsAString& aRemoteAddr,
-                              const uint8_t aUuid[16],
+                              const BluetoothUuid& aUuid,
                               BluetoothResultHandler* aRes) override;
   void GetRemoteServices(const nsAString& aRemoteAddr,
                          BluetoothResultHandler* aRes) override;
 
   /* Discovery */
 
   void StartDiscovery(BluetoothResultHandler* aRes) override;
   void CancelDiscovery(BluetoothResultHandler* aRes) override;
--- a/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
@@ -20,62 +20,62 @@ using namespace mozilla::ipc;
 const int BluetoothDaemonSocketModule::MAX_NUM_CLIENTS = 1;
 
 // Commands
 //
 
 nsresult
 BluetoothDaemonSocketModule::ListenCmd(BluetoothSocketType aType,
                                        const nsAString& aServiceName,
-                                       const uint8_t aServiceUuid[16],
+                                       const BluetoothUuid& aServiceUuid,
                                        int aChannel, bool aEncrypt,
                                        bool aAuth,
                                        BluetoothSocketResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<DaemonSocketPDU> pdu(
     new DaemonSocketPDU(SERVICE_ID, OPCODE_LISTEN,
                         0));
 
   nsresult rv = PackPDU(
     aType,
     PackConversion<nsAString, BluetoothServiceName>(aServiceName),
-    PackArray<uint8_t>(aServiceUuid, 16),
+    aServiceUuid,
     PackConversion<int, int32_t>(aChannel),
     SocketFlags(aEncrypt, aAuth), *pdu);
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
   }
   unused << pdu.forget();
   return rv;
 }
 
 nsresult
 BluetoothDaemonSocketModule::ConnectCmd(const nsAString& aBdAddr,
                                         BluetoothSocketType aType,
-                                        const uint8_t aUuid[16],
+                                        const BluetoothUuid& aServiceUuid,
                                         int aChannel, bool aEncrypt,
                                         bool aAuth,
                                         BluetoothSocketResultHandler* aRes)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoPtr<DaemonSocketPDU> pdu(
     new DaemonSocketPDU(SERVICE_ID, OPCODE_CONNECT,
                         0));
 
   nsresult rv = PackPDU(
     PackConversion<nsAString, BluetoothAddress>(aBdAddr),
     aType,
-    PackArray<uint8_t>(aUuid, 16),
+    aServiceUuid,
     PackConversion<int, int32_t>(aChannel),
     SocketFlags(aEncrypt, aAuth), *pdu);
   if (NS_FAILED(rv)) {
     return rv;
   }
   rv = Send(pdu, aRes);
   if (NS_FAILED(rv)) {
     return rv;
@@ -300,41 +300,41 @@ BluetoothDaemonSocketInterface::Bluetoot
 }
 
 BluetoothDaemonSocketInterface::~BluetoothDaemonSocketInterface()
 { }
 
 void
 BluetoothDaemonSocketInterface::Listen(BluetoothSocketType aType,
                                        const nsAString& aServiceName,
-                                       const uint8_t aServiceUuid[16],
+                                       const BluetoothUuid& aServiceUuid,
                                        int aChannel, bool aEncrypt,
                                        bool aAuth,
                                        BluetoothSocketResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
   nsresult rv = mModule->ListenCmd(aType, aServiceName, aServiceUuid,
                                    aChannel, aEncrypt, aAuth, aRes);
   if (NS_FAILED(rv))  {
     DispatchError(aRes, rv);
   }
 }
 
 void
 BluetoothDaemonSocketInterface::Connect(const nsAString& aBdAddr,
                                         BluetoothSocketType aType,
-                                        const uint8_t aUuid[16],
+                                        const BluetoothUuid& aServiceUuid,
                                         int aChannel, bool aEncrypt,
                                         bool aAuth,
                                         BluetoothSocketResultHandler* aRes)
 {
   MOZ_ASSERT(mModule);
 
-  nsresult rv = mModule->ConnectCmd(aBdAddr, aType, aUuid, aChannel,
+  nsresult rv = mModule->ConnectCmd(aBdAddr, aType, aServiceUuid, aChannel,
                                     aEncrypt, aAuth, aRes);
   if (NS_FAILED(rv))  {
     DispatchError(aRes, rv);
   }
 }
 
 void
 BluetoothDaemonSocketInterface::Accept(int aFd,
--- a/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.h
@@ -35,23 +35,23 @@ public:
   virtual nsresult Send(DaemonSocketPDU* aPDU,
                         DaemonSocketResultHandler* aRes) = 0;
 
   // Commands
   //
 
   nsresult ListenCmd(BluetoothSocketType aType,
                      const nsAString& aServiceName,
-                     const uint8_t aServiceUuid[16],
+                     const BluetoothUuid& aServiceUuid,
                      int aChannel, bool aEncrypt, bool aAuth,
                      BluetoothSocketResultHandler* aRes);
 
   nsresult ConnectCmd(const nsAString& aBdAddr,
                       BluetoothSocketType aType,
-                      const uint8_t aUuid[16],
+                      const BluetoothUuid& aServiceUuid,
                       int aChannel, bool aEncrypt, bool aAuth,
                       BluetoothSocketResultHandler* aRes);
 
   nsresult AcceptCmd(int aFd, BluetoothSocketResultHandler* aRes);
 
   nsresult CloseCmd(BluetoothSocketResultHandler* aRes);
 
 protected:
@@ -103,23 +103,23 @@ class BluetoothDaemonSocketInterface fin
   : public BluetoothSocketInterface
 {
 public:
   BluetoothDaemonSocketInterface(BluetoothDaemonSocketModule* aModule);
   ~BluetoothDaemonSocketInterface();
 
   void Listen(BluetoothSocketType aType,
               const nsAString& aServiceName,
-              const uint8_t aServiceUuid[16],
+              const BluetoothUuid& aServiceUuid,
               int aChannel, bool aEncrypt, bool aAuth,
               BluetoothSocketResultHandler* aRes) override;
 
   void Connect(const nsAString& aBdAddr,
                BluetoothSocketType aType,
-               const uint8_t aUuid[16],
+               const BluetoothUuid& aServiceUuid,
                int aChannel, bool aEncrypt, bool aAuth,
                BluetoothSocketResultHandler* aRes) override;
 
   void Accept(int aFd, BluetoothSocketResultHandler* aRes) override;
 
   void Close(BluetoothSocketResultHandler* aRes) override;
 
 private:
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -893,17 +893,17 @@ public:
     mGetRemoteServiceRecordArray[i].mManager->OnGetServiceChannel(
       mDeviceAddress, uuidStr, -1);
     mGetRemoteServiceRecordArray.RemoveElementAt(i);
   }
 
   void CancelDiscovery() override
   {
     // Disabled discovery mode, now perform SDP operation.
-    sBtInterface->GetRemoteServiceRecord(mDeviceAddress, mUuid.mUuid, this);
+    sBtInterface->GetRemoteServiceRecord(mDeviceAddress, mUuid, this);
   }
 
 private:
   ssize_t FindRequest() const
   {
     for (size_t i = 0; i < mGetRemoteServiceRecordArray.Length(); ++i) {
       if ((mGetRemoteServiceRecordArray[i].mDeviceAddress == mDeviceAddress) &&
           (mGetRemoteServiceRecordArray[i].mUuid == mUuid)) {
@@ -936,17 +936,17 @@ BluetoothServiceBluedroid::GetServiceCha
 
   /* Stop discovery of remote devices here, because SDP operations
    * won't be performed while the adapter is in discovery mode.
    */
   if (mDiscovering) {
     sBtInterface->CancelDiscovery(res);
   } else {
     sBtInterface->GetRemoteServiceRecord(
-      aDeviceAddress, uuid.mUuid, res);
+      aDeviceAddress, uuid, res);
   }
 
   return NS_OK;
 }
 
 struct BluetoothServiceBluedroid::GetRemoteServicesRequest final
 {
   GetRemoteServicesRequest(const nsAString& aDeviceAddress,
--- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp
@@ -660,17 +660,17 @@ BluetoothSocket::Connect(const nsAString
 
   mImpl = new DroidSocketImpl(aConsumerLoop, aIOLoop, this);
 
   BluetoothSocketResultHandler* res = new ConnectSocketResultHandler(mImpl);
   SetCurrentResultHandler(res);
 
   sBluetoothSocketInterface->Connect(
     aDeviceAddress, aType,
-    aServiceUuid.mUuid, aChannel,
+    aServiceUuid, aChannel,
     aEncrypt, aAuth, res);
 
   return NS_OK;
 }
 
 nsresult
 BluetoothSocket::Connect(const nsAString& aDeviceAddress,
                          const BluetoothUuid& aServiceUuid,
@@ -724,17 +724,17 @@ BluetoothSocket::Listen(const nsAString&
 
   mImpl = new DroidSocketImpl(aConsumerLoop, aIOLoop, this);
 
   BluetoothSocketResultHandler* res = new ListenResultHandler(mImpl);
   SetCurrentResultHandler(res);
 
   sBluetoothSocketInterface->Listen(
     aType,
-    aServiceName, aServiceUuid.mUuid, aChannel,
+    aServiceName, aServiceUuid, aChannel,
     aEncrypt, aAuth, res);
 
   return NS_OK;
 }
 
 nsresult
 BluetoothSocket::Listen(const nsAString& aServiceName,
                         const BluetoothUuid& aServiceUuid,
--- a/dom/bluetooth/common/BluetoothInterface.h
+++ b/dom/bluetooth/common/BluetoothInterface.h
@@ -52,23 +52,23 @@ protected:
 
 class BluetoothSocketInterface
 {
 public:
   // Init and Cleanup is handled by BluetoothInterface
 
   virtual void Listen(BluetoothSocketType aType,
                       const nsAString& aServiceName,
-                      const uint8_t aServiceUuid[16],
+                      const BluetoothUuid& aServiceUuid,
                       int aChannel, bool aEncrypt, bool aAuth,
                       BluetoothSocketResultHandler* aRes) = 0;
 
   virtual void Connect(const nsAString& aBdAddr,
                        BluetoothSocketType aType,
-                       const uint8_t aUuid[16],
+                       const BluetoothUuid& aServiceUuid,
                        int aChannel, bool aEncrypt, bool aAuth,
                        BluetoothSocketResultHandler* aRes) = 0;
 
   virtual void Accept(int aFd, BluetoothSocketResultHandler* aRes) = 0;
 
   virtual void Close(BluetoothSocketResultHandler* aRes) = 0;
 
 protected:
@@ -1047,17 +1047,17 @@ public:
                                        BluetoothResultHandler* aRes) = 0;
   virtual void SetRemoteDeviceProperty(const nsAString& aRemoteAddr,
                                        const BluetoothNamedValue& aProperty,
                                        BluetoothResultHandler* aRes) = 0;
 
   /* Remote Services */
 
   virtual void GetRemoteServiceRecord(const nsAString& aRemoteAddr,
-                                      const uint8_t aUuid[16],
+                                      const BluetoothUuid& aUuid,
                                       BluetoothResultHandler* aRes) = 0;
   virtual void GetRemoteServices(const nsAString& aRemoteAddr,
                                  BluetoothResultHandler* aRes) = 0;
 
   /* Discovery */
 
   virtual void StartDiscovery(BluetoothResultHandler* aRes) = 0;
   virtual void CancelDiscovery(BluetoothResultHandler* aRes) = 0;
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -1908,18 +1908,19 @@ ReadResponse(mozIStorageConnection* aCon
   if (!serializedInfo.IsEmpty()) {
     nsAutoCString originNoSuffix;
     OriginAttributes attrs;
     if (!attrs.PopulateFromOrigin(serializedInfo, originNoSuffix)) {
       NS_WARNING("Something went wrong parsing a serialized principal!");
       return NS_ERROR_FAILURE;
     }
 
+    nsCString signedPkg = NS_ConvertUTF16toUTF8(attrs.mSignedPkg);
     aSavedResponseOut->mValue.principalInfo() =
-      mozilla::ipc::ContentPrincipalInfo(attrs.mAppId, attrs.mInBrowser, originNoSuffix);
+      mozilla::ipc::ContentPrincipalInfo(attrs.mAppId, attrs.mInBrowser, originNoSuffix, signedPkg);
   }
 
   int32_t redirected;
   rv = state->GetInt32(7, &redirected);
   aSavedResponseOut->mValue.channelInfo().redirected() = !!redirected;
 
   rv = state->GetUTF8String(8, aSavedResponseOut->mValue.channelInfo().redirectedURI());
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_indexeddb_idbkeyrange_h__
 #define mozilla_dom_indexeddb_idbkeyrange_h__
 
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/indexedDB/Key.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsISupports.h"
 #include "nsString.h"
 
 class mozIStorageStatement;
 struct PRThread;
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -107,37 +107,42 @@ public:
     if (decoders.IsEmpty()) {
       sUniqueInstance = nullptr;
     }
   }
 };
 
 StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
 
+#if defined(PR_LOGGING)
 PRLogModuleInfo* gStateWatchingLog;
 PRLogModuleInfo* gMozPromiseLog;
 PRLogModuleInfo* gMediaTimerLog;
 PRLogModuleInfo* gMediaSampleLog;
+#endif
 
 void
 MediaDecoder::InitStatics()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+#if defined(PR_LOGGING)
   // Log modules.
   gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
   gMediaTimerLog = PR_NewLogModule("MediaTimer");
   gMediaSampleLog = PR_NewLogModule("MediaSample");
+#endif
 }
 
 NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
 
 NS_IMPL_ISUPPORTS0(MediaDecoder)
 
-void MediaDecoder::NotifyOwnerActivityChanged()
+void
+MediaDecoder::NotifyOwnerActivityChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
   if (!mOwner) {
     NS_WARNING("MediaDecoder without a decoder owner, can't update dormant");
     return;
   }
@@ -154,17 +159,18 @@ MediaDecoder::IsHeuristicDormantSupporte
 #if defined(MOZ_EME)
     // We disallow dormant for encrypted media until bug 1181864 is fixed.
     mInfo &&
     !mInfo->IsEncrypted() &&
 #endif
     mIsHeuristicDormantSupported;
 }
 
-void MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
+void
+MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (!mDecoderStateMachine ||
       mPlayState == PLAY_STATE_SHUTDOWN ||
       !mOwner->GetVideoFrameContainer() ||
       (mOwner->GetMediaElement() && mOwner->GetMediaElement()->IsBeingDestroyed()) ||
@@ -225,27 +231,29 @@ void MediaDecoder::UpdateDormantState(bo
     ChangeState(PLAY_STATE_LOADING);
   } else {
     DECODER_LOG("UpdateDormantState() leaving DORMANT state");
     // exit dormant state
     mDecoderStateMachine->DispatchSetDormant(false);
   }
 }
 
-void MediaDecoder::DormantTimerExpired(nsITimer* aTimer, void* aClosure)
+void
+MediaDecoder::DormantTimerExpired(nsITimer* aTimer, void* aClosure)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aClosure);
   MediaDecoder* decoder = static_cast<MediaDecoder*>(aClosure);
   ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
   decoder->UpdateDormantState(true /* aDormantTimeout */,
                               false /* aActivity */);
 }
 
-void MediaDecoder::StartDormantTimer()
+void
+MediaDecoder::StartDormantTimer()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!IsHeuristicDormantSupported()) {
     return;
   }
 
   if (mIsHeuristicDormant ||
       mShuttingDown ||
@@ -261,79 +269,87 @@ void MediaDecoder::StartDormantTimer()
     mDormantTimer = do_CreateInstance("@mozilla.org/timer;1");
   }
   mDormantTimer->InitWithFuncCallback(&MediaDecoder::DormantTimerExpired,
                                       this,
                                       mHeuristicDormantTimeout,
                                       nsITimer::TYPE_ONE_SHOT);
 }
 
-void MediaDecoder::CancelDormantTimer()
+void
+MediaDecoder::CancelDormantTimer()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mDormantTimer) {
     mDormantTimer->Cancel();
   }
 }
 
-void MediaDecoder::Pause()
+void
+MediaDecoder::Pause()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   if (mPlayState == PLAY_STATE_LOADING ||
       IsEnded()) {
     mNextState = PLAY_STATE_PAUSED;
     return;
   }
 
   ChangeState(PLAY_STATE_PAUSED);
 }
 
-void MediaDecoder::SetVolume(double aVolume)
+void
+MediaDecoder::SetVolume(double aVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mVolume = aVolume;
 }
 
-void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
-                                   bool aFinishWhenEnded)
+void
+MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
+                              bool aFinishWhenEnded)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
   mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded);
 }
 
-void MediaDecoder::RemoveOutputStream(MediaStream* aStream)
+void
+MediaDecoder::RemoveOutputStream(MediaStream* aStream)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load().");
   mDecoderStateMachine->RemoveOutputStream(aStream);
 }
 
-double MediaDecoder::GetDuration()
+double
+MediaDecoder::GetDuration()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mDuration;
 }
 
 AbstractCanonical<media::NullableTimeUnit>*
 MediaDecoder::CanonicalDurationOrNull()
 {
   MOZ_ASSERT(mDecoderStateMachine);
   return mDecoderStateMachine->CanonicalDuration();
 }
 
-void MediaDecoder::SetInfinite(bool aInfinite)
+void
+MediaDecoder::SetInfinite(bool aInfinite)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mInfiniteStream = aInfinite;
   DurationChanged();
 }
 
-bool MediaDecoder::IsInfinite()
+bool
+MediaDecoder::IsInfinite()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mInfiniteStream;
 }
 
 MediaDecoder::MediaDecoder() :
   mWatchManager(this, AbstractThread::MainThread()),
   mDormantSupported(false),
@@ -422,26 +438,28 @@ MediaDecoder::MediaDecoder() :
   mWatchManager.Watch(mCurrentPosition, &MediaDecoder::UpdateLogicalPosition);
   mWatchManager.Watch(mPlayState, &MediaDecoder::UpdateLogicalPosition);
   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::UpdateLogicalPosition);
 
   // mIgnoreProgressData
   mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
 }
 
-bool MediaDecoder::Init(MediaDecoderOwner* aOwner)
+bool
+MediaDecoder::Init(MediaDecoderOwner* aOwner)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mOwner = aOwner;
   mVideoFrameContainer = aOwner->GetVideoFrameContainer();
   MediaShutdownManager::Instance().Register(this);
   return true;
 }
 
-void MediaDecoder::Shutdown()
+void
+MediaDecoder::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown)
     return;
 
   mShuttingDown = true;
 
@@ -471,17 +489,18 @@ void MediaDecoder::Shutdown()
 MediaDecoder::~MediaDecoder()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaMemoryTracker::RemoveMediaDecoder(this);
   UnpinForSeek();
   MOZ_COUNT_DTOR(MediaDecoder);
 }
 
-nsresult MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
+nsresult
+MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (aStreamListener) {
     *aStreamListener = nullptr;
   }
 
   {
     // Hold the lock while we do this to set proper lock ordering
@@ -490,70 +509,75 @@ nsresult MediaDecoder::OpenResource(nsIS
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
     nsresult rv = mResource->Open(aStreamListener);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
-nsresult MediaDecoder::Load(nsIStreamListener** aStreamListener,
-                            MediaDecoder* aCloneDonor)
+nsresult
+MediaDecoder::Load(nsIStreamListener** aStreamListener,
+                   MediaDecoder* aCloneDonor)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mResource, "Can't load without a MediaResource");
 
   nsresult rv = OpenResource(aStreamListener);
   NS_ENSURE_SUCCESS(rv, rv);
 
   SetStateMachine(CreateStateMachine());
   NS_ENSURE_TRUE(GetStateMachine(), NS_ERROR_FAILURE);
 
   return InitializeStateMachine(aCloneDonor);
 }
 
-nsresult MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor)
+nsresult
+MediaDecoder::InitializeStateMachine(MediaDecoder* aCloneDonor)
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ASSERTION(mDecoderStateMachine, "Cannot initialize null state machine!");
 
   MediaDecoder* cloneDonor = static_cast<MediaDecoder*>(aCloneDonor);
   nsresult rv = mDecoderStateMachine->Init(
       cloneDonor ? cloneDonor->mDecoderStateMachine.get() : nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If some parameters got set before the state machine got created,
   // set them now
   SetStateMachineParameters();
 
   return NS_OK;
 }
 
-void MediaDecoder::SetStateMachineParameters()
+void
+MediaDecoder::SetStateMachineParameters()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mMinimizePreroll) {
     mDecoderStateMachine->DispatchMinimizePrerollUntilPlaybackStarts();
   }
   mTimedMetadataListener = mDecoderStateMachine->TimedMetadataEvent().Connect(
     AbstractThread::MainThread(), this, &MediaDecoder::OnMetadataUpdate);
 }
 
-void MediaDecoder::SetMinimizePrerollUntilPlaybackStarts()
+void
+MediaDecoder::SetMinimizePrerollUntilPlaybackStarts()
 {
   MOZ_ASSERT(NS_IsMainThread());
   DECODER_LOG("SetMinimizePrerollUntilPlaybackStarts()");
   mMinimizePreroll = true;
 
   // This needs to be called before we init the state machine, otherwise it will
   // have no effect.
   MOZ_DIAGNOSTIC_ASSERT(!mDecoderStateMachine);
 }
 
-nsresult MediaDecoder::Play()
+nsresult
+MediaDecoder::Play()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
 
   NS_ASSERTION(mDecoderStateMachine != nullptr, "Should have state machine.");
   if (mPausedForPlaybackRateNull) {
     return NS_OK;
@@ -565,17 +589,18 @@ nsresult MediaDecoder::Play()
     mNextState = PLAY_STATE_PLAYING;
     return NS_OK;
   }
 
   ChangeState(PLAY_STATE_PLAYING);
   return NS_OK;
 }
 
-nsresult MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
+nsresult
+MediaDecoder::Seek(double aTime, SeekTarget::Type aSeekType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   NS_ENSURE_TRUE(!mShuttingDown, NS_ERROR_FAILURE);
 
   UpdateDormantState(false /* aDormantTimeout */, true /* aActivity */);
 
   MOZ_ASSERT(aTime >= 0.0, "Cannot seek to a negative value.");
@@ -597,52 +622,57 @@ nsresult MediaDecoder::Seek(double aTime
       paused = mOwner->GetPaused();
     }
     PinForSeek();
     ChangeState(paused ? PLAY_STATE_PAUSED : PLAY_STATE_PLAYING);
   }
   return NS_OK;
 }
 
-void MediaDecoder::CallSeek(const SeekTarget& aTarget)
+void
+MediaDecoder::CallSeek(const SeekTarget& aTarget)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mSeekRequest.DisconnectIfExists();
   mSeekRequest.Begin(
     mDecoderStateMachine->InvokeSeek(aTarget)
     ->Then(AbstractThread::MainThread(), __func__, this,
            &MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
 }
 
-double MediaDecoder::GetCurrentTime()
+double
+MediaDecoder::GetCurrentTime()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mLogicalPosition;
 }
 
-already_AddRefed<nsIPrincipal> MediaDecoder::GetCurrentPrincipal()
+already_AddRefed<nsIPrincipal>
+MediaDecoder::GetCurrentPrincipal()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mResource ? mResource->GetCurrentPrincipal() : nullptr;
 }
 
-void MediaDecoder::OnMetadataUpdate(TimedMetadata&& aMetadata)
+void
+MediaDecoder::OnMetadataUpdate(TimedMetadata&& aMetadata)
 {
   MOZ_ASSERT(NS_IsMainThread());
   RemoveMediaTracks();
   MetadataLoaded(nsAutoPtr<MediaInfo>(new MediaInfo(*aMetadata.mInfo)),
                  Move(aMetadata.mTags),
                  MediaDecoderEventVisibility::Observable);
   FirstFrameLoaded(Move(aMetadata.mInfo),
                    MediaDecoderEventVisibility::Observable);
 }
 
-void MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
-                                  nsAutoPtr<MetadataTags> aTags,
-                                  MediaDecoderEventVisibility aEventVisibility)
+void
+MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
+                             nsAutoPtr<MetadataTags> aTags,
+                             MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown) {
     return;
   }
 
   DECODER_LOG("MetadataLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d",
@@ -673,18 +703,19 @@ MediaDecoder::PlayStateStr()
     case PLAY_STATE_PAUSED: return "PLAY_STATE_PAUSED";
     case PLAY_STATE_PLAYING: return "PLAY_STATE_PLAYING";
     case PLAY_STATE_ENDED: return "PLAY_STATE_ENDED";
     case PLAY_STATE_SHUTDOWN: return "PLAY_STATE_SHUTDOWN";
     default: return "INVALID_PLAY_STATE";
   }
 }
 
-void MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
-                                    MediaDecoderEventVisibility aEventVisibility)
+void
+MediaDecoder::FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
+                               MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown) {
     return;
   }
 
   DECODER_LOG("FirstFrameLoaded, channels=%u rate=%u hasAudio=%d hasVideo=%d mPlayState=%s mIsDormant=%d",
@@ -711,84 +742,92 @@ void MediaDecoder::FirstFrameLoaded(nsAu
     ChangeState(mNextState);
   }
 
   // Run NotifySuspendedStatusChanged now to give us a chance to notice
   // that autoplay should run.
   NotifySuspendedStatusChanged();
 }
 
-void MediaDecoder::ResetConnectionState()
+void
+MediaDecoder::ResetConnectionState()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return;
 
   if (mOwner) {
     // Notify the media element that connection gets lost.
     mOwner->ResetConnectionState();
   }
 
   // Since we have notified the media element the connection
   // lost event, the decoder will be reloaded when user tries
   // to play the Rtsp streaming next time.
   Shutdown();
 }
 
-void MediaDecoder::NetworkError()
+void
+MediaDecoder::NetworkError()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return;
 
   if (mOwner)
     mOwner->NetworkError();
 
   Shutdown();
 }
 
-void MediaDecoder::DecodeError()
+void
+MediaDecoder::DecodeError()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return;
 
   if (mOwner)
     mOwner->DecodeError();
 
   Shutdown();
 }
 
-void MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
+void
+MediaDecoder::UpdateSameOriginStatus(bool aSameOrigin)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mSameOriginMedia = aSameOrigin;
 }
 
-bool MediaDecoder::IsSeeking() const
+bool
+MediaDecoder::IsSeeking() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mLogicallySeeking;
 }
 
-bool MediaDecoder::IsEndedOrShutdown() const
+bool
+MediaDecoder::IsEndedOrShutdown() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return IsEnded() || mPlayState == PLAY_STATE_SHUTDOWN;
 }
 
-bool MediaDecoder::IsEnded() const
+bool
+MediaDecoder::IsEnded() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mPlayState == PLAY_STATE_ENDED ||
          (mWasEndedWhenEnteredDormant && (mPlayState != PLAY_STATE_SHUTDOWN));
 }
 
-void MediaDecoder::PlaybackEnded()
+void
+MediaDecoder::PlaybackEnded()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown ||
       mLogicallySeeking ||
       mPlayState == PLAY_STATE_LOADING) {
     return;
   }
@@ -861,38 +900,41 @@ MediaDecoder::UpdatePlaybackRate()
     // Set a minimum rate of 10,000 bytes per second ... sometimes we just
     // don't have good data
     rate = std::max(rate, 10000u);
   }
 
   mResource->SetPlaybackRate(rate);
 }
 
-void MediaDecoder::NotifySuspendedStatusChanged()
+void
+MediaDecoder::NotifySuspendedStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mResource && mOwner) {
     bool suspended = mResource->IsSuspendedByCache();
     mOwner->NotifySuspendedByCache(suspended);
   }
 }
 
-void MediaDecoder::NotifyBytesDownloaded()
+void
+MediaDecoder::NotifyBytesDownloaded()
 {
   MOZ_ASSERT(NS_IsMainThread());
   {
     ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
     UpdatePlaybackRate();
   }
   if (mOwner) {
     mOwner->DownloadProgressed();
   }
 }
 
-void MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
+void
+MediaDecoder::NotifyDownloadEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   DECODER_LOG("NotifyDownloadEnded, status=%x", aStatus);
 
   if (aStatus == NS_BINDING_ABORTED) {
     // Download has been cancelled by user.
     if (mOwner) {
@@ -911,41 +953,44 @@ void MediaDecoder::NotifyDownloadEnded(n
     // DownloadSuspended on the element.
     // Also NotifySuspendedStatusChanged() will be called to update readyState
     // if download ended with success.
   } else if (aStatus != NS_BASE_STREAM_CLOSED) {
     NetworkError();
   }
 }
 
-void MediaDecoder::NotifyPrincipalChanged()
+void
+MediaDecoder::NotifyPrincipalChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mOwner) {
     mOwner->NotifyDecoderPrincipalChanged();
   }
 }
 
-void MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
+void
+MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mShuttingDown || mIgnoreProgressData) {
     return;
   }
 
   MOZ_ASSERT(mDecoderStateMachine);
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   if (aOffset >= mDecoderPosition) {
     mPlaybackStatistics->AddBytes(aBytes);
   }
   mDecoderPosition = aOffset + aBytes;
 }
 
-void MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
+void
+MediaDecoder::OnSeekResolved(SeekResolveValue aVal)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mSeekRequest.Complete();
 
   if (mShuttingDown)
     return;
 
   bool fireEnded = false;
@@ -969,30 +1014,32 @@ void MediaDecoder::OnSeekResolved(SeekRe
       mOwner->SeekCompleted();
       if (fireEnded) {
         mOwner->PlaybackEnded();
       }
     }
   }
 }
 
-void MediaDecoder::SeekingStarted(MediaDecoderEventVisibility aEventVisibility)
+void
+MediaDecoder::SeekingStarted(MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return;
 
   if (mOwner) {
     if (aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
       mOwner->SeekStarted();
     }
   }
 }
 
-void MediaDecoder::ChangeState(PlayState aState)
+void
+MediaDecoder::ChangeState(PlayState aState)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
   if (mNextState == aState) {
     mNextState = PLAY_STATE_PAUSED;
   }
 
@@ -1010,17 +1057,18 @@ void MediaDecoder::ChangeState(PlayState
     RemoveMediaTracks();
   }
 
   CancelDormantTimer();
   // Start dormant timer if necessary
   StartDormantTimer();
 }
 
-void MediaDecoder::UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisibility)
+void
+MediaDecoder::UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisibility)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return;
 
   // Per spec, offical position remains stable during pause and seek.
   if (mPlayState == PLAY_STATE_PAUSED || IsSeeking()) {
     return;
@@ -1037,17 +1085,18 @@ void MediaDecoder::UpdateLogicalPosition
   Invalidate();
 
   if (mOwner && logicalPositionChanged &&
       aEventVisibility != MediaDecoderEventVisibility::Suppressed) {
     FireTimeUpdate();
   }
 }
 
-void MediaDecoder::DurationChanged()
+void
+MediaDecoder::DurationChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
 
   double oldDuration = mDuration;
   if (IsInfinite()) {
     mDuration = std::numeric_limits<double>::infinity();
   } else if (mExplicitDuration.Ref().isSome()) {
@@ -1072,17 +1121,18 @@ void MediaDecoder::DurationChanged()
     mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   }
 
   if (CurrentPosition() > TimeUnit::FromSeconds(mDuration).ToMicroseconds()) {
     Seek(mDuration, SeekTarget::Accurate);
   }
 }
 
-void MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
+void
+MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mPlayState <= PLAY_STATE_LOADING) {
     return;
   }
 
   // The duration is only changed if its significantly different than the
@@ -1092,37 +1142,40 @@ void MediaDecoder::UpdateEstimatedMediaD
   if (mEstimatedDuration.Ref().isSome() &&
       mozilla::Abs(mEstimatedDuration.Ref().ref().ToMicroseconds() - aDuration) < ESTIMATED_DURATION_FUZZ_FACTOR_USECS) {
     return;
   }
 
   mEstimatedDuration = Some(TimeUnit::FromMicroseconds(aDuration));
 }
 
-void MediaDecoder::SetMediaSeekable(bool aMediaSeekable) {
+void
+MediaDecoder::SetMediaSeekable(bool aMediaSeekable) {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
   mMediaSeekable = aMediaSeekable;
 }
 
 bool
 MediaDecoder::IsTransportSeekable()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return GetResource()->IsTransportSeekable();
 }
 
-bool MediaDecoder::IsMediaSeekable()
+bool
+MediaDecoder::IsMediaSeekable()
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_ENSURE_TRUE(GetStateMachine(), false);
   return mMediaSeekable;
 }
 
-media::TimeIntervals MediaDecoder::GetSeekable()
+media::TimeIntervals
+MediaDecoder::GetSeekable()
 {
   MOZ_ASSERT(NS_IsMainThread());
   // We can seek in buffered range if the media is seekable. Also, we can seek
   // in unbuffered ranges if the transport level is seekable (local file or the
   // server supports range requests, etc.)
   if (!IsMediaSeekable()) {
     return media::TimeIntervals();
   } else if (!IsTransportSeekable()) {
@@ -1131,59 +1184,65 @@ media::TimeIntervals MediaDecoder::GetSe
     return media::TimeIntervals(
       media::TimeInterval(media::TimeUnit::FromMicroseconds(0),
                           IsInfinite() ?
                             media::TimeUnit::FromInfinity() :
                             media::TimeUnit::FromSeconds(GetDuration())));
   }
 }
 
-void MediaDecoder::SetFragmentEndTime(double aTime)
+void
+MediaDecoder::SetFragmentEndTime(double aTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mDecoderStateMachine) {
     mDecoderStateMachine->DispatchSetFragmentEndTime(static_cast<int64_t>(aTime * USECS_PER_S));
   }
 }
 
-void MediaDecoder::Suspend()
+void
+MediaDecoder::Suspend()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mResource) {
     mResource->Suspend(true);
   }
 }
 
-void MediaDecoder::Resume(bool aForceBuffering)
+void
+MediaDecoder::Resume(bool aForceBuffering)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mResource) {
     mResource->Resume();
   }
   if (aForceBuffering) {
     if (mDecoderStateMachine) {
       mDecoderStateMachine->DispatchStartBuffering();
     }
   }
 }
 
-void MediaDecoder::SetLoadInBackground(bool aLoadInBackground)
+void
+MediaDecoder::SetLoadInBackground(bool aLoadInBackground)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mResource) {
     mResource->SetLoadInBackground(aLoadInBackground);
   }
 }
 
-bool MediaDecoder::OnStateMachineTaskQueue() const
+bool
+MediaDecoder::OnStateMachineTaskQueue() const
 {
   return mDecoderStateMachine->OnTaskQueue();
 }
 
-void MediaDecoder::SetPlaybackRate(double aPlaybackRate)
+void
+MediaDecoder::SetPlaybackRate(double aPlaybackRate)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mPlaybackRate = aPlaybackRate;
   if (mPlaybackRate == 0.0) {
     mPausedForPlaybackRateNull = true;
     Pause();
   } else if (mPausedForPlaybackRateNull) {
     // Play() uses mPausedForPlaybackRateNull value, so must reset it first
@@ -1191,23 +1250,25 @@ void MediaDecoder::SetPlaybackRate(doubl
     // If the playbackRate is no longer null, restart the playback, iff the
     // media was playing.
     if (mOwner && !mOwner->GetPaused()) {
       Play();
     }
   }
 }
 
-void MediaDecoder::SetPreservesPitch(bool aPreservesPitch)
+void
+MediaDecoder::SetPreservesPitch(bool aPreservesPitch)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mPreservesPitch = aPreservesPitch;
 }
 
-bool MediaDecoder::OnDecodeTaskQueue() const {
+bool
+MediaDecoder::OnDecodeTaskQueue() const {
   NS_WARN_IF_FALSE(mDecoderStateMachine, "mDecoderStateMachine is null");
   return mDecoderStateMachine ? mDecoderStateMachine->OnDecodeTaskQueue() : false;
 }
 
 void
 MediaDecoder::SetStateMachine(MediaDecoderStateMachine* aStateMachine)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -1226,117 +1287,133 @@ MediaDecoder::SetStateMachine(MediaDecod
     mBuffered.DisconnectIfConnected();
     mStateMachineIsShutdown.DisconnectIfConnected();
     mNextFrameStatus.DisconnectIfConnected();
     mCurrentPosition.DisconnectIfConnected();
     mPlaybackPosition.DisconnectIfConnected();
   }
 }
 
-ReentrantMonitor& MediaDecoder::GetReentrantMonitor() {
+ReentrantMonitor&
+MediaDecoder::GetReentrantMonitor() {
   return mReentrantMonitor;
 }
 
-ImageContainer* MediaDecoder::GetImageContainer()
+ImageContainer*
+MediaDecoder::GetImageContainer()
 {
   return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer() : nullptr;
 }
 
-void MediaDecoder::InvalidateWithFlags(uint32_t aFlags)
+void
+MediaDecoder::InvalidateWithFlags(uint32_t aFlags)
 {
   if (mVideoFrameContainer) {
     mVideoFrameContainer->InvalidateWithFlags(aFlags);
   }
 }
 
-void MediaDecoder::Invalidate()
+void
+MediaDecoder::Invalidate()
 {
   if (mVideoFrameContainer) {
     mVideoFrameContainer->Invalidate();
   }
 }
 
 // Constructs the time ranges representing what segments of the media
 // are buffered and playable.
-media::TimeIntervals MediaDecoder::GetBuffered() {
+media::TimeIntervals
+MediaDecoder::GetBuffered() {
   MOZ_ASSERT(NS_IsMainThread());
   return mBuffered.Ref();
 }
 
-size_t MediaDecoder::SizeOfVideoQueue() {
+size_t
+MediaDecoder::SizeOfVideoQueue() {
   MOZ_ASSERT(NS_IsMainThread());
   if (mDecoderStateMachine) {
     return mDecoderStateMachine->SizeOfVideoQueue();
   }
   return 0;
 }
 
-size_t MediaDecoder::SizeOfAudioQueue() {
+size_t
+MediaDecoder::SizeOfAudioQueue() {
   MOZ_ASSERT(NS_IsMainThread());
   if (mDecoderStateMachine) {
     return mDecoderStateMachine->SizeOfAudioQueue();
   }
   return 0;
 }
 
-void MediaDecoder::NotifyDataArrived(uint32_t aLength, int64_t aOffset, bool aThrottleUpdates) {
+void
+MediaDecoder::NotifyDataArrived(uint32_t aLength,
+                                int64_t aOffset,
+                                bool aThrottleUpdates) {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (mDecoderStateMachine) {
     mDecoderStateMachine->DispatchNotifyDataArrived(aLength, aOffset, aThrottleUpdates);
   }
 
   // ReadyState computation depends on MediaDecoder::CanPlayThrough, which
   // depends on the download rate.
   UpdateReadyState();
 }
 
 // Provide access to the state machine object
-MediaDecoderStateMachine* MediaDecoder::GetStateMachine() const {
+MediaDecoderStateMachine*
+MediaDecoder::GetStateMachine() const {
   return mDecoderStateMachine;
 }
 
 void
 MediaDecoder::NotifyWaitingForResourcesStatusChanged()
 {
   if (mDecoderStateMachine) {
     mDecoderStateMachine->DispatchWaitingForResourcesStatusChanged();
   }
 }
 
 // Drop reference to state machine.  Only called during shutdown dance.
-void MediaDecoder::BreakCycles() {
+void
+MediaDecoder::BreakCycles() {
   SetStateMachine(nullptr);
 }
 
-MediaDecoderOwner* MediaDecoder::GetMediaOwner() const
+MediaDecoderOwner*
+MediaDecoder::GetMediaOwner() const
 {
   return mOwner;
 }
 
-void MediaDecoder::FireTimeUpdate()
+void
+MediaDecoder::FireTimeUpdate()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mOwner)
     return;
   mOwner->FireTimeUpdate(true);
 }
 
-void MediaDecoder::PinForSeek()
+void
+MediaDecoder::PinForSeek()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaResource* resource = GetResource();
   if (!resource || mPinnedForSeek) {
     return;
   }
   mPinnedForSeek = true;
   resource->Pin();
 }
 
-void MediaDecoder::UnpinForSeek()
+void
+MediaDecoder::UnpinForSeek()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MediaResource* resource = GetResource();
   if (!resource || !mPinnedForSeek) {
     return;
   }
   mPinnedForSeek = false;
   resource->Unpin();
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -518,17 +518,17 @@ public:
 
   // Returns a weak reference to the media decoder owner.
   MediaDecoderOwner* GetMediaOwner() const;
 
   bool OnStateMachineTaskQueue() const override;
 
   bool OnDecodeTaskQueue() const override;
 
-  MediaDecoderStateMachine* GetStateMachine() { return mDecoderStateMachine; }
+  MediaDecoderStateMachine* GetStateMachine() const;
   void SetStateMachine(MediaDecoderStateMachine* aStateMachine);
 
   // Returns the monitor for other threads to synchronise access to
   // state.
   ReentrantMonitor& GetReentrantMonitor() override;
 
   // Constructs the time ranges representing what segments of the media
   // are buffered and playable.
@@ -647,19 +647,16 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
     UpdateLogicalPosition(MediaDecoderEventVisibility::Observable);
   }
 
   // Find the end of the cached data starting at the current decoder
   // position.
   int64_t GetDownloadPosition();
 
-  // Provide access to the state machine object
-  MediaDecoderStateMachine* GetStateMachine() const;
-
   // Drop reference to state machine.  Only called during shutdown dance.
   virtual void BreakCycles();
 
   // Notifies the element that decoding has failed.
   virtual void DecodeError();
 
   // Indicate whether the media is same-origin with the element.
   void UpdateSameOriginStatus(bool aSameOrigin);
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -201,17 +201,16 @@ MediaDecoderStateMachine::MediaDecoderSt
   mDecodedVideoEndTime(-1),
   mPlaybackRate(1.0),
   mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
   mAmpleAudioThresholdUsecs(detail::AMPLE_AUDIO_USECS),
   mQuickBufferingLowDataThresholdUsecs(detail::QUICK_BUFFERING_LOW_DATA_USECS),
   mIsAudioPrerolling(false),
   mIsVideoPrerolling(false),
   mAudioCaptured(false),
-  mPositionChangeQueued(false),
   mAudioCompleted(false, "MediaDecoderStateMachine::mAudioCompleted"),
   mNotifyMetadataBeforeFirstFrame(false),
   mDispatchedEventToDecode(false),
   mQuickBuffering(false),
   mMinimizePreroll(false),
   mDecodeThreadWaiting(false),
   mDropAudioUntilNextDiscontinuity(false),
   mDropVideoUntilNextDiscontinuity(false),
@@ -1150,24 +1149,16 @@ void MediaDecoderStateMachine::UpdatePla
   bool fragmentEnded = mFragmentEndTime >= 0 && GetMediaTime() >= mFragmentEndTime;
   mMetadataManager.DispatchMetadataIfNeeded(TimeUnit::FromMicroseconds(aTime));
 
   if (fragmentEnded) {
     StopPlayback();
   }
 }
 
-void MediaDecoderStateMachine::ClearPositionChangeFlag()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-  AssertCurrentThreadInMonitor();
-
-  mPositionChangeQueued = false;
-}
-
 static const char* const gMachineStateStr[] = {
   "NONE",
   "DECODING_METADATA",
   "WAIT_FOR_RESOURCES",
   "WAIT_FOR_CDM",
   "DORMANT",
   "DECODING",
   "SEEKING",
@@ -2891,24 +2882,16 @@ void MediaDecoderStateMachine::StartBuff
   DECODER_LOG("Changed state from DECODING to BUFFERING, decoded for %.3lfs",
               decodeDuration.ToSeconds());
   MediaStatistics stats = GetStatistics();
   DECODER_LOG("Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
               stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)",
               stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)");
 }
 
-void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-  DispatchAudioDecodeTaskIfNeeded();
-  DispatchVideoDecodeTaskIfNeeded();
-}
-
 void
 MediaDecoderStateMachine::ScheduleStateMachine()
 {
   MOZ_ASSERT(OnTaskQueue());
   AssertCurrentThreadInMonitor();
   if (mDispatchedStateMachine) {
     return;
   }
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -260,21 +260,16 @@ private:
   void NotifyWaitingForResourcesStatusChanged();
 
   nsRefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget);
 
   void Shutdown();
 
   void FinishShutdown();
 
-  // Clear the flag indicating that a playback position change event
-  // is currently queued. This is called from the main thread and must
-  // be called with the decode monitor held.
-  void ClearPositionChangeFlag();
-
   // Update the playback position. This can result in a timeupdate event
   // and an invalidate of the frame being dispatched asynchronously if
   // there is no such event currently queued.
   // Only called on the decoder thread. Must be called with
   // the decode monitor held.
   void UpdatePlaybackPosition(int64_t aTime);
 
   // Causes the state machine to switch to buffering state, and to
@@ -317,20 +312,16 @@ private:
     MOZ_ASSERT(OnTaskQueue());
     AssertCurrentThreadInMonitor();
     return mState == DECODER_STATE_SEEKING;
   }
 
   // Returns the state machine task queue.
   TaskQueue* OwnerThread() const { return mTaskQueue; }
 
-  // Calls ScheduleStateMachine() after taking the decoder lock. Also
-  // notifies the decoder thread in case it's waiting on the decoder lock.
-  void ScheduleStateMachineWithLockAndWakeDecoder();
-
   // Schedules the shared state machine thread to run the state machine.
   //
   // The first variant coalesces multiple calls into a single state machine
   // cycle, the second variant does not. The second variant must be used when
   // not already on the state machine task queue.
   void ScheduleStateMachine();
   void ScheduleStateMachineCrossThread()
   {
@@ -1142,23 +1133,16 @@ private:
     return aType == MediaData::AUDIO_DATA ? mAudioWaitRequest : mVideoWaitRequest;
   }
 
   // True if we shouldn't play our audio (but still write it to any capturing
   // streams). When this is true, the audio thread will never start again after
   // it has stopped.
   bool mAudioCaptured;
 
-  // True if an event to notify about a change in the playback
-  // position has been queued, but not yet run. It is set to false when
-  // the event is run. This allows coalescing of these events as they can be
-  // produced many times per second. Synchronised via decoder monitor.
-  // Accessed on main and state machine threads.
-  bool mPositionChangeQueued;
-
   // True if the audio playback thread has finished. It is finished
   // when either all the audio frames have completed playing, or we've moved
   // into shutdown state, and the threads are to be
   // destroyed. Written by the audio playback thread and read and written by
   // the state machine thread. Synchronised via decoder monitor.
   // When data is being sent to a MediaStream, this is true when all data has
   // been written to the MediaStream.
   Watchable<bool> mAudioCompleted;
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1832,16 +1832,19 @@ MediaManager::GetUserMedia(nsPIDOMWindow
   MediaSourceEnum videoType = dom::MediaSourceEnum::Camera;
   MediaSourceEnum audioType = dom::MediaSourceEnum::Microphone;
 
   if (c.mVideo.IsMediaTrackConstraints()) {
     auto& vc = c.mVideo.GetAsMediaTrackConstraints();
     videoType = StringToEnum(dom::MediaSourceEnumValues::strings,
                              vc.mMediaSource,
                              dom::MediaSourceEnum::Other);
+    Telemetry::Accumulate(loop ? Telemetry::LOOP_GET_USER_MEDIA_TYPE :
+                                 Telemetry::WEBRTC_GET_USER_MEDIA_TYPE,
+                          (uint32_t) videoType);
     switch (videoType) {
       case dom::MediaSourceEnum::Camera:
         break;
 
       case dom::MediaSourceEnum::Browser:
       case dom::MediaSourceEnum::Screen:
       case dom::MediaSourceEnum::Application:
       case dom::MediaSourceEnum::Window:
@@ -1864,17 +1867,17 @@ MediaManager::GetUserMedia(nsPIDOMWindow
 #if defined (XP_WIN)
               !IsVistaOrLater()
 #endif
               ) ||
 #endif
             (!privileged && !HostHasPermission(*docURI))) {
           nsRefPtr<MediaStreamError> error =
               new MediaStreamError(aWindow,
-                                   NS_LITERAL_STRING("PermissionDeniedError"));
+                                   NS_LITERAL_STRING("SecurityError"));
           onFailure->OnError(error);
           return NS_OK;
         }
         break;
 
       case dom::MediaSourceEnum::Microphone:
       case dom::MediaSourceEnum::Other:
       default: {
@@ -1929,28 +1932,31 @@ MediaManager::GetUserMedia(nsPIDOMWindow
                              ac.mMediaSource,
                              dom::MediaSourceEnum::Other);
     // Work around WebIDL default since spec uses same dictionary w/audio & video.
     if (audioType == dom::MediaSourceEnum::Camera) {
       audioType = dom::MediaSourceEnum::Microphone;
       ac.mMediaSource.AssignASCII(EnumToASCII(dom::MediaSourceEnumValues::strings,
                                               audioType));
     }
+    Telemetry::Accumulate(loop ? Telemetry::LOOP_GET_USER_MEDIA_TYPE :
+                                 Telemetry::WEBRTC_GET_USER_MEDIA_TYPE,
+                          (uint32_t) audioType);
 
     switch (audioType) {
       case dom::MediaSourceEnum::Microphone:
         break;
 
       case dom::MediaSourceEnum::AudioCapture:
         // Only enable AudioCapture if the pref is enabled. If it's not, we can
         // deny right away.
         if (!Preferences::GetBool("media.getusermedia.audiocapture.enabled")) {
           nsRefPtr<MediaStreamError> error =
             new MediaStreamError(aWindow,
-                                 NS_LITERAL_STRING("PermissionDeniedError"));
+                                 NS_LITERAL_STRING("SecurityError"));
           onFailure->OnError(error);
           return NS_OK;
         }
         break;
 
       case dom::MediaSourceEnum::Other:
       default: {
         nsRefPtr<MediaStreamError> error =
@@ -2000,17 +2006,17 @@ MediaManager::GetUserMedia(nsPIDOMWindow
       rv = permManager->TestExactPermissionFromPrincipal(
         aWindow->GetExtantDoc()->NodePrincipal(), "camera", &videoPerm);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if ((!IsOn(c.mAudio) || audioPerm == nsIPermissionManager::DENY_ACTION) &&
         (!IsOn(c.mVideo) || videoPerm == nsIPermissionManager::DENY_ACTION)) {
       nsRefPtr<MediaStreamError> error =
-          new MediaStreamError(aWindow, NS_LITERAL_STRING("PermissionDeniedError"));
+          new MediaStreamError(aWindow, NS_LITERAL_STRING("SecurityError"));
       onFailure->OnError(error);
       RemoveFromWindowList(windowID, listener);
       return NS_OK;
     }
   }
 
 #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
   if (mCameraManager == nullptr) {
@@ -2626,17 +2632,17 @@ MediaManager::Observe(nsISupports* aSubj
       // A particular device or devices were chosen by the user.
       // NOTE: does not allow setting a device to null; assumes nullptr
       nsCOMPtr<nsISupportsArray> array(do_QueryInterface(aSubject));
       MOZ_ASSERT(array);
       uint32_t len = 0;
       array->Count(&len);
       if (!len) {
         // neither audio nor video were selected
-        task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
+        task->Denied(NS_LITERAL_STRING("SecurityError"));
         return NS_OK;
       }
       bool videoFound = false, audioFound = false;
       for (uint32_t i = 0; i < len; i++) {
         nsCOMPtr<nsISupports> supports;
         array->GetElementAt(i,getter_AddRefs(supports));
         nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supports));
         MOZ_ASSERT(device); // shouldn't be returning anything else...
@@ -2663,17 +2669,17 @@ MediaManager::Observe(nsISupports* aSubj
     if (sInShutdown) {
       return task->Denied(NS_LITERAL_STRING("In shutdown"));
     }
     // Reuse the same thread to save memory.
     MediaManager::PostTask(FROM_HERE, task.forget());
     return NS_OK;
 
   } else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
-    nsString errorMessage(NS_LITERAL_STRING("PermissionDeniedError"));
+    nsString errorMessage(NS_LITERAL_STRING("SecurityError"));
 
     if (aSubject) {
       nsCOMPtr<nsISupportsString> msg(do_QueryInterface(aSubject));
       MOZ_ASSERT(msg);
       msg->GetData(errorMessage);
       if (errorMessage.IsEmpty())
         errorMessage.AssignLiteral(MOZ_UTF16("InternalError"));
     }
--- a/dom/media/MediaPermissionGonk.cpp
+++ b/dom/media/MediaPermissionGonk.cpp
@@ -225,17 +225,17 @@ MediaPermissionRequest::GetElement(nsIDO
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaPermissionRequest::Cancel()
 {
   nsString callID;
   mRequest->GetCallID(callID);
-  NotifyPermissionDeny(callID, NS_LITERAL_STRING("PermissionDeniedError"));
+  NotifyPermissionDeny(callID, NS_LITERAL_STRING("SecurityError"));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaPermissionRequest::Allow(JS::HandleValue aChoices)
 {
   // check if JS object
   if (!aChoices.isObject()) {
--- a/dom/media/MediaStreamError.cpp
+++ b/dom/media/MediaStreamError.cpp
@@ -15,18 +15,18 @@ BaseMediaMgrError::BaseMediaMgrError(con
                                      const nsAString& aConstraint)
   : mName(aName)
   , mMessage(aMessage)
   , mConstraint(aConstraint)
 {
   if (mMessage.IsEmpty()) {
     if (mName.EqualsLiteral("NotFoundError")) {
       mMessage.AssignLiteral("The object can not be found here.");
-    } else if (mName.EqualsLiteral("PermissionDeniedError")) {
-      mMessage.AssignLiteral("The user did not grant permission for the operation.");
+    } else if (mName.EqualsLiteral("SecurityError")) {
+      mMessage.AssignLiteral("The operation is insecure.");
     } else if (mName.EqualsLiteral("SourceUnavailableError")) {
       mMessage.AssignLiteral("The source of the MediaStream could not be "
           "accessed due to a hardware error (e.g. lock from another process).");
     } else if (mName.EqualsLiteral("InternalError")) {
       mMessage.AssignLiteral("Internal error.");
     } else if (mName.EqualsLiteral("NotSupportedError")) {
       mMessage.AssignLiteral("The operation is not supported.");
     } else if (mName.EqualsLiteral("OverconstrainedError")) {
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html
@@ -24,26 +24,26 @@ var tests = [
                    fake: true },
     error: null },
   { message: "audio overconstrained by facingMode ignored",
     constraints: { audio: { facingMode: { exact: 'left' } },
                    fake: true },
     error: null },
   { message: "full screensharing requires permission",
     constraints: { video: { mediaSource: 'screen' } },
-    error: "PermissionDeniedError" },
+    error: "SecurityError" },
   { message: "application screensharing requires permission",
     constraints: { video: { mediaSource: 'application' } },
-    error: "PermissionDeniedError" },
+    error: "SecurityError" },
   { message: "window screensharing requires permission",
     constraints: { video: { mediaSource: 'window' } },
-    error: "PermissionDeniedError" },
+    error: "SecurityError" },
   { message: "browser screensharing requires permission",
     constraints: { video: { mediaSource: 'browser' } },
-    error: "PermissionDeniedError" },
+    error: "SecurityError" },
   { message: "unknown mediaSource in video fails",
     constraints: { video: { mediaSource: 'uncle' } },
     error: "OverconstrainedError",
     constraint: "mediaSource" },
   { message: "unknown mediaSource in audio fails",
     constraints: { audio: { mediaSource: 'uncle' } },
     error: "OverconstrainedError",
     constraint: "mediaSource" },
--- a/dom/webidl/ChromeUtils.webidl
+++ b/dom/webidl/ChromeUtils.webidl
@@ -36,23 +36,23 @@ interface ChromeUtils : ThreadSafeChrome
  * OriginAttributes, the second is used for pattern-matching (i.e. does this
  * OriginAttributesDictionary match the non-empty attributes in this pattern).
  *
  * IMPORTANT: If you add any members here, you need to do the following:
  * (1) Add them to both dictionaries.
  * (2) Update the methods on mozilla::OriginAttributes, including equality,
  *     serialization, and deserialization.
  * (3) Update the methods on mozilla::OriginAttributesPattern, including matching.
- * (4) Bump the CIDs (_not_ IIDs) of all the principal implementations that
- *     use OriginAttributes in their nsISerializable implementations.
  */
 dictionary OriginAttributesDictionary {
   unsigned long appId = 0;
   unsigned long userContextId = 0;
   boolean inBrowser = false;
   DOMString addonId = "";
+  DOMString signedPkg = "";
 };
 dictionary OriginAttributesPatternDictionary {
   unsigned long appId;
   unsigned long userContextId;
   boolean inBrowser;
   DOMString addonId;
+  DOMString signedPkg;
 };
--- a/dom/webidl/MediaStreamTrack.webidl
+++ b/dom/webidl/MediaStreamTrack.webidl
@@ -25,16 +25,17 @@ enum MediaSourceEnum {
     "camera",
     "screen",
     "application",
     "window",
     "browser",
     "microphone",
     "audioCapture",
     "other"
+    // If values are added, adjust n_values in Histograms.json (2 places)
 };
 
 typedef (long or ConstrainLongRange) ConstrainLong;
 typedef (double or ConstrainDoubleRange) ConstrainDouble;
 typedef (boolean or ConstrainBooleanParameters) ConstrainBoolean;
 typedef (DOMString or sequence<DOMString> or ConstrainDOMStringParameters) ConstrainDOMString;
 
 // Note: When adding new constraints, remember to update the SelectSettings()
--- a/dom/workers/ServiceWorkerRegistrar.cpp
+++ b/dom/workers/ServiceWorkerRegistrar.cpp
@@ -327,18 +327,19 @@ ServiceWorkerRegistrar::ReadData()
     GET_LINE(suffix);
 
     OriginAttributes attrs;
     if (!attrs.PopulateFromSuffix(suffix)) {
       return NS_ERROR_INVALID_ARG;
     }
 
     GET_LINE(line);
+    nsCString signedPkg = NS_ConvertUTF16toUTF8(attrs.mSignedPkg);
     entry->principal() =
-      mozilla::ipc::ContentPrincipalInfo(attrs.mAppId, attrs.mInBrowser, line);
+      mozilla::ipc::ContentPrincipalInfo(attrs.mAppId, attrs.mInBrowser, line, signedPkg);
 
     GET_LINE(entry->scope());
     GET_LINE(entry->scriptSpec());
     GET_LINE(entry->currentWorkerURL());
 
     nsAutoCString cacheName;
     GET_LINE(cacheName);
     CopyUTF8toUTF16(cacheName, entry->activeCacheName());
--- a/dom/workers/test/gtest/TestReadWrite.cpp
+++ b/dom/workers/test/gtest/TestReadWrite.cpp
@@ -216,17 +216,17 @@ TEST(ServiceWorkerRegistrar, TestWriteDa
 
     nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
 
     for (int i = 0; i < 10; ++i) {
       ServiceWorkerRegistrationData* d = data.AppendElement();
 
       nsAutoCString spec;
       spec.AppendPrintf("spec write %d", i);
-      d->principal() = mozilla::ipc::ContentPrincipalInfo(i, i % 2, spec);
+      d->principal() = mozilla::ipc::ContentPrincipalInfo(i, i % 2, spec, EmptyCString());
       d->scope().AppendPrintf("scope write %d", i);
       d->scriptSpec().AppendPrintf("scriptSpec write %d", i);
       d->currentWorkerURL().AppendPrintf("currentWorkerURL write %d", i);
       d->activeCacheName().AppendPrintf("activeCacheName write %d", i);
       d->waitingCacheName().AppendPrintf("waitingCacheName write %d", i);
     }
 
     nsresult rv = swr->TestWriteData();
--- a/editor/composer/nsEditorSpellCheck.cpp
+++ b/editor/composer/nsEditorSpellCheck.cpp
@@ -595,18 +595,19 @@ nsEditorSpellCheck::SetCurrentDictionary
   if (!mUpdateDictionaryRunning) {
 
     // Ignore pending dictionary fetchers by increasing this number.
     mDictionaryFetcherGroup++;
 
     uint32_t flags = 0;
     mEditor->GetFlags(&flags);
     if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
-      if (mPreferredLang.IsEmpty() ||
-          !mPreferredLang.Equals(aDictionary, nsCaseInsensitiveStringComparator())) {
+      if (!aDictionary.IsEmpty() && (mPreferredLang.IsEmpty() ||
+          !mPreferredLang.Equals(aDictionary,
+                                 nsCaseInsensitiveStringComparator()))) {
         // When user sets dictionary manually, we store this value associated
         // with editor url, if it doesn't match the document language exactly.
         // For example on "en" sites, we need to store "en-GB", otherwise
         // the language might jump back to en-US although the user explicitly
         // chose otherwise.
         StoreCurrentDictionary(mEditor, aDictionary);
 #ifdef DEBUG_DICT
         printf("***** Writing content preferences for |%s|\n",
@@ -634,37 +635,16 @@ nsEditorSpellCheck::SetCurrentDictionary
   }
   return mSpellChecker->SetCurrentDictionary(aDictionary);
 }
 
 NS_IMETHODIMP
 nsEditorSpellCheck::CheckCurrentDictionary()
 {
   mSpellChecker->CheckCurrentDictionary();
-
-  // Check if our current dictionary is still available.
-  nsAutoString currentDictionary;
-  nsresult rv = GetCurrentDictionary(currentDictionary);
-  if (NS_SUCCEEDED(rv) && !currentDictionary.IsEmpty()) {
-    return NS_OK;
-  }
-
-  // If our preferred current dictionary has gone, pick another one.
-  nsTArray<nsString> dictList;
-  rv = mSpellChecker->GetDictionaryList(&dictList);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (dictList.Length() > 0) {
-    // Use RAII object to prevent content preferences being written during
-    // this call.
-    UpdateDictionaryHolder holder(this);
-    rv = SetCurrentDictionary(dictList[0]);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsEditorSpellCheck::UninitSpellChecker()
 {
   NS_ENSURE_TRUE(mSpellChecker, NS_ERROR_NOT_INITIALIZED);
 
@@ -759,17 +739,17 @@ nsEditorSpellCheck::TryDictionary(const 
       case DICT_COMPARE_CASE_INSENSITIVE:
         equals = aDictName.Equals(dictStr, nsCaseInsensitiveStringComparator());
         break;
       case DICT_COMPARE_DASHMATCH:
         equals = nsStyleUtil::DashMatchCompare(dictStr, aDictName, nsCaseInsensitiveStringComparator());
         break;
     }
     if (equals) {
-      rv = SetCurrentDictionary(dictStr);
+      rv = mSpellChecker->SetCurrentDictionary(dictStr);
 #ifdef DEBUG_DICT
       if (NS_SUCCEEDED(rv))
         printf("***** Set |%s|.\n", NS_ConvertUTF16toUTF8(dictStr).get());
 #endif
       // We always break here. We tried to set the dictionary to an existing
       // dictionary from the list. This must work, if it doesn't, there is
       // no point trying another one.
       break;
@@ -830,27 +810,35 @@ nsEditorSpellCheck::DictionaryFetched(Di
   if (mPreferredLang.IsEmpty()) {
     mPreferredLang.Assign(aFetcher->mRootDocContentLang);
 #ifdef DEBUG_DICT
     printf("***** mPreferredLang (content-language) |%s|\n",
            NS_ConvertUTF16toUTF8(mPreferredLang).get());
 #endif
   }
 
+  // Auxiliary status.
+  nsresult rv2;
+
+  // We obtain a list of available dictionaries.
+  nsTArray<nsString> dictList;
+  rv2 = mSpellChecker->GetDictionaryList(&dictList);
+  NS_ENSURE_SUCCESS(rv2, rv2);
+
   // Priority 1:
   // If we successfully fetched a dictionary from content prefs, do not go
   // further. Use this exact dictionary.
   // Don't use content preferences for editor with eEditorMailMask flag.
   nsAutoString dictName;
   uint32_t flags;
   mEditor->GetFlags(&flags);
   if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
     dictName.Assign(aFetcher->mDictionary);
     if (!dictName.IsEmpty()) {
-      if (NS_SUCCEEDED(SetCurrentDictionary(dictName))) {
+      if (NS_SUCCEEDED(TryDictionary(dictName, dictList, DICT_NORMAL_COMPARE))) {
 #ifdef DEBUG_DICT
         printf("***** Assigned from content preferences |%s|\n",
                NS_ConvertUTF16toUTF8(dictName).get());
 #endif
 
         // We take an early exit here, so let's not forget to clear the word
         // list.
         DeleteSuggestedWordList();
@@ -866,24 +854,16 @@ nsEditorSpellCheck::DictionaryFetched(Di
   // After checking the content preferences, we use the language of the element
   // or document.
   dictName.Assign(mPreferredLang);
 #ifdef DEBUG_DICT
   printf("***** Assigned from element/doc |%s|\n",
          NS_ConvertUTF16toUTF8(dictName).get());
 #endif
 
-  // Auxiliary status.
-  nsresult rv2;
-
-  // We obtain a list of available dictionaries.
-  nsTArray<nsString> dictList;
-  rv2 = mSpellChecker->GetDictionaryList(&dictList);
-  NS_ENSURE_SUCCESS(rv2, rv2);
-
   // Get the preference value.
   nsAutoString preferredDict;
   preferredDict = Preferences::GetLocalizedString("spellchecker.dictionary");
 
   // The following will be driven by this status. Once we were able to set a
   // dictionary successfully, we're done. So we start with a "failed" status.
   nsresult rv = NS_ERROR_NOT_AVAILABLE;
 
@@ -1001,17 +981,19 @@ nsEditorSpellCheck::DictionaryFetched(Di
           rv = TryDictionary(lang2, dictList, DICT_COMPARE_CASE_INSENSITIVE);
         }
       }
 
       // Priority 7:
       // If it does not work, pick the first one.
       if (NS_FAILED(rv)) {
         if (dictList.Length() > 0) {
-          rv = SetCurrentDictionary(dictList[0]);
+          nsAutoString firstInList;
+          firstInList.Assign(dictList[0]);
+          rv = TryDictionary(firstInList, dictList, DICT_NORMAL_COMPARE);
 #ifdef DEBUG_DICT
           printf("***** Trying first of list |%s|\n",
                  NS_ConvertUTF16toUTF8(dictList[0]).get());
           if (NS_SUCCEEDED(rv))
             printf ("***** Setting worked.\n");
 #endif
         }
       }
--- a/editor/composer/test/chrome.ini
+++ b/editor/composer/test/chrome.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g' || os == 'android'
 
 [test_async_UpdateCurrentDictionary.html]
 [test_bug338427.html]
 [test_bug434998.xul]
 [test_bug678842.html]
-[test_abug697981.html]
+[test_bug697981.html]
 [test_bug717433.html]
 [test_bug1204147.html]
 [test_bug1200533.html]
--- a/editor/composer/test/test_async_UpdateCurrentDictionary.html
+++ b/editor/composer/test/test_async_UpdateCurrentDictionary.html
@@ -43,18 +43,21 @@ function start() {
       // Second, make some Update calls, but then do a Set.  The Set should
       // effectively cancel the Updates, but the Updates' callbacks should be
       // called nonetheless.
       var numCalls = 3;
       for (var i = 0; i < numCalls; i++) {
         sc.UpdateCurrentDictionary(function () {
           is(sc.GetCurrentDictionary(), "",
              "No dictionary should be active after Update.");
-          if (--numCalls == 0)
+          if (--numCalls == 0) {
+            // This will clear the content preferences and reset "spellchecker.dictionary".
+            sc.SetCurrentDictionary("");
             SimpleTest.finish();
+          }
         });
       }
       try {
         sc.SetCurrentDictionary("testing-XX");
       }
       catch (err) {
         // Set throws NS_ERROR_NOT_AVAILABLE because "testing-XX" isn't really
         // an available dictionary.
--- a/editor/composer/test/test_bug338427.html
+++ b/editor/composer/test/test_bug338427.html
@@ -37,16 +37,19 @@ function init() {
         spellchecker.spellChecker.SetCurrentDictionary(lang);
 
         onSpellCheck(textarea, function () {
             try {
                 var dictionary =
                     spellchecker.spellChecker.GetCurrentDictionary();
             } catch(e) {}
             is(dictionary, lang, "Unexpected spell check dictionary");
+
+            // This will clear the content preferences and reset "spellchecker.dictionary".
+            spellchecker.spellChecker.SetCurrentDictionary("");
             SimpleTest.finish();
         });
     });
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(init);
 
--- a/editor/composer/test/test_bug678842.html
+++ b/editor/composer/test/test_bug678842.html
@@ -80,18 +80,18 @@ var loadListener = function(evt) {
       content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug678842_subframe.html?firstload=false';
     } else {
       is (currentDictonary, "en-GB", "unexpected lang " + currentDictonary + " instead of en-GB");
       content.removeEventListener('load', loadListener, false);
 
       // Remove the fake en-GB dictionary again, since it's otherwise picked up by later tests.
       hunspell.removeDirectory(en_GB);
 
-      // Reset the preference, so the last value we set doesn't collide with the next test.
-      Services.prefs.setCharPref("spellchecker.dictionary", "");
+      // This will clear the content preferences and reset "spellchecker.dictionary".
+      spellchecker.SetCurrentDictionary("");
       SimpleTest.finish();
     }
   });
 }
 
 content.addEventListener('load', loadListener, false);
 
 content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug678842_subframe.html?firstload=true';
rename from editor/composer/test/test_abug697981.html
rename to editor/composer/test/test_bug697981.html
--- a/editor/composer/test/test_abug697981.html
+++ b/editor/composer/test/test_bug697981.html
@@ -24,21 +24,16 @@ function getMisspelledWords(editor) {
 }
 
 var elem_de;
 var editor_de;
 var de_DE;
 var hunspell;
 
 /** Test for Bug 697981 **/
-/*
- * Note the hack: This test fails of there are content preferences left behind from previous tests.
- * That's why this test resides in a file "test_abug697981.html" so it runs first.
- * We will fix this later.
- */
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(function() {
   Components.utils.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm");
 
   var dir = Components.classes["@mozilla.org/file/directory_service;1"]
                       .getService(Components.interfaces.nsIProperties)
                       .get("CurWorkD", Components.interfaces.nsIFile);
   dir.append("tests");
--- a/editor/composer/test/test_bug717433.html
+++ b/editor/composer/test/test_bug717433.html
@@ -27,17 +27,16 @@ var content = document.getElementById('c
 
 var firstLoad = true;
 var expected = "";
 var en_GB;
 var hunspell;
 
 var loadListener = function(evt) {
   Components.utils.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm");
-  Components.utils.import("resource://gre/modules/Services.jsm");
 
   if (firstLoad) {
     var dir = Components.classes["@mozilla.org/file/directory_service;1"]
                         .getService(Components.interfaces.nsIProperties)
                         .get("CurWorkD", Components.interfaces.nsIFile);
     dir.append("tests");
     dir.append("editor");
     dir.append("composer");
@@ -81,18 +80,18 @@ var loadListener = function(evt) {
       content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug717433_subframe.html?firstload=false';
     } else {
       is(currentDictonary, expected, expected + " expected");
       content.removeEventListener('load', loadListener, false);
 
       // Remove the fake en-GB dictionary again, since it's otherwise picked up by later tests.
       hunspell.removeDirectory(en_GB);
 
-      // Reset the preference, so the last value we set doesn't collide with the next test.
-      Services.prefs.setCharPref("spellchecker.dictionary", "");
+      // This will clear the content preferences and reset "spellchecker.dictionary".
+      spellchecker.SetCurrentDictionary("");
       SimpleTest.finish();
     }
   });
 }
 
 content.addEventListener('load', loadListener, false);
 
 content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug717433_subframe.html?firstload=true';
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -1323,22 +1323,21 @@ NS_IMETHODIMP nsEditor::Observe(nsISuppo
                        SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION),
                "Unexpected observer topic");
 
   // When mozInlineSpellChecker::CanEnableInlineSpellChecking changes
   SyncRealTimeSpell();
 
   // When nsIEditorSpellCheck::GetCurrentDictionary changes
   if (mInlineSpellChecker) {
-    // if the current dictionary is no longer available, find another one
+    // Do the right thing in the spellchecker, if the dictionary is no longer
+    // available. This will not set a new dictionary.
     nsCOMPtr<nsIEditorSpellCheck> editorSpellCheck;
     mInlineSpellChecker->GetSpellChecker(getter_AddRefs(editorSpellCheck));
     if (editorSpellCheck) {
-      // Note: This might change the current dictionary, which may call
-      // this observer recursively.
       editorSpellCheck->CheckCurrentDictionary();
     }
 
     // update the inline spell checker to reflect the new current dictionary
     mInlineSpellChecker->SpellCheckRange(nullptr); // causes recheck
   }
 
   return NS_OK;
--- a/editor/nsIEditorSpellCheck.idl
+++ b/editor/nsIEditorSpellCheck.idl
@@ -11,17 +11,16 @@ interface nsIEditorSpellCheckCallback;
 
 [scriptable, uuid(dd32ef3b-a7d8-43d1-9617-5f2dddbe29eb)]
 interface nsIEditorSpellCheck : nsISupports
 {
 
   /**
    * Call this on any change in installed dictionaries to ensure that the spell
    * checker is not using a current dictionary which is no longer available.
-   * If the current dictionary is no longer available, then pick another one.
    */
   void checkCurrentDictionary();
 
  /**
    * Returns true if we can enable spellchecking. If there are no available
    * dictionaries, this will return false.
    */
   boolean       canSpellCheck();
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -47,24 +47,26 @@
 #include "SourceSurfaceRawData.h"
 
 #include "DrawEventRecorder.h"
 
 #include "Logging.h"
 
 #include "mozilla/CheckedInt.h"
 
+#if defined(PR_LOGGING)
 GFX2D_API PRLogModuleInfo *
 GetGFX2DLog()
 {
   static PRLogModuleInfo *sLog;
   if (!sLog)
     sLog = PR_NewLogModule("gfx2d");
   return sLog;
 }
+#endif
 
 // The following code was largely taken from xpcom/glue/SSE.cpp and
 // made a little simpler.
 enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
 
 #ifdef HAVE_CPUID_H
 
 #if !(defined(__SSE2__) || defined(_M_X64) || \
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -17,17 +17,19 @@
 
 #if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
 #include "nsDebug.h"
 #endif
 #include "Point.h"
 #include "BaseRect.h"
 #include "Matrix.h"
 
+#if defined(MOZ_LOGGING)
 extern GFX2D_API PRLogModuleInfo *GetGFX2DLog();
+#endif
 
 namespace mozilla {
 namespace gfx {
 
 // Attempting to be consistent with prlog values, but that isn't critical
 // (and note that 5 has a special meaning - see the description
 // with sGfxLogLevel)
 const int LOG_CRITICAL = 1;
@@ -37,31 +39,33 @@ const int LOG_DEBUG_PRLOG = 4;
 const int LOG_EVERYTHING = 5; // This needs to be the highest value
 
 #if defined(DEBUG)
 const int LOG_DEFAULT = LOG_EVERYTHING;
 #else
 const int LOG_DEFAULT = LOG_CRITICAL;
 #endif
 
+#if defined(MOZ_LOGGING)
 inline mozilla::LogLevel PRLogLevelForLevel(int aLevel) {
   switch (aLevel) {
   case LOG_CRITICAL:
     return LogLevel::Error;
   case LOG_WARNING:
     return LogLevel::Warning;
   case LOG_DEBUG:
     return LogLevel::Debug;
   case LOG_DEBUG_PRLOG:
     return LogLevel::Debug;
   case LOG_EVERYTHING:
     return LogLevel::Error;
   }
   return LogLevel::Debug;
 }
+#endif
 
 class PreferenceAccess
 {
 public:
   virtual ~PreferenceAccess();
 
   // This should connect the variable aVar to be updated whenever a preference
   // aName is modified.  aDefault would be used if the preference is undefined,
@@ -128,19 +132,22 @@ struct BasicLogger
   // For efficiency, this method exists and copies the logic of the
   // OutputMessage below.  If making any changes here, also make it
   // in the appropriate places in that method.
   static bool ShouldOutputMessage(int aLevel) {
     if (PreferenceAccess::sGfxLogLevel >= aLevel) {
 #if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
       return true;
 #else
+#if defined(MOZ_LOGGING)
       if (MOZ_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) {
         return true;
-      } else if ((PreferenceAccess::sGfxLogLevel >= LOG_DEBUG_PRLOG) ||
+      } else
+#endif
+      if ((PreferenceAccess::sGfxLogLevel >= LOG_DEBUG_PRLOG) ||
                  (aLevel < LOG_DEBUG)) {
         return true;
       }
 #endif
     }
     return false;
   }
 
@@ -155,19 +162,22 @@ struct BasicLogger
     //
     // If making any logic changes to this method, you should probably
     // make the corresponding change in the ShouldOutputMessage method
     // above.
     if (PreferenceAccess::sGfxLogLevel >= aLevel) {
 #if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID)
       printf_stderr("%s%s", aString.c_str(), aNoNewline ? "" : "\n");
 #else
+#if defined(MOZ_LOGGING)
       if (MOZ_LOG_TEST(GetGFX2DLog(), PRLogLevelForLevel(aLevel))) {
         PR_LogPrint("%s%s", aString.c_str(), aNoNewline ? "" : "\n");
-      } else if ((PreferenceAccess::sGfxLogLevel >= LOG_DEBUG_PRLOG) ||
+      } else
+#endif
+      if ((PreferenceAccess::sGfxLogLevel >= LOG_DEBUG_PRLOG) ||
                  (aLevel < LOG_DEBUG)) {
         printf("%s%s", aString.c_str(), aNoNewline ? "" : "\n");
       }
 #endif
     }
   }
 };
 
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -70,19 +70,21 @@ SurfaceDescriptorX11::SurfaceDescriptorX
 {
   const XRenderPictFormat *pictFormat = aSurf->XRenderFormat();
   if (pictFormat) {
     mFormat = pictFormat->id;
   } else {
     mFormat = cairo_xlib_surface_get_visual(aSurf->CairoSurface())->visualid;
   }
 
+#ifdef GL_PROVIDER_GLX
   if (aForwardGLX) {
     mGLXPixmap = aSurf->GetGLXPixmap();
   }
+#endif
 }
 
 SurfaceDescriptorX11::SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
                                            const gfx::IntSize& aSize)
   : mId(aDrawable)
   , mFormat(aFormatID)
   , mSize(aSize)
   , mGLXPixmap(None)
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -77,16 +77,17 @@ PrincipalInfoToPrincipal(const Principal
         return nullptr;
       }
 
       if (info.appId() == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
         rv = secMan->GetSimpleCodebasePrincipal(uri, getter_AddRefs(principal));
       } else {
         // TODO: Bug 1167100 - User nsIPrincipal.originAttribute in ContentPrincipalInfo
         OriginAttributes attrs(info.appId(), info.isInBrowserElement());
+        attrs.mSignedPkg = NS_ConvertUTF8toUTF16(info.signedPkg());
         principal = BasePrincipal::CreateCodebasePrincipal(uri, attrs);
         rv = principal ? NS_OK : NS_ERROR_FAILURE;
       }
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return nullptr;
       }
 
       return principal.forget();
@@ -197,16 +198,20 @@ PrincipalToPrincipalInfo(nsIPrincipal* a
   }
 
   nsCString spec;
   rv = uri->GetSpec(spec);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
+  const mozilla::OriginAttributes& attr =
+	mozilla::BasePrincipal::Cast(aPrincipal)->OriginAttributesRef();
+  nsCString signedPkg = NS_ConvertUTF16toUTF8(attr.mSignedPkg);
+
   bool isUnknownAppId;
   rv = aPrincipal->GetUnknownAppId(&isUnknownAppId);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   uint32_t appId;
   if (isUnknownAppId) {
@@ -219,17 +224,17 @@ PrincipalToPrincipalInfo(nsIPrincipal* a
   }
 
   bool isInBrowserElement;
   rv = aPrincipal->GetIsInBrowserElement(&isInBrowserElement);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
-  *aPrincipalInfo = ContentPrincipalInfo(appId, isInBrowserElement, spec);
+  *aPrincipalInfo = ContentPrincipalInfo(appId, isInBrowserElement, spec, signedPkg);
   return NS_OK;
 }
 
 nsresult
 LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
                        OptionalLoadInfoArgs* aOptionalLoadInfoArgs)
 {
   if (!aLoadInfo) {
--- a/ipc/glue/PBackgroundSharedTypes.ipdlh
+++ b/ipc/glue/PBackgroundSharedTypes.ipdlh
@@ -7,16 +7,17 @@ using struct mozilla::void_t from "ipc/I
 namespace mozilla {
 namespace ipc {
 
 struct ContentPrincipalInfo
 {
   uint32_t appId;
   bool isInBrowserElement;
   nsCString spec;
+  nsCString signedPkg;
 };
 
 struct SystemPrincipalInfo
 { };
 
 struct NullPrincipalInfo
 { };
 
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -27,16 +27,17 @@ builtin(include, ../../build/autoconf/zl
 builtin(include, ../../build/autoconf/linux.m4)dnl
 builtin(include, ../../build/autoconf/python-virtualenv.m4)dnl
 builtin(include, ../../build/autoconf/winsdk.m4)dnl
 builtin(include, ../../build/autoconf/icu.m4)dnl
 builtin(include, ../../build/autoconf/ffi.m4)dnl
 builtin(include, ../../build/autoconf/clang-plugin.m4)dnl
 builtin(include, ../../build/autoconf/alloc.m4)dnl
 builtin(include, ../../build/autoconf/jemalloc.m4)dnl
+builtin(include, ../../build/autoconf/ios.m4)dnl
 
 define([__MOZ_AC_INIT_PREPARE], defn([AC_INIT_PREPARE]))
 define([AC_INIT_PREPARE],
 [if test -z "$srcdir"; then
   srcdir=`dirname "[$]0"`
 fi
 srcdir="$srcdir/../.."
 __MOZ_AC_INIT_PREPARE($1)
--- a/js/src/asmjs/AsmJSSignalHandlers.cpp
+++ b/js/src/asmjs/AsmJSSignalHandlers.cpp
@@ -193,17 +193,17 @@ class AutoSetHandlingSignal
 # define R12_sig(p) ((p)->uc_mcontext.mc_r12)
 # define R13_sig(p) ((p)->uc_mcontext.mc_r13)
 # define R14_sig(p) ((p)->uc_mcontext.mc_r14)
 # if defined(__FreeBSD__) && defined(__arm__)
 #  define R15_sig(p) ((p)->uc_mcontext.__gregs[_REG_R15])
 # else
 #  define R15_sig(p) ((p)->uc_mcontext.mc_r15)
 # endif
-#elif defined(XP_MACOSX)
+#elif defined(XP_DARWIN)
 # define EIP_sig(p) ((p)->uc_mcontext->__ss.__eip)
 # define RIP_sig(p) ((p)->uc_mcontext->__ss.__rip)
 #else
 # error "Don't know how to read/write to the thread state via the mcontext_t."
 #endif
 
 #if defined(XP_WIN)
 # include "jswin.h"
@@ -308,17 +308,17 @@ enum { REG_EIP = 14 };
 #if !defined(XP_WIN)
 # define CONTEXT ucontext_t
 #endif
 
 // Define a context type for use in the emulator code. This is usually just
 // the same as CONTEXT, but on Mac we use a different structure since we call
 // into the emulator code from a Mach exception handler rather than a
 // sigaction-style signal handler.
-#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 # if defined(JS_CODEGEN_X64)
 struct macos_x64_context {
     x86_thread_state64_t thread;
     x86_float_state64_t float_;
 };
 #  define EMULATOR_CONTEXT macos_x64_context
 # else
 struct macos_x86_context {
@@ -416,17 +416,17 @@ StoreValueFromGPReg(void* addr, size_t s
 
 MOZ_COLD static void
 StoreValueFromGPImm(void* addr, size_t size, int32_t imm)
 {
     MOZ_RELEASE_ASSERT(size <= sizeof(imm));
     memcpy(addr, &imm, size);
 }
 
-# if !defined(XP_MACOSX)
+# if !defined(XP_DARWIN)
 MOZ_COLD static void*
 AddressOfFPRegisterSlot(CONTEXT* context, FloatRegisters::Encoding encoding)
 {
     switch (encoding) {
       case X86Encoding::xmm0:  return &XMM_sig(context, 0);
       case X86Encoding::xmm1:  return &XMM_sig(context, 1);
       case X86Encoding::xmm2:  return &XMM_sig(context, 2);
       case X86Encoding::xmm3:  return &XMM_sig(context, 3);
@@ -516,17 +516,17 @@ AddressOfGPRegisterSlot(EMULATOR_CONTEXT
       case X86Encoding::r12: return &context->thread.__r12;
       case X86Encoding::r13: return &context->thread.__r13;
       case X86Encoding::r14: return &context->thread.__r14;
       case X86Encoding::r15: return &context->thread.__r15;
       default: break;
     }
     MOZ_CRASH();
 }
-# endif  // !XP_MACOSX
+# endif  // !XP_DARWIN
 #endif // JS_CODEGEN_X64
 
 MOZ_COLD static void
 SetRegisterToCoercedUndefined(EMULATOR_CONTEXT* context, size_t size,
                               const Disassembler::OtherOperand& value)
 {
     if (value.kind() == Disassembler::OtherOperand::FPR)
         SetFPRegToNaN(size, AddressOfFPRegisterSlot(context, value.fpr()));
@@ -788,17 +788,17 @@ AsmJSFaultHandler(LPEXCEPTION_POINTERS e
 {
     if (HandleFault(exception))
         return EXCEPTION_CONTINUE_EXECUTION;
 
     // No need to worry about calling other handlers, the OS does this for us.
     return EXCEPTION_CONTINUE_SEARCH;
 }
 
-#elif defined(XP_MACOSX)
+#elif defined(XP_DARWIN)
 # include <mach/exc.h>
 
 static uint8_t**
 ContextToPC(EMULATOR_CONTEXT* context)
 {
 # if defined(JS_CPU_X64)
     static_assert(sizeof(context->thread.__rip) == sizeof(void*),
                   "stored IP should be compile-time pointer-sized");
@@ -1194,17 +1194,17 @@ JitInterruptHandler(int signum, siginfo_
     if (JSRuntime* rt = RuntimeForCurrentThread())
         RedirectJitCodeToInterruptCheck(rt, (CONTEXT*)context);
 }
 #endif
 
 bool
 js::EnsureSignalHandlersInstalled(JSRuntime* rt)
 {
-#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     // On OSX, each JSRuntime gets its own handler thread.
     if (!rt->asmJSMachExceptionHandler.installed() && !rt->asmJSMachExceptionHandler.install(rt))
         return false;
 #endif
 
     // All the rest of the handlers are process-wide and thus must only be
     // installed once. We assume that there are no races creating the first
     // JSRuntime of the process.
@@ -1257,17 +1257,17 @@ js::EnsureSignalHandlersInstalled(JSRunt
 #endif // defined(XP_WIN)
 
 #if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     // Install a SIGSEGV handler to handle safely-out-of-bounds asm.js heap
     // access.
 # if defined(XP_WIN)
     if (!AddVectoredExceptionHandler(/* FirstHandler = */ true, AsmJSFaultHandler))
         return false;
-# elif defined(XP_MACOSX)
+# elif defined(XP_DARWIN)
     // OSX handles seg faults via the Mach exception handler above, so don't
     // install AsmJSFaultHandler.
 # else
     // SA_NODEFER allows us to reenter the signal handler if we crash while
     // handling the signal, and fall through to the Breakpad handler by testing
     // handlingSignal.
     struct sigaction faultHandler;
     faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER;
--- a/js/src/asmjs/AsmJSSignalHandlers.h
+++ b/js/src/asmjs/AsmJSSignalHandlers.h
@@ -14,17 +14,17 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef asmjs_AsmJSSignalHandlers_h
 #define asmjs_AsmJSSignalHandlers_h
 
-#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 # include <mach/mach.h>
 # include "jslock.h"
 #endif
 
 struct JSRuntime;
 
 namespace js {
 
@@ -34,17 +34,17 @@ namespace js {
 //  - rely on InterruptRunningJitCode to halt running Ion/asm.js from any thread
 bool
 EnsureSignalHandlersInstalled(JSRuntime* rt);
 
 // Force any currently-executing asm.js code to call HandleExecutionInterrupt.
 extern void
 InterruptRunningJitCode(JSRuntime* rt);
 
-#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
 // On OSX we are forced to use the lower-level Mach exception mechanism instead
 // of Unix signals. Mach exceptions are not handled on the victim's stack but
 // rather require an extra thread. For simplicity, we create one such thread
 // per JSRuntime (upon the first use of asm.js in the JSRuntime). This thread
 // and related resources are owned by AsmJSMachExceptionHandler which is owned
 // by JSRuntime.
 class AsmJSMachExceptionHandler
 {
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -1299,31 +1299,35 @@ class MOZ_STACK_CLASS ModuleValidator
     bool tryRequireHeapLengthToBeAtLeast(uint32_t len) {
         return module_->tryRequireHeapLengthToBeAtLeast(len);
     }
     uint32_t minHeapLength() const {
         return module_->minHeapLength();
     }
 
     // Error handling.
+    bool hasAlreadyFailed() const {
+        return !!errorString_;
+    }
+
     bool failOffset(uint32_t offset, const char* str) {
-        MOZ_ASSERT(!errorString_);
+        MOZ_ASSERT(!hasAlreadyFailed());
         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
         MOZ_ASSERT(str);
         errorOffset_ = offset;
         errorString_ = DuplicateString(cx_, str);
         return false;
     }
 
     bool fail(ParseNode* pn, const char* str) {
         return failOffset(pn->pn_pos.begin, str);
     }
 
     bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap) {
-        MOZ_ASSERT(!errorString_);
+        MOZ_ASSERT(!hasAlreadyFailed());
         MOZ_ASSERT(errorOffset_ == UINT32_MAX);
         MOZ_ASSERT(fmt);
         errorOffset_ = offset;
         errorString_.reset(JS_vsmprintf(fmt, ap));
         return false;
     }
 
     bool failfOffset(uint32_t offset, const char* fmt, ...) {
@@ -6781,20 +6785,24 @@ CheckFunctions(ModuleValidator& m, Scope
     for (size_t i = 0; i < numParallelJobs; i++)
         tasks.infallibleAppend(LIFO_ALLOC_PARALLEL_CHUNK_SIZE);
 
     // With compilation memory in-scope, dispatch helper threads.
     ParallelGroupState group(tasks);
     if (!CheckFunctionsParallel(m, group, results)) {
         CancelOutstandingJobs(group);
 
-        // If failure was triggered by a helper thread, report error.
-        if (void* maybeFunc = HelperThreadState().maybeAsmJSFailedFunction()) {
-            AsmFunction* func = reinterpret_cast<AsmFunction*>(maybeFunc);
-            return m.failOffset(func->srcBegin(), "allocation failure during compilation");
+        // If a validation error didn't occur on the main thread, either a
+        // syntax error occurred and will be signalled by the regular parser,
+        // or an error occurred on an helper thread.
+        if (!m.hasAlreadyFailed()) {
+            if (void* maybeFunc = HelperThreadState().maybeAsmJSFailedFunction()) {
+                AsmFunction* func = reinterpret_cast<AsmFunction*>(maybeFunc);
+                return m.failOffset(func->srcBegin(), "allocation failure during compilation");
+            }
         }
 
         // Otherwise, the error occurred on the main thread and was already reported.
         return false;
     }
     return true;
 }
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3760,17 +3760,22 @@ AC_SUBST(WIN32_CONSOLE_EXE_LDFLAGS)
 AC_SUBST(WIN32_GUI_EXE_LDFLAGS)
 
 AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
 
 dnl Set various defines and substitutions
 dnl ========================================================
 
 if test "$OS_ARCH" = "Darwin"; then
-  AC_DEFINE(XP_MACOSX)
+  if test -n "$MOZ_IOS"; then
+    AC_DEFINE(XP_IOS)
+  else
+    AC_DEFINE(XP_MACOSX)
+  fi
+  AC_DEFINE(XP_DARWIN)
   AC_DEFINE(XP_UNIX)
 elif test "$OS_ARCH" != "WINNT"; then
   AC_DEFINE(XP_UNIX)
 fi
 
 if test "$MOZ_DEBUG"; then
     AC_DEFINE(MOZ_REFLOW_PERF)
     AC_DEFINE(MOZ_REFLOW_PERF_DSP)
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -646,16 +646,18 @@ FunctionBox::FunctionBox(ExclusiveContex
                          JSObject* enclosingStaticScope, ParseContext<ParseHandler>* outerpc,
                          Directives directives, bool extraWarnings, GeneratorKind generatorKind)
   : ObjectBox(fun, traceListHead),
     SharedContext(cx, directives, extraWarnings),
     bindings(),
     enclosingStaticScope_(enclosingStaticScope),
     bufStart(0),
     bufEnd(0),
+    startLine(1),
+    startColumn(0),
     length(0),
     generatorKindBits_(GeneratorKindAsBits(generatorKind)),
     inGenexpLambda(false),
     hasDestructuringArgs(false),
     useAsm(false),
     insideUseAsm(outerpc && outerpc->useAsmOrInsideUseAsm()),
     wasEmitted(false),
     usesArguments(false),
@@ -870,17 +872,20 @@ Parser<ParseHandler>::standaloneModule(H
     pn->pn_blockid = modulepc.blockid();
 
     MOZ_ASSERT(pn->isKind(PNK_STATEMENTLIST));
     mn->pn_body = pn;
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
-    MOZ_ASSERT(tt == TOK_EOF);
+    if (tt != TOK_EOF) {
+        report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, "module", TokenKindToDesc(tt));
+        return null();
+    }
 
     if (!FoldConstants(context, &pn, this))
         return null();
 
     Rooted<Bindings> bindings(context, modulebox->bindings);
     if (!modulepc.generateBindings(context, tokenStream, alloc, &bindings))
         return null();
     modulebox->bindings = bindings;
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -108,17 +108,17 @@ js::Nursery::~Nursery()
 
 void
 js::Nursery::updateDecommittedRegion()
 {
 #ifndef JS_GC_ZEAL
     if (numActiveChunks_ < numNurseryChunks_) {
         // Bug 994054: madvise on MacOS is too slow to make this
         //             optimization worthwhile.
-# ifndef XP_MACOSX
+# ifndef XP_DARWIN
         uintptr_t decommitStart = chunk(numActiveChunks_).start();
         uintptr_t decommitSize = heapEnd() - decommitStart;
         MOZ_ASSERT(decommitStart == AlignBytes(decommitStart, Alignment));
         MOZ_ASSERT(decommitSize == AlignBytes(decommitStart, Alignment));
         MarkPagesUnused((void*)decommitStart, decommitSize);
 # endif
     }
 #endif
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1646,17 +1646,17 @@ IsNativeRegExpEnabled(JSContext* cx)
 #else
     return cx->runtime()->options().nativeRegExp();
 #endif
 }
 
 RegExpCode
 irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* data,
                          HandleLinearString sample, bool is_global, bool ignore_case,
-                         bool is_ascii, bool match_only, bool force_bytecode)
+                         bool is_ascii, bool match_only, bool force_bytecode, bool sticky)
 {
     if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
         JS_ReportError(cx, "regexp too big");
         return RegExpCode();
     }
 
     LifoAlloc& alloc = cx->tempLifoAlloc();
     RegExpCompiler compiler(cx, &alloc, data->capture_count, ignore_case, is_ascii, match_only);
@@ -1672,17 +1672,17 @@ irregexp::CompilePattern(JSContext* cx, 
 
     // Wrap the body of the regexp in capture #0.
     RegExpNode* captured_body = RegExpCapture::ToNode(data->tree,
                                                       0,
                                                       &compiler,
                                                       compiler.accept());
     RegExpNode* node = captured_body;
     bool is_end_anchored = data->tree->IsAnchoredAtEnd();
-    bool is_start_anchored = data->tree->IsAnchoredAtStart();
+    bool is_start_anchored = sticky || data->tree->IsAnchoredAtStart();
     int max_length = data->tree->max_match();
     if (!is_start_anchored) {
         // Add a .*? at the beginning, outside the body capture, unless
         // this expression is anchored at the beginning.
         RegExpNode* loop_node =
             RegExpQuantifier::ToNode(0,
                                      RegExpTree::kInfinity,
                                      false,
--- a/js/src/irregexp/RegExpEngine.h
+++ b/js/src/irregexp/RegExpEngine.h
@@ -83,17 +83,17 @@ struct RegExpCode
     void destroy() {
         js_free(byteCode);
     }
 };
 
 RegExpCode
 CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData* data,
                HandleLinearString sample,  bool is_global, bool ignore_case,
-               bool is_ascii, bool match_only, bool force_bytecode);
+               bool is_ascii, bool match_only, bool force_bytecode, bool sticky);
 
 // Note: this may return RegExpRunStatus_Error if an interrupt was requested
 // while the code was executing.
 template <typename CharT>
 RegExpRunStatus
 ExecuteCode(JSContext* cx, jit::JitCode* codeBlock, const CharT* chars, size_t start,
             size_t length, MatchPairs* matches);
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/oom-helper-thread-plus-validation-error.js
@@ -0,0 +1,11 @@
+if (typeof oomAfterAllocations !== 'function' || typeof evaluate !== 'function')
+    quit();
+
+oomAfterAllocations(10, 2);
+evaluate(`function mod(stdlib, ffi, heap) {
+    "use asm";
+    function f3(k) {
+        k = k | 0;
+    }
+    function g3(k) {}
+}`);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1203790.js
@@ -0,0 +1,10 @@
+gczeal(14);
+verifyprebarriers();
+x = [];
+Array.prototype.push.call(x, new Uint8Array());
+Array.prototype.some.call(x, function() {
+    try {
+        y.toString();
+    } catch (e) {}
+});
+Array.prototype.shift.call(x);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1204722.js
@@ -0,0 +1,7 @@
+
+x = [1e81];
+x.map(function() {});
+x.pop();
+x.push([]);
+[].map(function() {});
+eval("[1/0]");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1205870.js
@@ -0,0 +1,16 @@
+
+// Make sure that unboxed arrays can be created with all possible inline
+// capacities for the different sizes.
+var bools = [];
+var ints = [];
+var doubles = [];
+for (var i = 0; i < 150; i++) {
+    bools.push(false);
+    ints.push(0);
+    doubles.push(0.5);
+}
+for (var i = 0; i < 150; i++) {
+    bools = bools.slice(1);
+    ints = ints.slice(1);
+    doubles = doubles.slice(1);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1204726.js
@@ -0,0 +1,14 @@
+
+setJitCompilerOption("ion.warmup.trigger", 1);
+gczeal(4);
+function test() {
+  for (var res = false; !res; res = inIon()) {};
+}
+var g = newGlobal();
+g.parent = this;
+g.eval(`
+  var dbg = new Debugger();
+  var parentw = dbg.addDebuggee(parent);
+  dbg.onIonCompilation = function (graph) {};
+`);
+test();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1191576.js
@@ -0,0 +1,17 @@
+// |jit-test| allow-oom
+
+if (!('gczeal' in this && 'oomAfterAllocations' in this))
+    quit();
+
+var lfcode = new Array();
+gczeal(14);
+loadFile(`
+for each(let e in newGlobal()) {
+    if (oomAfterAllocations(100))
+        continue;
+}
+`);
+function loadFile(lfVarx) {
+    for (lfLocal in this) {}
+    evaluate(lfVarx);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1206677.js
@@ -0,0 +1,14 @@
+load(libdir + 'oomTest.js');
+
+if (helperThreadCount() === 0)
+  quit(0);
+
+var lfGlobal = newGlobal();
+for (lfLocal in this) {
+    if (!(lfLocal in lfGlobal)) {
+        lfGlobal[lfLocal] = this[lfLocal];
+    }
+}
+const script = 'oomTest(() => getBacktrace({args: true, locals: "123795", thisprops: true}));';
+lfGlobal.offThreadCompileScript(script);
+lfGlobal.runOffThreadScript();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1199898.js
@@ -0,0 +1,4 @@
+// |jit-test| error: TypeError
+do {
+  for (var a of [{}]) {}
+} while (4());
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1199952.js
@@ -0,0 +1,23 @@
+var g = newGlobal();
+g.parent = this;
+g.eval(`
+    var dbg = new Debugger();
+    var parentw = dbg.addDebuggee(parent);
+    dbg.onIonCompilation = function (graph) {};
+`);
+gczeal(7,1);
+var findNearestDateBefore = function(start, predicate) {
+    var current = start;
+    var month = 1000 * 60 * 60 * 24 * 30;
+    for (var step = month; step > 0; step = Math.floor(step / 3)) {
+        !predicate(current);
+        current = new Date(current.getTime() + step);
+    }
+};
+var juneDate = new Date(2000, 5, 20, 0, 0, 0, 0);
+var decemberDate = new Date(2000, 11, 20, 0, 0, 0, 0);
+var juneOffset = juneDate.getTimezoneOffset();
+var decemberOffset = decemberDate.getTimezoneOffset();
+var isSouthernHemisphere = (juneOffset > decemberOffset);
+var winterTime = isSouthernHemisphere ? juneDate : decemberDate;
+var dstStart = findNearestDateBefore(winterTime, function (date) {});
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1204165.js
@@ -0,0 +1,10 @@
+var x;
+function f() {
+    x = [];
+    for (var i = 0; i < 1; ++i) {
+        x.push("");
+    }
+    [0].concat(x);
+}
+f();
+f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug1204857.js
@@ -0,0 +1,2 @@
+// |jit-test| error: SyntaxError: unexpected garbage after module
+parseModule(("}"));
--- a/js/src/jit/InstructionReordering.cpp
+++ b/js/src/jit/InstructionReordering.cpp
@@ -90,18 +90,21 @@ jit::ReorderInstructions(MIRGenerator* m
             // and has no cost if the constant is emitted at its use.
             if (ins->isConstant() &&
                 ins->hasOneUse() &&
                 ins->usesBegin()->consumer()->block() == *block &&
                 !IsFloatingPointType(ins->type()))
             {
                 iter++;
                 MInstructionIterator targetIter = block->begin();
-                if (targetIter->isInterruptCheck())
+                while (targetIter->isConstant() || targetIter->isInterruptCheck()) {
+                    if (*targetIter == ins)
+                        break;
                     targetIter++;
+                }
                 MoveBefore(*block, *targetIter, ins);
                 continue;
             }
 
             // Look for inputs where this instruction is the last use of that
             // input. If we move this instruction up, the input's lifetime will
             // be shortened, modulo resume point uses (which don't need to be
             // stored in a register, and can be handled by the register
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -567,17 +567,17 @@ LinkBackgroundCodeGen(JSContext* cx, Ion
     if (!codegen)
         return false;
 
     JitContext jctx(cx, &builder->alloc());
 
     // Root the assembler until the builder is finished below. As it was
     // constructed off thread, the assembler has not been rooted previously,
     // though any GC activity would discard the builder.
-    codegen->masm.constructRoot(cx);
+    MacroAssembler::AutoRooter masm(cx, &codegen->masm);
 
     return LinkCodeGen(cx, builder, codegen, scripts, info);
 }
 
 void
 jit::LazyLink(JSContext* cx, HandleScript calleeScript)
 {
     IonBuilder* builder;
@@ -2226,18 +2226,18 @@ IonCompile(JSContext* cx, JSScript* scri
 
         return AbortReason_NoAbort;
     }
 
     // See PrepareForDebuggerOnIonCompilationHook
     Rooted<ScriptVector> debugScripts(cx, ScriptVector(cx));
     OnIonCompilationInfo debugInfo;
 
-    ScopedJSDeletePtr<CodeGenerator> codegen;
     {
+        ScopedJSDeletePtr<CodeGenerator> codegen;
         AutoEnterAnalysis enter(cx);
         codegen = CompileBackEnd(builder);
         if (!codegen) {
             JitSpew(JitSpew_IonAbort, "Failed during back-end compilation.");
             return AbortReason_Disable;
         }
 
         succeeded = LinkCodeGen(cx, builder, codegen, &debugScripts, &debugInfo);
@@ -2834,19 +2834,21 @@ InvalidateActivation(FreeOp* fop, const 
             MOZ_ASSERT(it.isScripted());
             const char* type = "Unknown";
             if (it.isIonJS())
                 type = "Optimized";
             else if (it.isBaselineJS())
                 type = "Baseline";
             else if (it.isBailoutJS())
                 type = "Bailing";
-            JitSpew(JitSpew_IonInvalidate, "#%d %s JS frame @ %p, %s:%" PRIuSIZE " (fun: %p, script: %p, pc %p)",
-                    frameno, type, it.fp(), it.script()->filename(), it.script()->lineno(),
-                    it.maybeCallee(), (JSScript*)it.script(), it.returnAddressToFp());
+            JitSpew(JitSpew_IonInvalidate,
+                    "#%d %s JS frame @ %p, %s:%" PRIuSIZE " (fun: %p, script: %p, pc %p)",
+                    frameno, type, it.fp(), it.script()->maybeForwardedFilename(),
+                    it.script()->lineno(), it.maybeCallee(), (JSScript*)it.script(),
+                    it.returnAddressToFp());
             break;
           }
           case JitFrame_IonStub:
             JitSpew(JitSpew_IonInvalidate, "#%d ion stub frame @ %p", frameno, it.fp());
             break;
           case JitFrame_BaselineStub:
             JitSpew(JitSpew_IonInvalidate, "#%d baseline stub frame @ %p", frameno, it.fp());
             break;
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1039,29 +1039,37 @@ ReadAllocation(const JitFrameIterator& f
         Register reg = a->toGeneralReg()->reg();
         return frame.machineState().read(reg);
     }
     return *frame.jsFrame()->slotRef(SafepointSlotEntry(a));
 }
 #endif
 
 static void
-MarkThisAndArguments(JSTracer* trc, JitFrameLayout* layout)
+MarkThisAndArguments(JSTracer* trc, const JitFrameIterator& frame)
 {
     // Mark |this| and any extra actual arguments for an Ion frame. Marking of
     // formal arguments is taken care of by the frame's safepoint/snapshot,
     // except when the script might have lazy arguments, in which case we mark
-    // them as well.
+    // them as well. We also have to mark formals if we have a LazyLink frame.
+
+    JitFrameLayout* layout = frame.isExitFrameLayout<LazyLinkExitFrameLayout>()
+                             ? frame.exitFrame()->as<LazyLinkExitFrameLayout>()->jsFrame()
+                             : frame.jsFrame();
 
     size_t nargs = layout->numActualArgs();
     size_t nformals = 0;
     size_t newTargetOffset = 0;
     if (CalleeTokenIsFunction(layout->calleeToken())) {
         JSFunction* fun = CalleeTokenToFunction(layout->calleeToken());
-        nformals = fun->nonLazyScript()->argumentsHasVarBinding() ? 0 : fun->nargs();
+        if (!frame.isExitFrameLayout<LazyLinkExitFrameLayout>() &&
+            !fun->nonLazyScript()->argumentsHasVarBinding())
+        {
+            nformals = fun->nargs();
+        }
         newTargetOffset = Max(nargs, fun->nargs());
     }
 
     Value* argv = layout->argv();
 
     // Trace |this|.
     TraceRoot(trc, argv, "ion-thisv");
 
@@ -1070,23 +1078,16 @@ MarkThisAndArguments(JSTracer* trc, JitF
         TraceRoot(trc, &argv[i], "ion-argv");
 
     // Always mark the new.target from the frame. It's not in the snapshots.
     // +1 to pass |this|
     if (CalleeTokenIsConstructing(layout->calleeToken()))
         TraceRoot(trc, &argv[1 + newTargetOffset], "ion-newTarget");
 }
 
-static void
-MarkThisAndArguments(JSTracer* trc, const JitFrameIterator& frame)
-{
-    JitFrameLayout* layout = frame.jsFrame();
-    MarkThisAndArguments(trc, layout);
-}
-
 #ifdef JS_NUNBOX32
 static inline void
 WriteAllocation(const JitFrameIterator& frame, const LAllocation* a, uintptr_t value)
 {
     if (a->isGeneralReg()) {
         Register reg = a->toGeneralReg()->reg();
         frame.machineState().write(reg, value);
     } else {
@@ -1420,17 +1421,17 @@ MarkJitExitFrame(JSTracer* trc, const Ji
     }
 
     if (frame.isExitFrameLayout<LazyLinkExitFrameLayout>()) {
         LazyLinkExitFrameLayout* ll = frame.exitFrame()->as<LazyLinkExitFrameLayout>();
         JitFrameLayout* layout = ll->jsFrame();
 
         TraceRoot(trc, ll->stubCode(), "lazy-link-code");
         layout->replaceCalleeToken(MarkCalleeToken(trc, layout->calleeToken()));
-        MarkThisAndArguments(trc, layout);
+        MarkThisAndArguments(trc, frame);
         return;
     }
 
     if (frame.isBareExit()) {
         // Nothing to mark. Fake exit frame pushed for VM functions with
         // nothing to mark on the stack.
         return;
     }
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -107,17 +107,17 @@ JitOptions::JitOptions()
     // Toggle whether eager scalar replacement is globally disabled.
     SET_DEFAULT(disableScalarReplacement, false);
 
     // Toggles whether shared stubs are used in Ionmonkey.
     SET_DEFAULT(disableSharedStubs, true);
 
     // Toggles whether sincos optimization is globally disabled.
     // See bug984018: The MacOS is the only one that has the sincos fast.
-    #if defined(XP_MACOSX)
+    #if defined(XP_DARWIN)
         SET_DEFAULT(disableSincos, false);
     #else
         SET_DEFAULT(disableSincos, true);
     #endif
 
     // Toggles whether sink code motion is globally disabled.
     SET_DEFAULT(disableSink, true);
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -1012,22 +1012,16 @@ js::ContextHasOutstandingRequests(const 
 
 JS_FRIEND_API(void)
 js::SetActivityCallback(JSRuntime* rt, ActivityCallback cb, void* arg)
 {
     rt->activityCallback = cb;
     rt->activityCallbackArg = arg;
 }
 
-JS_FRIEND_API(bool)
-js::IsContextRunningJS(JSContext* cx)
-{
-    return cx->currentlyRunning();
-}
-
 JS_FRIEND_API(void)
 JS::NotifyDidPaint(JSRuntime* rt)
 {
     rt->gc.notifyDidPaint();
 }
 
 JS_FRIEND_API(void)
 JS::PokeGC(JSRuntime* rt)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -1081,19 +1081,16 @@ typedef void
  * idle and a request begins.
  */
 JS_FRIEND_API(void)
 SetActivityCallback(JSRuntime* rt, ActivityCallback cb, void* arg);
 
 extern JS_FRIEND_API(const JSStructuredCloneCallbacks*)
 GetContextStructuredCloneCallbacks(JSContext* cx);
 
-extern JS_FRIEND_API(bool)
-IsContextRunningJS(JSContext* cx);
-
 typedef bool
 (* DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass,
                                     uint32_t protoID, uint32_t depth);
 struct JSDOMCallbacks {
     DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto;
 };
 typedef struct JSDOMCallbacks DOMCallbacks;
 
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -35,17 +35,17 @@
 #include "jstypes.h"
 
 #include "jit/InlinableNatives.h"
 #include "js/Class.h"
 #include "vm/Time.h"
 
 #include "jsobjinlines.h"
 
-#if defined(ANDROID) || defined(XP_MACOSX) || defined(__DragonFly__) || \
+#if defined(ANDROID) || defined(XP_DARWIN) || defined(__DragonFly__) || \
     defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
 # include <stdlib.h>
 # define HAVE_ARC4RANDOM
 #endif
 
 using namespace js;
 
 using mozilla::Abs;
--- a/js/src/jsnativestack.cpp
+++ b/js/src/jsnativestack.cpp
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsnativestack.h"
 
 #ifdef XP_WIN
 # include "jswin.h"
 
-#elif defined(XP_MACOSX) || defined(DARWIN) || defined(XP_UNIX)
+#elif defined(XP_DARWIN) || defined(DARWIN) || defined(XP_UNIX)
 # include <pthread.h>
 
 # if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
 #  include <pthread_np.h>
 # endif
 
 # if defined(ANDROID)
 #  include <sys/types.h>
@@ -89,17 +89,17 @@ js::GetNativeStackBaseImpl()
 }
 
 #else /* XP_UNIX */
 
 void*
 js::GetNativeStackBaseImpl()
 {
     pthread_t thread = pthread_self();
-# if defined(XP_MACOSX) || defined(DARWIN)
+# if defined(XP_DARWIN) || defined(DARWIN)
     return pthread_get_stackaddr_np(thread);
 
 # else
     pthread_attr_t sattr;
     pthread_attr_init(&sattr);
 #  if defined(__OpenBSD__)
     stack_t ss;
 #  elif defined(PTHREAD_NP_H) || defined(_PTHREAD_NP_H_) || defined(NETBSD)
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1160,17 +1160,17 @@ FirstCharMatcher8bit(const char* text, u
 #else
     return reinterpret_cast<const char*>(memchr(text, pat, n));
 #endif
 }
 
 static const char16_t*
 FirstCharMatcher16bit(const char16_t* text, uint32_t n, const char16_t pat)
 {
-#if defined(XP_MACOSX) || defined(XP_WIN)
+#if defined(XP_DARWIN) || defined(XP_WIN)
     /*
      * Performance of memchr is horrible in OSX. Windows is better,
      * but it is still better to use UnrolledMatcher.
      */
     return FirstCharMatcherUnrolled<char16_t, char16_t>(text, n, pat);
 #else
     /*
      * For linux the best performance is obtained by slightly hacking memchr.
@@ -1734,18 +1734,18 @@ js::str_lastIndexOf(JSContext* cx, unsig
         else
             res = LastIndexOfImpl(textChars, textLen, pat->twoByteChars(nogc), patLen, start);
     }
 
     args.rval().setInt32(res);
     return true;
 }
 
-static bool
-HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
+bool
+js::HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
 {
     MOZ_ASSERT(start + pat->length() <= text->length());
 
     size_t patLen = pat->length();
 
     AutoCheckCannotGC nogc;
     if (text->hasLatin1Chars()) {
         const Latin1Char* textChars = text->latin1Chars(nogc) + start;
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -214,16 +214,20 @@ StringEqualsAscii(JSLinearString* str, c
 
 /* Return true if the string contains a pattern anywhere inside it. */
 extern bool
 StringHasPattern(JSLinearString* text, const char16_t* pat, uint32_t patlen);
 
 extern int
 StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start);
 
+/* Return true if the string contains a pattern at |start|. */
+extern bool
+HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start);
+
 template <typename CharT>
 extern bool
 HasRegExpMetaChars(const CharT* chars, size_t length);
 
 extern bool
 StringHasRegExpMetaChars(JSLinearString* str);
 
 template <typename Char1, typename Char2>
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/RegExp/sticky.js
@@ -0,0 +1,126 @@
+var BUGNUMBER = 773687;
+var summary = 'sticky flag should not break assertion behavior.';
+
+print(BUGNUMBER + ": " + summary);
+
+function test(re, text, expectations) {
+  // Sanity check for test data itself.
+  assertEq(expectations.length, text.length + 1);
+
+  for (var i = 0; i < expectations.length; i++) {
+    var result = expectations[i];
+
+    re.lastIndex = i;
+    var match = re.exec(text);
+    if (result === null) {
+      assertEq(re.lastIndex, 0);
+      assertEq(match, null);
+    } else {
+      assertEq(re.lastIndex, result.lastIndex);
+      assertEq(match !== null, true);
+      assertEq(match.length, result.matches.length);
+      for (var j = 0; j < result.matches.length; j++)
+        assertEq(match[j], result.matches[j]);
+      assertEq(match.index, result.index);
+    }
+  }
+}
+
+// simple text
+test(/bc/y, "abcabd", [
+  null,
+  { lastIndex: 3, matches: ["bc"], index: 1 },
+  null,
+  null,
+  null,
+  null,
+  null,
+]);
+
+// complex pattern
+test(/bc|c|d/y, "abcabd", [
+  null,
+  { lastIndex: 3, matches: ["bc"], index: 1 },
+  { lastIndex: 3, matches: ["c"], index: 2 },
+  null,
+  null,
+  { lastIndex: 6, matches: ["d"], index: 5 },
+  null,
+]);
+
+test(/.*(bc|c|d)/y, "abcabd", [
+  { lastIndex: 6, matches: ["abcabd", "d"], index: 0 },
+  { lastIndex: 6, matches: ["bcabd", "d"], index: 1 },
+  { lastIndex: 6, matches: ["cabd", "d"], index: 2 },
+  { lastIndex: 6, matches: ["abd", "d"], index: 3 },
+  { lastIndex: 6, matches: ["bd", "d"], index: 4 },
+  { lastIndex: 6, matches: ["d", "d"], index: 5 },
+  null,
+]);
+
+test(/.*?(bc|c|d)/y, "abcabd", [
+  { lastIndex: 3, matches: ["abc", "bc"], index: 0 },
+  { lastIndex: 3, matches: ["bc", "bc"], index: 1 },
+  { lastIndex: 3, matches: ["c", "c"], index: 2 },
+  { lastIndex: 6, matches: ["abd", "d"], index: 3 },
+  { lastIndex: 6, matches: ["bd", "d"], index: 4 },
+  { lastIndex: 6, matches: ["d", "d"], index: 5 },
+  null,
+]);
+
+test(/(bc|.*c|d)/y, "abcabd", [
+  { lastIndex: 3, matches: ["abc", "abc"], index: 0 },
+  { lastIndex: 3, matches: ["bc", "bc"], index: 1 },
+  { lastIndex: 3, matches: ["c", "c"], index: 2 },
+  null,
+  null,
+  { lastIndex: 6, matches: ["d", "d"], index: 5 },
+  null,
+]);
+
+// ^ assertions
+test(/^/y, "abcabc", [
+  { lastIndex: 0, matches: [""], index: 0 },
+  null,
+  null,
+  null,
+  null,
+  null,
+  null,
+]);
+
+test(/^a/my, "abc\nabc", [
+  { lastIndex: 1, matches: ["a"], index: 0 },
+  null,
+  null,
+  null,
+  { lastIndex: 5, matches: ["a"], index: 4 },
+  null,
+  null,
+  null,
+]);
+
+// \b assertions
+test(/\b/y, "abc bc", [
+  { lastIndex: 0, matches: [""], index: 0 },
+  null,
+  null,
+  { lastIndex: 3, matches: [""], index: 3 },
+  { lastIndex: 4, matches: [""], index: 4 },
+  null,
+  { lastIndex: 6, matches: [""], index: 6 },
+]);
+
+// \B assertions
+test(/\B/y, "abc bc", [
+  null,
+  { lastIndex: 1, matches: [""], index: 1 },
+  { lastIndex: 2, matches: [""], index: 2 },
+  null,
+  null,
+  { lastIndex: 5, matches: [""], index: 5 },
+  null,
+]);
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
--- a/js/src/vm/MatchPairs.h
+++ b/js/src/vm/MatchPairs.h
@@ -74,17 +74,16 @@ class MatchPairs
     friend class RegExpStatics;
 
     /* MatchPair buffer allocator: set pairs_ and pairCount_. */
     virtual bool allocOrExpandArray(size_t pairCount) = 0;
 
     bool initArrayFrom(MatchPairs& copyFrom);
     void forgetArray() { pairs_ = nullptr; }
 
-    void displace(size_t disp);
     void checkAgainst(size_t inputLength) {
 #ifdef DEBUG
         for (size_t i = 0; i < pairCount_; i++) {
             const MatchPair& p = (*this)[i];
             MOZ_ASSERT(p.check());
             if (p.isUndefined())
                 continue;
             MOZ_ASSERT(size_t(p.limit) <= inputLength);
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -862,18 +862,50 @@ ObjectGroup::newArrayObject(ExclusiveCon
                 return nullptr;
             group->setPreliminaryObjects(preliminaryObjects);
         }
 
         if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group))
             return nullptr;
     }
 
-    return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind,
-                                     ShouldUpdateTypes::DontUpdate);
+    // The type of the elements being added will already be reflected in type
+    // information, but make sure when creating an unboxed array that the
+    // common element type is suitable for the unboxed representation.
+    ShouldUpdateTypes updateTypes = ShouldUpdateTypes::DontUpdate;
+    if (group->maybePreliminaryObjects())
+        group->maybePreliminaryObjects()->maybeAnalyze(cx, group);
+    if (group->maybeUnboxedLayout()) {
+        switch (group->unboxedLayout().elementType()) {
+          case JSVAL_TYPE_BOOLEAN:
+            if (elementType != TypeSet::BooleanType())
+                updateTypes = ShouldUpdateTypes::Update;
+            break;
+          case JSVAL_TYPE_INT32:
+            if (elementType != TypeSet::Int32Type())
+                updateTypes = ShouldUpdateTypes::Update;
+            break;
+          case JSVAL_TYPE_DOUBLE:
+            if (elementType != TypeSet::Int32Type() && elementType != TypeSet::DoubleType())
+                updateTypes = ShouldUpdateTypes::Update;
+            break;
+          case JSVAL_TYPE_STRING:
+            if (elementType != TypeSet::StringType())
+                updateTypes = ShouldUpdateTypes::Update;
+            break;
+          case JSVAL_TYPE_OBJECT:
+            if (elementType != TypeSet::NullType() && !elementType.get().isObjectUnchecked())
+                updateTypes = ShouldUpdateTypes::Update;
+            break;
+          default:
+            MOZ_CRASH();
+        }
+    }
+
+    return NewCopiedArrayTryUseGroup(cx, group, vp, length, newKind, updateTypes);
 }
 
 // Try to change the group of |source| to match that of |target|.
 static bool
 GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target)
 {
     MOZ_ASSERT(source->group() != target->group());
 
--- a/js/src/vm/PosixNSPR.cpp
+++ b/js/src/vm/PosixNSPR.cpp
@@ -143,17 +143,17 @@ PR_GetCurrentThread()
 
     return (PRThread*)pthread_getspecific(gSelfThreadIndex);
 }
 
 PRStatus
 PR_SetCurrentThreadName(const char* name)
 {
     int result;
-#ifdef XP_MACOSX
+#ifdef XP_DARWIN
     result = pthread_setname_np(name);
 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
     pthread_set_name_np(pthread_self(), name);
     result = 0;
 #elif defined(__NetBSD__)
     result = pthread_setname_np(pthread_self(), "%s", (void*)name);
 #else
     result = pthread_setname_np(pthread_self(), name);
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -142,29 +142,16 @@ MatchPairs::initArrayFrom(MatchPairs& co
     if (!allocOrExpandArray(copyFrom.pairCount()))
         return false;
 
     PodCopy(pairs_, copyFrom.pairs_, pairCount_);
 
     return true;
 }
 
-void
-MatchPairs::displace(size_t disp)
-{
-    if (disp == 0)
-        return;
-
-    for (size_t i = 0; i < pairCount_; i++) {
-        MOZ_ASSERT(pairs_[i].check());
-        pairs_[i].start += (pairs_[i].start < 0) ? 0 : disp;
-        pairs_[i].limit += (pairs_[i].limit < 0) ? 0 : disp;
-    }
-}
-
 bool
 ScopedMatchPairs::allocOrExpandArray(size_t pairCount)
 {
     /* Array expansion is forbidden, but array reuse is acceptable. */
     if (pairCount_) {
         MOZ_ASSERT(pairs_);
         MOZ_ASSERT(pairCount_ == pairCount);
         return true;
@@ -575,42 +562,18 @@ RegExpShared::trace(JSTracer* trc)
 
 bool
 RegExpShared::compile(JSContext* cx, HandleLinearString input,
                       CompilationMode mode, ForceByteCodeEnum force)
 {
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
     AutoTraceLog logCompile(logger, TraceLogger_IrregexpCompile);
 
-    if (!sticky()) {
-        RootedAtom pattern(cx, source);
-        return compile(cx, pattern, input, mode, force);
-    }
-
-    /*
-     * The sticky case we implement hackily by prepending a caret onto the front
-     * and relying on |::execute| to pseudo-slice the string when it sees a sticky regexp.
-     */
-    static const char prefix[] = {'^', '(', '?', ':'};
-    static const char postfix[] = {')'};
-
-    using mozilla::ArrayLength;
-    StringBuffer sb(cx);
-    if (!sb.reserve(ArrayLength(prefix) + source->length() + ArrayLength(postfix)))
-        return false;
-    sb.infallibleAppend(prefix, ArrayLength(prefix));
-    if (!sb.append(source))
-        return false;
-    sb.infallibleAppend(postfix, ArrayLength(postfix));
-
-    RootedAtom fakeySource(cx, sb.finishAtom());
-    if (!fakeySource)
-        return false;
-
-    return compile(cx, fakeySource, input, mode, force);
+    RootedAtom pattern(cx, source);
+    return compile(cx, pattern, input, mode, force);
 }
 
 bool
 RegExpShared::compile(JSContext* cx, HandleAtom pattern, HandleLinearString input,
                       CompilationMode mode, ForceByteCodeEnum force)
 {
     if (!ignoreCase() && !StringHasRegExpMetaChars(pattern))
         canStringMatch = true;
@@ -630,17 +593,18 @@ RegExpShared::compile(JSContext* cx, Han
 
     this->parenCount = data.capture_count;
 
     irregexp::RegExpCode code = irregexp::CompilePattern(cx, this, &data, input,
                                                          false /* global() */,
                                                          ignoreCase(),
                                                          input->hasLatin1Chars(),
                                                          mode == MatchOnly,
-                                                         force == ForceByteCode);
+                                                         force == ForceByteCode,
+                                                         sticky());
     if (code.empty())
         return false;
 
     MOZ_ASSERT(!code.jitCode || !code.byteCode);
     MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode);
 
     RegExpCompilation& compilation = this->compilation(mode, input->hasLatin1Chars());
     if (code.jitCode)
@@ -676,64 +640,67 @@ RegExpShared::execute(JSContext* cx, Han
      * Ensure sufficient memory for output vector.
      * No need to initialize it. The RegExp engine fills them in on a match.
      */
     if (matches && !matches->allocOrExpandArray(pairCount())) {
         ReportOutOfMemory(cx);
         return RegExpRunStatus_Error;
     }
 
-    /*
-     * |displacement| emulates sticky mode by matching from this offset
-     * into the char buffer and subtracting the delta off at the end.
-     */
-    size_t charsOffset = 0;
     size_t length = input->length();
-    size_t origLength = length;
-    size_t displacement = 0;
-
-    if (sticky()) {
-        displacement = start;
-        charsOffset += displacement;
-        length -= displacement;
-        start = 0;
-    }
 
     // Reset the Irregexp backtrack stack if it grows during execution.
     irregexp::RegExpStackScope stackScope(cx->runtime());
 
     if (canStringMatch) {
         MOZ_ASSERT(pairCount() == 1);
-        int res = StringFindPattern(input, source, start + charsOffset);
+        size_t sourceLength = source->length();
+        if (sticky()) {
+            // First part checks size_t overflow.
+            if (sourceLength + start < sourceLength || sourceLength + start > length)
+                return RegExpRunStatus_Success_NotFound;
+            if (!HasSubstringAt(input, source, start))
+                return RegExpRunStatus_Success_NotFound;
+
+            if (matches) {
+                (*matches)[0].start = start;
+                (*matches)[0].limit = start + sourceLength;
+
+                matches->checkAgainst(length);
+            }
+            return RegExpRunStatus_Success;
+        }
+
+        int res = StringFindPattern(input, source, start);
         if (res == -1)
             return RegExpRunStatus_Success_NotFound;
 
         if (matches) {
             (*matches)[0].start = res;
-            (*matches)[0].limit = res + source->length();
+            (*matches)[0].limit = res + sourceLength;
 
-            matches->checkAgainst(origLength);
+            matches->checkAgainst(length);
         }
         return RegExpRunStatus_Success;
     }
 
     do {
         jit::JitCode* code = compilation(mode, input->hasLatin1Chars()).jitCode;
         if (!code)
             break;
 
         RegExpRunStatus result;
         {
             AutoTraceLog logJIT(logger, TraceLogger_IrregexpExecute);
             AutoCheckCannotGC nogc;
             if (input->hasLatin1Chars()) {
-                const Latin1Char* chars = input->latin1Chars(nogc) + charsOffset;
+                const Latin1Char* chars = input->latin1Chars(nogc);
                 result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
             } else {
-                const char16_t* chars = input->twoByteChars(nogc) + charsOffset;
+                const char16_t* chars = input->twoByteChars(nogc);
                 result = irregexp::ExecuteCode(cx, code, chars, start, length, matches);
             }
         }
 
         if (result == RegExpRunStatus_Error) {
             // An 'Error' result is returned if a stack overflow guard or
             // interrupt guard failed. If CheckOverRecursed doesn't throw, break
             // out and retry the regexp in the bytecode interpreter, which can
@@ -744,47 +711,43 @@ RegExpShared::execute(JSContext* cx, Han
             break;
         }
 
         if (result == RegExpRunStatus_Success_NotFound)
             return RegExpRunStatus_Success_NotFound;
 
         MOZ_ASSERT(result == RegExpRunStatus_Success);
 
-        if (matches) {
-            matches->displace(displacement);
-            matches->checkAgainst(origLength);
-        }
+        if (matches)
+            matches->checkAgainst(length);
         return RegExpRunStatus_Success;
     } while (false);
 
     // Compile bytecode for the RegExp if necessary.
     if (!compileIfNecessary(cx, input, mode, ForceByteCode))
         return RegExpRunStatus_Error;
 
     uint8_t* byteCode = compilation(mode, input->hasLatin1Chars()).byteCode;
     AutoTraceLog logInterpreter(logger, TraceLogger_IrregexpExecute);
 
     AutoStableStringChars inputChars(cx);
     if (!inputChars.init(cx, input))
         return RegExpRunStatus_Error;
 
     RegExpRunStatus result;
     if (inputChars.isLatin1()) {
-        const Latin1Char* chars = inputChars.latin1Range().start().get() + charsOffset;
+        const Latin1Char* chars = inputChars.latin1Range().start().get();
         result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
     } else {
-        const char16_t* chars = inputChars.twoByteRange().start().get() + charsOffset;
+        const char16_t* chars = inputChars.twoByteRange().start().get();
         result = irregexp::InterpretCode(cx, byteCode, chars, start, length, matches);
     }
 
-    if (result == RegExpRunStatus_Success && matches) {
-        matches->displace(displacement);
-        matches->checkAgainst(origLength);
-    }
+    if (result == RegExpRunStatus_Success && matches)
+        matches->checkAgainst(length);
     return result;
 }
 
 size_t
 RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
 {
     size_t n = mallocSizeOf(this);
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -7,24 +7,24 @@
 #include "vm/Runtime-inl.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ThreadLocal.h"
 
-#if defined(XP_MACOSX)
+#if defined(XP_DARWIN)
 #include <mach/mach.h>
 #elif defined(XP_UNIX)
 #include <sys/resource.h>
 #elif defined(XP_WIN)
 #include <processthreadsapi.h>
 #include <windows.h>
-#endif // defined(XP_MACOSX) || defined(XP_UNIX) || defined(XP_WIN)
+#endif // defined(XP_DARWIN) || defined(XP_UNIX) || defined(XP_WIN)
 
 #include <locale.h>
 #include <string.h>
 
 #ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
 # include <sys/mman.h>
 #endif
 
@@ -1104,17 +1104,17 @@ JSRuntime::Stopwatch::transferDeltas(uin
 // but on some platforms we need to fall back to per-process.
 // Data is not guaranteed to be monotonic.
 bool
 JSRuntime::Stopwatch::getResources(uint64_t* userTime,
                                    uint64_t* systemTime) const {
     MOZ_ASSERT(userTime);
     MOZ_ASSERT(systemTime);
 
-#if defined(XP_MACOSX)
+#if defined(XP_DARWIN)
     // On MacOS X, to get we per-thread data, we need to
     // reach into the kernel.
 
     mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
     thread_basic_info_data_t info;
     mach_port_t port = mach_thread_self();
     kern_return_t err =
         thread_info(/* [in] targeted thread*/ port,
@@ -1171,17 +1171,17 @@ JSRuntime::Stopwatch::getResources(uint6
     *systemTime = kernelTimeInt.QuadPart / 10;
 
     ULARGE_INTEGER userTimeInt;
     userTimeInt.LowPart = userFileTime.dwLowDateTime;
     userTimeInt.HighPart = userFileTime.dwHighDateTime;
     // Convert 100 ns to 1 us.
     *userTime = userTimeInt.QuadPart / 10;
 
-#endif // defined(XP_MACOSX) || defined(XP_UNIX) || defined(XP_WIN)
+#endif // defined(XP_DARWIN) || defined(XP_UNIX) || defined(XP_WIN)
 
     return true;
 }
 
 
 bool
 js::SetStopwatchIsMonitoringJank(JSRuntime* rt, bool value)
 {
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -18,17 +18,17 @@
 #include "mozilla/Vector.h"
 
 #include <setjmp.h>
 
 #include "jsatom.h"
 #include "jsclist.h"
 #include "jsscript.h"
 
-#ifdef XP_MACOSX
+#ifdef XP_DARWIN
 # include "asmjs/AsmJSSignalHandlers.h"
 #endif
 #include "builtin/AtomicsObject.h"
 #include "ds/FixedSizeHash.h"
 #include "frontend/ParseMaps.h"
 #include "gc/GCRuntime.h"
 #include "gc/Tracer.h"
 #include "irregexp/RegExpStack.h"
@@ -1114,17 +1114,17 @@ struct JSRuntime : public JS::shadow::Ru
      * Head of circular list of all enabled Debuggers that have
      * onNewGlobalObject handler methods established.
      */
     JSCList             onNewGlobalObjectWatchers;
 
     /* Client opaque pointers */
     void*               data;
 
-#if defined(XP_MACOSX) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+#if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
     js::AsmJSMachExceptionHandler asmJSMachExceptionHandler;
 #endif
 
   private:
     // Whether EnsureSignalHandlersInstalled succeeded in installing all the
     // relevant handlers for this platform.
     bool signalHandlersInstalled_;
 
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -1133,18 +1133,21 @@ namespace js {
 template <AllowGC allowGC, typename CharT>
 JSFlatString*
 NewStringCopyNDontDeflate(ExclusiveContext* cx, const CharT* s, size_t n)
 {
     if (JSInlineString::lengthFits<CharT>(n))
         return NewInlineString<allowGC>(cx, mozilla::Range<const CharT>(s, n));
 
     ScopedJSFreePtr<CharT> news(cx->pod_malloc<CharT>(n + 1));
-    if (!news)
+    if (!news) {
+        if (!allowGC)
+            cx->recoverFromOutOfMemory();
         return nullptr;
+    }
 
     PodCopy(news.get(), s, n);
     news[n] = 0;
 
     JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
     if (!str)
         return nullptr;
 
--- a/js/src/vm/UnboxedObject-inl.h
+++ b/js/src/vm/UnboxedObject-inl.h
@@ -187,16 +187,38 @@ UnboxedArrayObject::setLength(ExclusiveC
     if (length > INT32_MAX) {
         // Track objects with overflowing lengths in type information.
         MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
     }
 
     length_ = length;
 }
 
+inline void
+UnboxedArrayObject::setInitializedLength(uint32_t initlen)
+{
+    MOZ_ASSERT(initlen <= InitializedLengthMask);
+    if (initlen < initializedLength()) {
+        switch (elementType()) {
+          case JSVAL_TYPE_STRING:
+            for (size_t i = initlen; i < initializedLength(); i++)
+                triggerPreBarrier<JSVAL_TYPE_STRING>(i);
+            break;
+          case JSVAL_TYPE_OBJECT:
+            for (size_t i = initlen; i < initializedLength(); i++)
+                triggerPreBarrier<JSVAL_TYPE_OBJECT>(i);
+            break;
+          default:
+            MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType()));
+        }
+    }
+    capacityIndexAndInitializedLength_ =
+        (capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
+}
+
 template <JSValueType Type>
 inline bool
 UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
 {
     MOZ_ASSERT(index < initializedLength());
     MOZ_ASSERT(Type == elementType());
     uint8_t* p = elements() + index * UnboxedTypeSize(Type);
     return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
@@ -566,17 +588,17 @@ MoveBoxedOrUnboxedDenseElements(JSContex
 template <JSValueType DstType, JSValueType SrcType>
 static inline DenseElementResult
 CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
                                 uint32_t dstStart, uint32_t srcStart, uint32_t length)
 {
     MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src));
     MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst));
     MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart);
-    MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(src) >= srcStart + length);
+    MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length);
     MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length);
 
     SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length);
 
     if (DstType == JSVAL_TYPE_MAGIC) {
         if (SrcType == JSVAL_TYPE_MAGIC) {
             const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
             dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
--- a/js/src/vm/UnboxedObject.cpp
+++ b/js/src/vm/UnboxedObject.cpp
@@ -1240,52 +1240,70 @@ UnboxedArrayObject::objectMovedDuringMin
 
     return ndst->hasInlineElements() ? 0 : nbytes;
 }
 
 // Possible capacities for unboxed arrays. Some of these capacities might seem
 // a little weird, but were chosen to allow the inline data of objects of each
 // size to be fully utilized for arrays of the various types on both 32 bit and
 // 64 bit platforms.
+//
+// To find the possible inline capacities, the following script was used:
+//
+// var fixedSlotCapacities = [0, 2, 4, 8, 12, 16];
+// var dataSizes = [1, 4, 8];
+// var header32 = 4 * 2 + 4 * 2;
+// var header64 = 8 * 2 + 4 * 2;
+//
+// for (var i = 0; i < fixedSlotCapacities.length; i++) {
+//    var nfixed = fixedSlotCapacities[i];
+//    var size32 = 4 * 4 + 8 * nfixed - header32;
+//    var size64 = 8 * 4 + 8 * nfixed - header64;
+//    for (var j = 0; j < dataSizes.length; j++) {
+//        print(size32 / dataSizes[j]);
+//        print(size64 / dataSizes[j]);
+//    }
+// }
+//
 /* static */ const uint32_t
 UnboxedArrayObject::CapacityArray[] = {
     UINT32_MAX, // For CapacityMatchesLengthIndex.
-    0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 16, 17, 18, 20, 24, 26, 32, 34, 36, 40, 48, 52, 64, 68,
-    72, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
+    0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 16, 17, 18, 24, 26, 32, 34, 40, 64, 72, 96, 104, 128, 136,
+    256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
     1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608, 9437184, 11534336,
     13631488, 15728640, 17825792, 20971520, 24117248, 27262976, 31457280, 35651584, 40894464,
     46137344, 52428800, 59768832, MaximumCapacity
 };
 
 static const uint32_t
 Pow2CapacityIndexes[] = {
-    1,  // 1
-    2,  // 2
-    4,  // 4
+    2,  // 1
+    3,  // 2
+    5,  // 4
     8,  // 8
     13, // 16
-    19, // 32
-    25, // 64
-    28, // 128
-    29, // 256
-    30, // 512
-    31, // 1024
-    32, // 2048
-    33, // 4096
-    34, // 8192
-    35, // 16384
-    36, // 32768
-    37, // 65536
-    38, // 131072
-    39, // 262144
-    40, // 524288
-    41  // 1048576
+    18, // 32
+    21, // 64
+    25, // 128
+    27, // 256
+    28, // 512
+    29, // 1024
+    30, // 2048
+    31, // 4096
+    32, // 8192
+    33, // 16384
+    34, // 32768
+    35, // 65536
+    36, // 131072
+    37, // 262144
+    38, // 524288
+    39  // 1048576
 };
 
-static const uint32_t MebiCapacityIndex = 41;
+static const uint32_t MebiCapacityIndex = 39;
 
 /* static */ uint32_t
 UnboxedArrayObject::chooseCapacityIndex(uint32_t capacity, uint32_t length)
 {
     // Note: the structure and behavior of this method follow along with
     // NativeObject::goodAllocated. Changes to the allocation strategy in one
     // should generally be matched by the other.
 
--- a/js/src/vm/UnboxedObject.h
+++ b/js/src/vm/UnboxedObject.h
@@ -492,22 +492,17 @@ class UnboxedArrayObject : public JSObje
     }
 
     void setLengthInt32(uint32_t length) {
         MOZ_ASSERT(length <= INT32_MAX);
         length_ = length;
     }
 
     inline void setLength(ExclusiveContext* cx, uint32_t len);
-
-    void setInitializedLength(uint32_t initlen) {
-        MOZ_ASSERT(initlen <= InitializedLengthMask);
-        capacityIndexAndInitializedLength_ =
-            (capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
-    }
+    inline void setInitializedLength(uint32_t initlen);
 
   private:
     void setInlineElements() {
         elements_ = &inlineElements_[0];
     }
 
     void setCapacityIndex(uint32_t index) {
         MOZ_ASSERT(index <= (CapacityMask >> CapacityShift));
--- a/js/xpconnect/src/ExportHelpers.cpp
+++ b/js/xpconnect/src/ExportHelpers.cpp
@@ -4,21 +4,21 @@
  * 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 "xpcprivate.h"
 #include "WrapperFactory.h"
 #include "AccessCheck.h"
 #include "jsfriendapi.h"
 #include "jswrapper.h"
-#include "js/StructuredClone.h"
 #include "js/Proxy.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/File.h"
+#include "mozilla/dom/StructuredCloneHelper.h"
 #ifdef MOZ_NFC
 #include "mozilla/dom/MozNDEFRecord.h"
 #endif
 #include "nsGlobalWindow.h"
 #include "nsJSUtils.h"
 #include "nsIDOMFileList.h"
 
 using namespace mozilla;
@@ -40,120 +40,16 @@ IsReflector(JSObject* obj)
 enum StackScopedCloneTags {
     SCTAG_BASE = JS_SCTAG_USER_MIN,
     SCTAG_REFLECTOR,
     SCTAG_BLOB,
     SCTAG_FUNCTION,
     SCTAG_DOM_NFC_NDEF
 };
 
-class MOZ_STACK_CLASS StackScopedCloneData {
-public:
-    StackScopedCloneData(JSContext* aCx, StackScopedCloneOptions* aOptions)
-        : mOptions(aOptions)
-        , mReflectors(aCx)
-        , mFunctions(aCx)
-    {}
-
-    StackScopedCloneOptions* mOptions;
-    AutoObjectVector mReflectors;
-    AutoObjectVector mFunctions;
-    nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
-};
-
-static JSObject*
-StackScopedCloneRead(JSContext* cx, JSStructuredCloneReader* reader, uint32_t tag,
-                     uint32_t data, void* closure)
-{
-    MOZ_ASSERT(closure, "Null pointer!");
-    StackScopedCloneData* cloneData = static_cast<StackScopedCloneData*>(closure);
-    if (tag == SCTAG_REFLECTOR) {
-        MOZ_ASSERT(!data);
-
-        size_t idx;
-        if (!JS_ReadBytes(reader, &idx, sizeof(size_t)))
-            return nullptr;
-
-        RootedObject reflector(cx, cloneData->mReflectors[idx]);
-        MOZ_ASSERT(reflector, "No object pointer?");
-        MOZ_ASSERT(IsReflector(reflector), "Object pointer must be a reflector!");
-
-        if (!JS_WrapObject(cx, &reflector))
-            return nullptr;
-
-        return reflector;
-    }
-
-    if (tag == SCTAG_FUNCTION) {
-      MOZ_ASSERT(data < cloneData->mFunctions.length());
-
-      RootedValue functionValue(cx);
-      RootedObject obj(cx, cloneData->mFunctions[data]);
-
-      if (!JS_WrapObject(cx, &obj))
-          return nullptr;
-
-      FunctionForwarderOptions forwarderOptions;
-      if (!xpc::NewFunctionForwarder(cx, JSID_VOIDHANDLE, obj, forwarderOptions,
-                                     &functionValue))
-      {
-          return nullptr;
-      }
-
-      return &functionValue.toObject();
-    }
-
-    if (tag == SCTAG_BLOB) {
-        MOZ_ASSERT(!data);
-
-        size_t idx;
-        if (!JS_ReadBytes(reader, &idx, sizeof(size_t))) {
-            return nullptr;
-        }
-
-        nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
-        MOZ_ASSERT(global);
-
-        // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is called because
-        // otherwise the static analysis thinks it can gc the JSObject via the stack.
-        JS::Rooted<JS::Value> val(cx);
-        {
-            nsRefPtr<Blob> blob = Blob::Create(global, cloneData->mBlobImpls[idx]);
-            if (!ToJSValue(cx, blob, &val)) {
-                return nullptr;
-            }
-        }
-
-        return val.toObjectOrNull();
-    }
-
-    if (tag == SCTAG_DOM_NFC_NDEF) {
-#ifdef MOZ_NFC
-      nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(cx));
-      if (!global) {
-        return nullptr;
-      }
-
-      // Prevent the return value from being trashed by a GC during ~nsRefPtr.
-      JS::Rooted<JSObject*> result(cx);
-      {
-        nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(global);
-        result = ndefRecord->ReadStructuredClone(cx, reader) ?
-                 ndefRecord->WrapObject(cx, nullptr) : nullptr;
-      }
-      return result;
-#else
-      return nullptr;
-#endif
-    }
-
-    MOZ_ASSERT_UNREACHABLE("Encountered garbage in the clone stream!");
-    return nullptr;
-}
-
 // The HTML5 structured cloning algorithm includes a few DOM objects, notably
 // FileList. That wouldn't in itself be a reason to support them here,
 // but we've historically supported them for Cu.cloneInto (where we didn't support
 // other reflectors), so we need to continue to do so in the wrapReflectors == false
 // case to maintain compatibility.
 //
 // FileList clones are supposed to give brand new objects, rather than
 // cross-compartment wrappers. For this, our current implementation relies on the
@@ -165,83 +61,181 @@ bool IsFileList(JSObject* obj)
     if (!supports)
         return false;
     nsCOMPtr<nsIDOMFileList> fileList = do_QueryInterface(supports);
     if (fileList)
         return true;
     return false;
 }
 
-static bool
-StackScopedCloneWrite(JSContext* cx, JSStructuredCloneWriter* writer,
-                      Handle<JSObject*> obj, void* closure)
+class MOZ_STACK_CLASS StackScopedCloneData
+    : public StructuredCloneHelperInternal
 {
-    MOZ_ASSERT(closure, "Null pointer!");
-    StackScopedCloneData* cloneData = static_cast<StackScopedCloneData*>(closure);
+public:
+    StackScopedCloneData(JSContext* aCx, StackScopedCloneOptions* aOptions)
+        : mOptions(aOptions)
+        , mReflectors(aCx)
+        , mFunctions(aCx)
+    {}
 
+    ~StackScopedCloneData()
     {
-        Blob* blob = nullptr;
-        if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) {
-            BlobImpl* blobImpl = blob->Impl();
-            MOZ_ASSERT(blobImpl);
-
-            if (!cloneData->mBlobImpls.AppendElement(blobImpl))
-                return false;
-
-            size_t idx = cloneData->mBlobImpls.Length() - 1;
-            return JS_WriteUint32Pair(writer, SCTAG_BLOB, 0) &&
-                   JS_WriteBytes(writer, &idx, sizeof(size_t));
-        }
+        Shutdown();
     }
 
-    if ((cloneData->mOptions->wrapReflectors && IsReflector(obj)) ||
-        IsFileList(obj))
+    JSObject* ReadCallback(JSContext* aCx,
+                           JSStructuredCloneReader* aReader,
+                           uint32_t aTag,
+                           uint32_t aData)
     {
-        if (!cloneData->mReflectors.append(obj))
-            return false;
+        if (aTag == SCTAG_REFLECTOR) {
+            MOZ_ASSERT(!aData);
+
+            size_t idx;
+            if (!JS_ReadBytes(aReader, &idx, sizeof(size_t)))
+                return nullptr;
+
+            RootedObject reflector(aCx, mReflectors[idx]);
+            MOZ_ASSERT(reflector, "No object pointer?");
+            MOZ_ASSERT(IsReflector(reflector), "Object pointer must be a reflector!");
+
+            if (!JS_WrapObject(aCx, &reflector))
+                return nullptr;
+
+            return reflector;
+        }
+
+        if (aTag == SCTAG_FUNCTION) {
+          MOZ_ASSERT(aData < mFunctions.length());
+
+          RootedValue functionValue(aCx);
+          RootedObject obj(aCx, mFunctions[aData]);
+
+          if (!JS_WrapObject(aCx, &obj))
+              return nullptr;
+
+          FunctionForwarderOptions forwarderOptions;
+          if (!xpc::NewFunctionForwarder(aCx, JSID_VOIDHANDLE, obj, forwarderOptions,
+                                         &functionValue))
+          {
+              return nullptr;
+          }
+
+          return &functionValue.toObject();
+        }
+
+        if (aTag == SCTAG_BLOB) {
+            MOZ_ASSERT(!aData);
 
-        size_t idx = cloneData->mReflectors.length() - 1;
-        if (!JS_WriteUint32Pair(writer, SCTAG_REFLECTOR, 0))
-            return false;
-        if (!JS_WriteBytes(writer, &idx, sizeof(size_t)))
-            return false;
-        return true;
+            size_t idx;
+            if (!JS_ReadBytes(aReader, &idx, sizeof(size_t))) {
+                return nullptr;
+            }
+
+            nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+            MOZ_ASSERT(global);
+
+            // nsRefPtr<File> needs to go out of scope before toObjectOrNull() is called because
+            // otherwise the static analysis thinks it can gc the JSObject via the stack.
+            JS::Rooted<JS::Value> val(aCx);
+            {
+                nsRefPtr<Blob> blob = Blob::Create(global, mBlobImpls[idx]);
+                if (!ToJSValue(aCx, blob, &val)) {
+                    return nullptr;
+                }
+            }
+
+            return val.toObjectOrNull();
+        }
+
+        if (aTag == SCTAG_DOM_NFC_NDEF) {
+#ifdef MOZ_NFC
+          nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
+          if (!global) {
+            return nullptr;
+          }
+
+          // Prevent the return value from being trashed by a GC during ~nsRefPtr.
+          JS::Rooted<JSObject*> result(aCx);
+          {
+            nsRefPtr<MozNDEFRecord> ndefRecord = new MozNDEFRecord(global);
+            result = ndefRecord->ReadStructuredClone(aCx, aReader) ?
+                     ndefRecord->WrapObject(aCx, nullptr) : nullptr;
+          }
+          return result;
+#else
+          return nullptr;
+#endif
+        }
+
+        MOZ_ASSERT_UNREACHABLE("Encountered garbage in the clone stream!");
+        return nullptr;
     }
 
-    if (JS::IsCallable(obj)) {
-        if (cloneData->mOptions->cloneFunctions) {
-            cloneData->mFunctions.append(obj);
-            return JS_WriteUint32Pair(writer, SCTAG_FUNCTION, cloneData->mFunctions.length() - 1);
-        } else {
-            JS_ReportError(cx, "Permission denied to pass a Function via structured clone");
-            return false;
+    bool WriteCallback(JSContext* aCx,
+                       JSStructuredCloneWriter* aWriter,
+                       JS::Handle<JSObject*> aObj)
+    {
+        {
+            Blob* blob = nullptr;
+            if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
+                BlobImpl* blobImpl = blob->Impl();
+                MOZ_ASSERT(blobImpl);
+
+                if (!mBlobImpls.AppendElement(blobImpl))
+                    return false;
+
+                size_t idx = mBlobImpls.Length() - 1;
+                return JS_WriteUint32Pair(aWriter, SCTAG_BLOB, 0) &&
+                       JS_WriteBytes(aWriter, &idx, sizeof(size_t));
+            }
         }
-    }
+
+        if ((mOptions->wrapReflectors && IsReflector(aObj)) ||
+            IsFileList(aObj))
+        {
+            if (!mReflectors.append(aObj))
+                return false;
+
+            size_t idx = mReflectors.length() - 1;
+            if (!JS_WriteUint32Pair(aWriter, SCTAG_REFLECTOR, 0))
+                return false;
+            if (!JS_WriteBytes(aWriter, &idx, sizeof(size_t)))
+                return false;
+            return true;
+        }
+
+        if (JS::IsCallable(aObj)) {
+            if (mOptions->cloneFunctions) {
+                mFunctions.append(aObj);
+                return JS_WriteUint32Pair(aWriter, SCTAG_FUNCTION, mFunctions.length() - 1);
+            } else {
+                JS_ReportError(aCx, "Permission denied to pass a Function via structured clone");
+                return false;
+            }
+        }
 
 #ifdef MOZ_NFC
-    {
-      MozNDEFRecord* ndefRecord;
-      if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, obj, ndefRecord))) {
-        return JS_WriteUint32Pair(writer, SCTAG_DOM_NFC_NDEF, 0) &&
-               ndefRecord->WriteStructuredClone(cx, writer);
-      }
-    }
+        {
+          MozNDEFRecord* ndefRecord;
+          if (NS_SUCCEEDED(UNWRAP_OBJECT(MozNDEFRecord, aObj, ndefRecord))) {
+            return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NFC_NDEF, 0) &&
+                   ndefRecord->WriteStructuredClone(aCx, aWriter);
+          }
+        }
 #endif
 
-    JS_ReportError(cx, "Encountered unsupported value type writing stack-scoped structured clone");
-    return false;
-}
+        JS_ReportError(aCx, "Encountered unsupported value type writing stack-scoped structured clone");
+        return false;
+    }
 
-static const JSStructuredCloneCallbacks gStackScopedCloneCallbacks = {
-    StackScopedCloneRead,
-    StackScopedCloneWrite,
-    nullptr,
-    nullptr,
-    nullptr,
-    nullptr
+    StackScopedCloneOptions* mOptions;
+    AutoObjectVector mReflectors;
+    AutoObjectVector mFunctions;
+    nsTArray<nsRefPtr<BlobImpl>> mBlobImpls;
 };
 
 /*
  * General-purpose structured-cloning utility for cases where the structured
  * clone buffer is only used in stack-scope (that is to say, the buffer does
  * not escape from this function). The stack-scoping allows us to pass
  * references to various JSObjects directly in certain situations without
  * worrying about lifetime issues.
@@ -249,34 +243,33 @@ static const JSStructuredCloneCallbacks 
  * This function assumes that |cx| is already entered the compartment we want
  * to clone to, and that |val| may not be same-compartment with cx. When the
  * function returns, |val| is set to the result of the clone.
  */
 bool
 StackScopedClone(JSContext* cx, StackScopedCloneOptions& options,
                  MutableHandleValue val)
 {
-    JSAutoStructuredCloneBuffer buffer;
     StackScopedCloneData data(cx, &options);
     {
         // For parsing val we have to enter its compartment.
         // (unless it's a primitive)
         Maybe<JSAutoCompartment> ac;
         if (val.isObject()) {
             ac.emplace(cx, &val.toObject());
         } else if (val.isString() && !JS_WrapValue(cx, val)) {
             return false;
         }
 
-        if (!buffer.write(cx, val, &gStackScopedCloneCallbacks, &data))
+        if (!data.Write(cx, val))
             return false;
     }
 
     // Now recreate the clones in the target compartment.
-    if (!buffer.read(cx, val, &gStackScopedCloneCallbacks, &data))
+    if (!data.Read(cx, val))
         return false;
 
     // Deep-freeze if requested.
     if (options.deepFreeze && val.isObject()) {
         RootedObject obj(cx, &val.toObject());
         if (!JS_DeepFreezeObject(cx, obj))
             return false;
     }
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2092,28 +2092,40 @@ InvalidateEntirePaintedLayer(PaintedLaye
 LayerManager::PaintedLayerCreationHint
 ContainerState::GetLayerCreationHint(const nsIFrame* aAnimatedGeometryRoot)
 {
   // Check whether the layer will be scrollable. This is used as a hint to
   // influence whether tiled layers are used or not.
   if (mParameters.mInLowPrecisionDisplayPort) {
     return LayerManager::SCROLLABLE;
   }
-  nsIFrame* animatedGeometryRootParent = aAnimatedGeometryRoot->GetParent();
-  nsIScrollableFrame* scrollable = do_QueryFrame(animatedGeometryRootParent);
-  if (scrollable
-#ifdef MOZ_B2G
-      && scrollable->WantAsyncScroll()
-#endif
-     ) {
-    // WantAsyncScroll() returns false when the frame has overflow:hidden,
-    // so we won't create tiled layers for overflow:hidden frames even if
-    // they have a display port. The main purpose of the WantAsyncScroll check
-    // is to allow the B2G camera app to use hardware composer for compositing.
-    return LayerManager::SCROLLABLE;
+
+  // Check whether there's any active scroll frame on the animated geometry
+  // root chain.
+  nsIFrame* fParent;
+  for (const nsIFrame* f = aAnimatedGeometryRoot;
+       f != mContainerAnimatedGeometryRoot;
+       f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(mBuilder,
+           fParent, mContainerAnimatedGeometryRoot)) {
+    fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
+    if (!fParent) {
+      break;
+    }
+    nsIScrollableFrame* scrollable = do_QueryFrame(fParent);
+    if (scrollable
+  #ifdef MOZ_B2G
+        && scrollable->WantAsyncScroll()
+  #endif
+       ) {
+      // WantAsyncScroll() returns false when the frame has overflow:hidden,
+      // so we won't create tiled layers for overflow:hidden frames even if
+      // they have a display port. The main purpose of the WantAsyncScroll check
+      // is to allow the B2G camera app to use hardware composer for compositing.
+      return LayerManager::SCROLLABLE;
+    }
   }
   return LayerManager::NONE;
 }
 
 already_AddRefed<PaintedLayer>
 ContainerState::AttemptToRecyclePaintedLayer(const nsIFrame* aAnimatedGeometryRoot,
                                              nsDisplayItem* aItem,
                                              const nsPoint& aTopLeft)
new file mode 100644
--- /dev/null
+++ b/layout/style/GenerateCSSPropsGenerated.py
@@ -0,0 +1,58 @@
+# 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/.
+
+import sys
+import string
+
+properties = [{"name":p[0], "prop":p[1], "id":p[2],
+               "flags":p[3], "pref":p[4], "proptype":p[5]}
+              for (i, p) in enumerate(eval(sys.stdin.read()))]
+
+# Sort the list so that longhand and logical properties are intermingled
+# first, shorthand properties follow, then aliases appear last.  This matches
+# the order of the nsCSSProperty enum.
+
+def property_compare(x, y):
+    property_order = {"longhand": 0, "logical": 0, "shorthand": 1, "alias": 2}
+    return property_order[x["proptype"]] - property_order[y["proptype"]]
+
+properties = sorted(properties, cmp=property_compare)
+
+for i, p in enumerate(properties):
+    p["index"] = i
+
+def generate_idl_names(properties):
+    names = []
+    for p in properties:
+        if p["proptype"] is "alias":
+            continue
+        if "CSS_PROPERTY_INTERNAL" in p["flags"]:
+            names.append("  nullptr,  // %s" % p["name"])
+        else:
+            idl_name = p["prop"]
+            if not idl_name.startswith("Moz"):
+                idl_name = idl_name[0].lower() + idl_name[1:]
+            names.append('  "%s",' % idl_name)
+    return "\n".join(names)
+
+def generate_assertions(properties):
+    def enum(p):
+        if p["proptype"] is "alias":
+            return "eCSSPropertyAlias_%s" % p["prop"]
+        else:
+            return "eCSSProperty_%s" % p["id"]
+    msg = ('static_assert(%s == %d, "GenerateCSSPropsGenerated.py did not list '
+           'properties in nsCSSProperty order");')
+    return "\n".join(map(lambda p: msg % (enum(p), p["index"]), properties))
+
+cppFile = open(sys.argv[1], "r")
+cppTemplate = cppFile.read()
+cppFile.close()
+
+substitutions = {
+  "idl_names": generate_idl_names(properties),
+  "assertions": generate_assertions(properties)
+}
+print ("/* THIS IS AN AUTOGENERATED FILE.  DO NOT EDIT */\n\n" +
+       string.Template(cppTemplate).substitute(substitutions))
--- a/layout/style/Makefile.in
+++ b/layout/style/Makefile.in
@@ -1,8 +1,26 @@
 # 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/.
 
 INSTALL_TARGETS += structlist
 structlist_FILES := nsStyleStructList.h
 structlist_DEST = $(DIST)/include
 structlist_TARGET := export
+
+# TODO This list should be emitted to a .pp file via
+# GenerateCSSPropsGenerated.py.
+csspropsidlnames_dependencies = \
+  $(srcdir)/nsCSSPropList.h \
+  $(srcdir)/nsCSSPropAliasList.h \
+  $(srcdir)/nsCSSPropsGenerated.inc.in \
+  $(srcdir)/PythonCSSProps.h \
+  $(srcdir)/GenerateCSSPropsGenerated.py \
+  $(GLOBAL_DEPS) \
+  $(NULL)
+
+nsCSSPropsGenerated.inc : $(csspropsidlnames_dependencies)
+	$(CPP) $(DEFINES) $(ACDEFINES) \
+	  $(srcdir)/PythonCSSProps.h | \
+	    PYTHONDONTWRITEBYTECODE=1 $(PYTHON) \
+	      $(srcdir)/GenerateCSSPropsGenerated.py \
+	      $(srcdir)/nsCSSPropsGenerated.inc.in > $@
rename from dom/webidl/CSS2PropertiesProps.h
rename to layout/style/PythonCSSProps.h
--- a/dom/webidl/CSS2PropertiesProps.h
+++ b/layout/style/PythonCSSProps.h
@@ -3,37 +3,37 @@
 /* DO_PROP serves as an extra level of indirection to allow expansion
    of CSS_PROP_DOMPROP_PREFIXED */
 
 [
 
 #define PROP_STRINGIFY_INTERNAL(X) #X
 #define PROP_STRINGIFY(X) PROP_STRINGIFY_INTERNAL(X)
 
-#define DO_PROP(name, method, id, flags, pref) \
-  [ #name, #method, #id, PROP_STRINGIFY(flags), pref ],
+#define DO_PROP(name, method, id, flags, pref, proptype) \
+  [ #name, #method, #id, PROP_STRINGIFY(flags), pref, proptype ],
 #define CSS_PROP(name, id, method, flags, pref, parsevariant, kwtable, \
-		 stylestruct, stylestructofset, animtype) \
-  DO_PROP(name, method, id, flags, pref)
+		 stylestruct, stylestructoffset, animtype) \
+  DO_PROP(name, method, id, flags, pref, "longhand")
 #define CSS_PROP_SHORTHAND(name, id, method, flags, pref) \
-  DO_PROP(name, method, id, flags, pref)
+  DO_PROP(name, method, id, flags, pref, "shorthand")
+#define CSS_PROP_LOGICAL(name, id, method, flags, pref, parsevariant, kwtable, \
+     group, stylestruct, stylestructoffset, animtype) \
+  DO_PROP(name, method, id, flags, pref, "logical")
 #define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
-#define CSS_PROP_LIST_EXCLUDE_INTERNAL
-#define CSS_PROP_LIST_INCLUDE_LOGICAL
 
 #include "nsCSSPropList.h"
 
-#undef CSS_PROP_LIST_INCLUDE_LOGICAL
-#undef CSS_PROP_LIST_EXCLUDE_INTERNAL
 #undef CSS_PROP_PUBLIC_OR_PRIVATE
+#undef CSS_PROP_LOGICAL
 #undef CSS_PROP_SHORTHAND
 #undef CSS_PROP
 
 #define CSS_PROP_ALIAS(name, id, method, pref) \
-  DO_PROP(name, method, id, 0, pref)
+  DO_PROP(name, method, id, 0, pref, "alias")
 
 #include "nsCSSPropAliasList.h"
 
 #undef CSS_PROP_ALIAS
 
 #undef DO_PROP
 #undef PROP_STRINGIFY
 #undef PROP_STRINGIFY_INTERNAL
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -206,15 +206,22 @@ JAR_MANIFESTS += ['jar.mn']
 RESOURCE_FILES += [
     'contenteditable.css',
     'designmode.css',
     'ImageDocument.css',
     'TopLevelImageDocument.css',
     'TopLevelVideoDocument.css',
 ]
 
-GENERATED_FILES += ['nsStyleStructList.h']
+# nsCSSPropsGenerated.inc is generated from nsCSSPropsGenerated.inc.in by
+# GenerateCSSPropsGenerated.py; see the corresponding rules in Makefile.in.
+
+GENERATED_FILES += [
+    'nsCSSPropsGenerated.inc',
+    'nsStyleStructList.h',
+]
+
 style_struct_list = GENERATED_FILES['nsStyleStructList.h']
 style_struct_list.script = 'generate-stylestructlist.py'
 
 if CONFIG['GNU_CC']:
     CFLAGS += ['-Wshadow']
     CXXFLAGS += ['-Wshadow']
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -91,17 +91,19 @@
 
 #define CSS_PROP_DOMPROP_PREFIXED(name_) \
   CSS_PROP_PUBLIC_OR_PRIVATE(Moz ## name_, name_)
 
 #define CSS_PROP_NO_OFFSET (-1)
 
 // Callers may define CSS_PROP_LIST_EXCLUDE_INTERNAL if they want to
 // exclude internal properties that are not represented in the DOM (only
-// the DOM style code defines this).
+// the DOM style code defines this).  All properties defined in an
+// #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL section must have the
+// CSS_PROPERTY_INTERNAL flag set.
 
 // When capturing all properties by defining CSS_PROP, callers must also
 // define one of the following three macros:
 //
 //   CSS_PROP_LIST_EXCLUDE_LOGICAL
 //     Does not include logical properties (defined with CSS_PROP_LOGICAL,
 //     such as margin-inline-start) when capturing properties to CSS_PROP.
 //
@@ -412,17 +414,18 @@ CSS_PROP_TEXT(
     nullptr,
     offsetof(nsStyleText, mTabSize),
     eStyleAnimType_None)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_FONT(
     -x-system-font,
     _x_system_font,
     CSS_PROP_DOMPROP_PREFIXED(SystemFont),
-    CSS_PROPERTY_PARSE_INACCESSIBLE |
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_INACCESSIBLE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
     "",
     0,
     kFontKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 #endif // !defined(CSS_PROP_LIST_EXCLUDE_INTERNAL)
@@ -1510,17 +1513,18 @@ CSS_PROP_CONTENT(
     kContentKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_TEXT(
     -moz-control-character-visibility,
     _moz_control_character_visibility,
     CSS_PROP_DOMPROP_PREFIXED(ControlCharacterVisibility),
-    CSS_PROPERTY_PARSE_VALUE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kControlCharacterVisibilityKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 #endif
 CSS_PROP_CONTENT(
     counter-increment,
@@ -3748,64 +3752,69 @@ CSS_PROP_XUL(
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_FONT(
     -moz-script-level,
     script_level,
     ScriptLevel,
     // REVIEW: no range restriction?
     // NOTE: CSSParserImpl::ParseSingleValueProperty only accepts this
     // property when mUnsafeRulesEnabled is set.
-    CSS_PROPERTY_PARSE_VALUE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_VALUE,
     "",
     // script-level can take Auto, Integer and Number values, but only Auto
     // ("increment if parent is not in displaystyle") and Integer
     // ("relative") values can be specified in a style sheet.
     VARIANT_AHI,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_FONT(
     -moz-script-size-multiplier,
     script_size_multiplier,
     ScriptSizeMultiplier,
     // REVIEW: no range restriction?
-    CSS_PROPERTY_PARSE_INACCESSIBLE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_FONT(
     -moz-script-min-size,
     script_min_size,
     ScriptMinSize,
     // REVIEW: no range restriction?
-    CSS_PROPERTY_PARSE_INACCESSIBLE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_FONT(
     -moz-math-variant,
     math_variant,
     MathVariant,
-    CSS_PROPERTY_PARSE_INACCESSIBLE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     VARIANT_HK,
     kMathVariantKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_FONT(
     -moz-math-display,
     math_display,
     MathDisplay,
     // NOTE: CSSParserImpl::ParseSingleValueProperty only accepts this
     // property when mUnsafeRulesEnabled is set.
-    CSS_PROPERTY_PARSE_VALUE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kMathDisplayKTable,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 #endif // !defined(CSS_PROP_LIST_EXCLUDE_INTERNAL)
 #endif // !defined(CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND)
 
@@ -4179,37 +4188,40 @@ CSS_PROP_SHORTHAND(
 #ifdef CSS_PROP_STUB_NOT_CSS
 CSS_PROP_STUB_NOT_CSS
 CSS_PROP_STUB_NOT_CSS
 #else
 CSS_PROP_FONT(
     -x-lang,
     _x_lang,
     Lang,
-    CSS_PROPERTY_PARSE_INACCESSIBLE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_TABLE(
     -x-span,
     _x_span,
     Span,
-    CSS_PROPERTY_PARSE_INACCESSIBLE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_FONT(
     -x-text-zoom,
     _x_text_zoom,
     TextZoom,
-    CSS_PROPERTY_PARSE_INACCESSIBLE,
+    CSS_PROPERTY_INTERNAL |
+        CSS_PROPERTY_PARSE_INACCESSIBLE,
     "",
     0,
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 #endif /* !defined(CSS_PROP_STUB_NOT_CSS) */
 #endif /* !defined(CSS_PROP_LIST_EXCLUDE_INTERNAL) */
 #endif /* !defined(CSS_PROP_LIST_ONLY_COMPONENTS_OF_ALL_SHORTHAND) */
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -219,16 +219,52 @@ nsCSSProps::AddRefTable(void)
                ++p) {
             MOZ_ASSERT(nsCSSProps::PropHasFlags(*p, flag),
                        "all subproperties of a property with a "
                        "CSS_PROPERTY_ALWAYS_ENABLED_* flag must also have "
                        "the flag");
           }
         }
       }
+
+      // Assert that CSS_PROPERTY_INTERNAL is used on properties in
+      // #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL sections of nsCSSPropList.h
+      // and on no others.
+      static nsCSSProperty nonInternalProperties[] = {
+        #define CSS_PROP(name_, id_, ...)           eCSSProperty_##id_,
+        #define CSS_PROP_SHORTHAND(name_, id_, ...) eCSSProperty_##id_,
+        #define CSS_PROP_LIST_INCLUDE_LOGICAL
+        #define CSS_PROP_LIST_EXCLUDE_INTERNAL
+        #include "nsCSSPropList.h"
+        #undef CSS_PROP_LIST_EXCLUDE_INTERNAL
+        #undef CSS_PROP_LIST_INCLUDE_LOGICAL
+        #undef CSS_PROP_SHORTHAND
+        #undef CSS_PROP
+      };
+      MOZ_ASSERT(ArrayLength(nonInternalProperties) <= eCSSProperty_COUNT);
+
+      bool found[eCSSProperty_COUNT];
+      PodArrayZero(found);
+      for (nsCSSProperty p : nonInternalProperties) {
+        MOZ_ASSERT(!nsCSSProps::PropHasFlags(p, CSS_PROPERTY_INTERNAL),
+                   "properties defined outside of #ifndef "
+                   "CSS_PROP_LIST_EXCLUDE_INTERNAL sections must not have "
+                   "the CSS_PROPERTY_INTERNAL flag");
+        found[p] = true;
+      }
+
+      for (size_t i = 0; i < ArrayLength(found); ++i) {
+        if (!found[i]) {
+          auto p = static_cast<nsCSSProperty>(i);
+          MOZ_ASSERT(nsCSSProps::PropHasFlags(p, CSS_PROPERTY_INTERNAL),
+                     "properties defined in #ifndef "
+                     "CSS_PROP_LIST_EXCLUDE_INTERNAL sections must have "
+                     "the CSS_PROPERTY_INTERNAL flag");
+        }
+      }
     }
 #endif
   }
 }
 
 #undef  DEBUG_SHORTHANDS_CONTAINING
 
 bool
@@ -2977,8 +3013,10 @@ nsCSSProps::gPropertyUseCounter[eCSSProp
                 "on logical properties");                                   \
   static_assert(!(((flags_) & CSS_PROPERTY_LOGICAL_AXIS) &&                 \
                   ((flags_) & CSS_PROPERTY_LOGICAL_END_EDGE)),              \
                 "CSS_PROPERTY_LOGICAL_END_EDGE makes no sense when used "   \
                 "with CSS_PROPERTY_LOGICAL_AXIS");
 #include "nsCSSPropList.h"
 #undef CSS_PROP_LOGICAL
 #undef CSS_PROP
+
+#include "nsCSSPropsGenerated.inc"
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -225,16 +225,21 @@ static_assert((CSS_PROPERTY_PARSE_PROPER
 // margin-inline-end).  Must only be set if CSS_PROPERTY_LOGICAL is set.
 // When not set, the logical property is for the "start" edge (such as
 // margin-block-start or margin-inline-start).
 #define CSS_PROPERTY_LOGICAL_END_EDGE             (1<<26)
 
 // This property can be animated on the compositor.
 #define CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR    (1<<27)
 
+// This property is an internal property that is not represented
+// in the DOM.  Properties with this flag must be defined in an #ifndef
+// CSS_PROP_LIST_EXCLUDE_INTERNAL section of nsCSSPropList.h.
+#define CSS_PROPERTY_INTERNAL                     (1<<28)
+
 /**
  * Types of animatable values.
  */
 enum nsStyleAnimType {
   // requires a custom implementation in
   // StyleAnimationValue::ExtractComputedValue
   eStyleAnimType_Custom,
 
@@ -496,16 +501,38 @@ public:
    * getting too many of these properties, we should make kLogicalGroupTable
    * be a simple array of eCSSProperty_COUNT length.)
    */
   static const nsCSSProperty* LogicalGroup(nsCSSProperty aProperty);
 
 private:
   static bool gPropertyEnabled[eCSSProperty_COUNT_with_aliases];
 
+private:
+  // Defined in the generated nsCSSPropsGenerated.inc.
+  static const char* const kIDLNameTable[eCSSProperty_COUNT];
+
+public:
+  /**
+   * Returns the IDL name of the specified property, which must be a
+   * longhand, logical or shorthand property.  The IDL name is the property
+   * name with any hyphen-lowercase character pairs replaced by an
+   * uppercase character:
+   * https://drafts.csswg.org/cssom/#css-property-to-idl-attribute
+   *
+   * As a special case, the string "cssFloat" is returned for the float
+   * property.  nullptr is returned for internal properties.
+   */
+  static const char* PropertyIDLName(nsCSSProperty aProperty)
+  {
+    MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
+               "out of range");
+    return kIDLNameTable[aProperty];
+  }
+
 public:
 
   static bool IsEnabled(nsCSSProperty aProperty) {
     MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_with_aliases,
                "out of range");
     return gPropertyEnabled[aProperty];
   }
 
new file mode 100644
--- /dev/null
+++ b/layout/style/nsCSSPropsGenerated.inc.in
@@ -0,0 +1,13 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* processed file that defines CSS property tables that can't be generated
+   with the pre-processor, designed to be #included in nsCSSProps.cpp */
+
+const char* const nsCSSProps::kIDLNameTable[eCSSProperty_COUNT] = {
+${idl_names}
+};
+
+${assertions}
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -305,17 +305,18 @@ class RemoteReftest(RefTest):
         browserEnv = RefTest.buildBrowserEnv(self, options, profileDir)
         # remove desktop environment not used on device
         if "XPCOM_MEM_BLOAT_LOG" in browserEnv:
             del browserEnv["XPCOM_MEM_BLOAT_LOG"]
         return browserEnv
 
     def runApp(self, profile, binary, cmdargs, env,
                timeout=None, debuggerInfo=None,
-               symbolsPath=None, options=None):
+               symbolsPath=None, options=None,
+               valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
         status = self.automation.runApp(None, env,
                                         binary,
                                         profile.profile,
                                         cmdargs,
                                         utilityPath=options.utilityPath,
                                         xrePath=options.xrePath,
                                         debuggerInfo=debuggerInfo,
                                         symbolsPath=symbolsPath,
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -580,17 +580,18 @@ class RefTest(object):
             return line
 
         def log(self, line):
             log.info(line)
             return line
 
     def runApp(self, profile, binary, cmdargs, env,
                timeout=None, debuggerInfo=None,
-               symbolsPath=None, options=None):
+               symbolsPath=None, options=None,
+               valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
 
         def timeoutHandler():
             self.handleTimeout(
                 timeout, proc, options.utilityPath, debuggerInfo)
 
         interactive = False
         debug_args = None
         if debuggerInfo:
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -306,17 +306,18 @@ class B2GRemoteReftest(RefTest):
             print "Automation Error: Failed to copy extra files to device"
             raise
 
     def environment(self, **kwargs):
      return self.automation.environment(**kwargs)
 
     def runApp(self, profile, binary, cmdargs, env,
                timeout=None, debuggerInfo=None,
-               symbolsPath=None, options=None):
+               symbolsPath=None, options=None,
+               valgrindPath=None, valgrindArgs=None, valgrindSuppFiles=None):
         status = self.automation.runApp(None, env,
                                         binary,
                                         profile.profile,
                                         cmdargs,
                                         utilityPath=options.utilityPath,
                                         xrePath=options.xrePath,
                                         debuggerInfo=debuggerInfo,
                                         symbolsPath=symbolsPath,
--- a/mobile/android/base/util/WebActivityMapper.java
+++ b/mobile/android/base/util/WebActivityMapper.java
@@ -6,100 +6,121 @@
 package org.mozilla.gecko.util;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
 import android.text.TextUtils;
+import android.util.Log;
 
+import java.io.File;
 import java.util.HashMap;
 import java.util.Map;
 
 public final class WebActivityMapper {
+    private static final String LOGTAG = "Gecko";
+
     private static final Map<String, WebActivityMapping> activityMap = new HashMap<String, WebActivityMapping>();
     static {
         activityMap.put("dial", new DialMapping());
         activityMap.put("open", new OpenMapping());
         activityMap.put("pick", new PickMapping());
         activityMap.put("send", new SendMapping());
         activityMap.put("view", new ViewMapping());
+        activityMap.put("record", new RecordMapping());
     };
 
     private static abstract class WebActivityMapping {
+        protected JSONObject mData;
+
+        public void setData(JSONObject data) {
+            mData = data;
+        }
+
         // Cannot return null
         public abstract String getAction();
 
-        public String getMime(JSONObject data) throws JSONException {
+        public String getMime() throws JSONException {
             return null;
         }
 
-        public String getUri(JSONObject data) throws JSONException {
+        public String getUri() throws JSONException {
             return null;
         }
 
-        public void putExtras(JSONObject data, Intent intent) throws JSONException {}
+        public void putExtras(Intent intent) throws JSONException {}
     }
 
     /**
      * Provides useful defaults for mime type and uri.
      */
     private static abstract class BaseMapping extends WebActivityMapping {
         /**
          * If 'type' is present in data object, uses the value as the MIME type.
          */
         @Override
-        public String getMime(JSONObject data) throws JSONException {
-            return data.optString("type", null);
+        public String getMime() throws JSONException {
+            return mData.optString("type", null);
         }
 
         /**
          * If 'uri' or 'url' is present in data object, uses the respective value as the Uri.
          */
         @Override
-        public String getUri(JSONObject data) throws JSONException {
+        public String getUri() throws JSONException {
             // Will return uri or url if present.
-            String uri = data.optString("uri", null);
-            return uri != null ? uri : data.optString("url", null);
+            String uri = mData.optString("uri", null);
+            return uri != null ? uri : mData.optString("url", null);
         }
     }
 
     public static Intent getIntentForWebActivity(JSONObject message) throws JSONException {
         final String name = message.getString("name").toLowerCase();
         final JSONObject data = message.getJSONObject("data");
 
+        Log.w(LOGTAG, "Activity is: " + name);
         final WebActivityMapping mapping = activityMap.get(name);
+        if (mapping == null) {
+            Log.w(LOGTAG, "No mapping found!");
+            return null;
+        }
+
+        mapping.setData(data);
+
         final Intent intent = new Intent(mapping.getAction());
 
-        final String mime = mapping.getMime(data);
+        final String mime = mapping.getMime();
         if (!TextUtils.isEmpty(mime)) {
             intent.setType(mime);
         }
 
-        final String uri = mapping.getUri(data);
+        final String uri = mapping.getUri();
         if (!TextUtils.isEmpty(uri)) {
             intent.setData(Uri.parse(uri));
         }
 
-        mapping.putExtras(data, intent);
+        mapping.putExtras(intent);
 
         return intent;
     }
 
     private static class DialMapping extends WebActivityMapping {
         @Override
         public String getAction() {
             return Intent.ACTION_DIAL;
         }
 
         @Override
-        public String getUri(JSONObject data) throws JSONException {
-            return "tel:" + data.getString("number");
+        public String getUri() throws JSONException {
+            return "tel:" + mData.getString("number");
         }
     }
 
     private static class OpenMapping extends BaseMapping {
         @Override
         public String getAction() {
             return Intent.ACTION_VIEW;
         }
@@ -107,54 +128,94 @@ public final class WebActivityMapper {
 
     private static class PickMapping extends BaseMapping {
         @Override
         public String getAction() {
             return Intent.ACTION_GET_CONTENT;
         }
 
         @Override
-        public String getMime(JSONObject data) throws JSONException {
+        public String getMime() throws JSONException {
             // bug 1007112 - pick action needs a mimetype to work
-            String mime = data.optString("type", null);
+            String mime = mData.optString("type", null);
             return !TextUtils.isEmpty(mime) ? mime : "*/*";
         }
     }
 
     private static class SendMapping extends BaseMapping {
         @Override
         public String getAction() {
             return Intent.ACTION_SEND;
         }
 
         @Override
-        public void putExtras(JSONObject data, Intent intent) throws JSONException {
-            optPutExtra("text", Intent.EXTRA_TEXT, data, intent);
-            optPutExtra("html_text", Intent.EXTRA_HTML_TEXT, data, intent);
-            optPutExtra("stream", Intent.EXTRA_STREAM, data, intent);
+        public void putExtras(Intent intent) throws JSONException {
+            optPutExtra("text", Intent.EXTRA_TEXT, intent);
+            optPutExtra("html_text", Intent.EXTRA_HTML_TEXT, intent);
+            optPutExtra("stream", Intent.EXTRA_STREAM, intent);
         }
 
-        private static void optPutExtra(String key, String extraName, JSONObject data, Intent intent) {
-            final String extraValue = data.optString(key);
+        private void optPutExtra(String key, String extraName, Intent intent) {
+            final String extraValue = mData.optString(key);
             if (!TextUtils.isEmpty(extraValue)) {
                 intent.putExtra(extraName, extraValue);
             }
         }
     }
 
     private static class ViewMapping extends BaseMapping {
         @Override
         public String getAction() {
             return Intent.ACTION_VIEW;
         }
 
         @Override
-        public String getMime(JSONObject data) {
+        public String getMime() {
             // MozActivity adds a type 'url' here, we don't want to set the MIME to 'url'.
-            String type = data.optString("type", null);
+            String type = mData.optString("type", null);
             if ("url".equals(type) || "uri".equals(type)) {
                 return null;
             } else {
                 return type;
             }
         }
     }
+
+    private static class RecordMapping extends WebActivityMapping {
+        @Override
+        public String getAction() {
+            String type = mData.optString("type", null);
+            if ("photos".equals(type)) {
+                return "android.media.action.IMAGE_CAPTURE";
+            } else if ("videos".equals(type)) {
+                return "android.media.action.VIDEO_CAPTURE";
+            }
+            return null;
+        }
+
+        // Add an extra to specify where to save the picture/video.
+        @Override
+        public void putExtras(Intent intent) {
+            final String action = getAction();
+
+            final String dirType = action == "android.media.action.IMAGE_CAPTURE"
+                ? Environment.DIRECTORY_PICTURES
+                : Environment.DIRECTORY_MOVIES;
+
+            final String ext = action == "android.media.action.IMAGE_CAPTURE"
+                ? ".jpg"
+                : ".mp4";
+
+            File destDir = Environment.getExternalStoragePublicDirectory(dirType);
+
+            try {
+                File dest = File.createTempFile(
+                    "capture", /* prefix */
+                    ext,       /* suffix */
+                    destDir    /* directory */
+                );
+                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(dest));
+            } catch(Exception e) {
+                Log.w(LOGTAG, "Failed to add extra for " + action + " : " + e);
+            }
+        }
+    }
 }
--- a/modules/brotli/README.mozilla
+++ b/modules/brotli/README.mozilla
@@ -9,9 +9,9 @@ Upstream code can be viewed at
 
 and cloned by
   git clone https://github.com/google/brotli
 
 The in-tree copy is updated by running
   sh update.sh
 from within the modules/brotli directory.
 
-Current version: [commit ca29aa22c295daac15baf5d85427ecc7808b515c].
+Current version: [commit 1dd66ef114fd244778d9dcb5da09c28b49a0df33].
--- a/modules/brotli/dec/Makefile
+++ b/modules/brotli/dec/Makefile
@@ -1,12 +1,12 @@
 #brotli/dec
 
 include ../shared.mk
 
-CPPFLAGS += -Wall
+CFLAGS += -Wall
 
-OBJS = bit_reader.o decode.o huffman.o safe_malloc.o streams.o
+OBJS = bit_reader.o decode.o huffman.o state.o streams.o
 
 all : $(OBJS)
 
 clean :
 	rm -f $(OBJS)
--- a/modules/brotli/dec/bit_reader.c
+++ b/modules/brotli/dec/bit_reader.c
@@ -6,45 +6,50 @@
 
    http://www.apache.org/licenses/LICENSE-2.0
 
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-
-   Bit reading helpers
 */
 
-#include <assert.h>
+/* Bit reading helpers */
+
 #include <stdlib.h>
 
 #include "./bit_reader.h"
+#include "./port.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
-int BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input) {
-  size_t i;
-  assert(br != NULL);
+void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input) {
+  BROTLI_DCHECK(br != NULL);
 
-  br->buf_ptr_ = br->buf_;
   br->input_ = input;
   br->val_ = 0;
-  br->pos_ = 0;
   br->bit_pos_ = 0;
-  br->bit_end_pos_ = 0;
+  br->avail_in = 0;
   br->eos_ = 0;
-  if (!BrotliReadMoreInput(br)) {
-    return 0;
-  }
+  br->next_in = br->buf_;
+}
+
+
+void BrotliWarmupBitReader(BrotliBitReader* const br) {
+  size_t i;
+  br->val_ = 0;
   for (i = 0; i < sizeof(br->val_); ++i) {
-    br->val_ |= ((uint64_t)br->buf_[br->pos_]) << (8 * i);
-    ++br->pos_;
+#if (BROTLI_64_BITS_LITTLE_ENDIAN)
+    br->val_ |= ((uint64_t)*br->next_in) << (8 * i);
+#else
+    br->val_ |= ((uint32_t)*br->next_in) << (8 * i);
+#endif
+    ++br->next_in;
+    --br->avail_in;
   }
-  return (br->bit_end_pos_ > 0);
 }
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }    /* extern "C" */
 #endif
--- a/modules/brotli/dec/bit_reader.h
+++ b/modules/brotli/dec/bit_reader.h
@@ -6,199 +6,251 @@
 
    http://www.apache.org/licenses/LICENSE-2.0
 
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
+*/
 
-   Bit reading helpers
-*/
+/* Bit reading helpers */
 
 #ifndef BROTLI_DEC_BIT_READER_H_
 #define BROTLI_DEC_BIT_READER_H_
 
 #include <string.h>
+#include "./port.h"
 #include "./streams.h"
 #include "./types.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
-#if (defined(__x86_64__) || defined(_M_X64))
-/* This should be set to 1 only on little-endian machines. */
-#define BROTLI_USE_64_BITS 1
-#else
-#define BROTLI_USE_64_BITS 0
-#endif
 #define BROTLI_MAX_NUM_BIT_READ   25
-#define BROTLI_READ_SIZE          4096
-#define BROTLI_IBUF_SIZE          (2 * BROTLI_READ_SIZE + 32)
-#define BROTLI_IBUF_MASK          (2 * BROTLI_READ_SIZE - 1)
+#define BROTLI_READ_SIZE          1024
+#define BROTLI_IMPLICIT_ZEROES    128
+#define BROTLI_IBUF_SIZE          (BROTLI_READ_SIZE + BROTLI_IMPLICIT_ZEROES)
+#define BROTLI_IBUF_MASK          (BROTLI_READ_SIZE - 1)
 
-#define UNALIGNED_COPY64(dst, src) memcpy(dst, src, 8)
-#define UNALIGNED_MOVE64(dst, src) memmove(dst, src, 8)
-
-static const uint32_t kBitMask[BROTLI_MAX_NUM_BIT_READ] = {
-  0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,
-  65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215
-};
+/* Masking with this expression turns to a single "Unsigned Bit Field Extract"
+   UBFX instruction on ARM. */
+static BROTLI_INLINE uint32_t BitMask(int n) { return ~((0xffffffff) << n); }
 
 typedef struct {
-  /* Input byte buffer, consist of a ringbuffer and a "slack" region where */
-  /* bytes from the start of the ringbuffer are copied. */
-  uint8_t buf_[BROTLI_IBUF_SIZE];
-  uint8_t*    buf_ptr_;      /* next input will write here */
-  BrotliInput input_;        /* input callback */
-#if (BROTLI_USE_64_BITS)
+#if (BROTLI_64_BITS_LITTLE_ENDIAN)
   uint64_t    val_;          /* pre-fetched bits */
 #else
   uint32_t    val_;          /* pre-fetched bits */
 #endif
-  uint32_t    pos_;          /* byte position in stream */
   uint32_t    bit_pos_;      /* current bit-reading position in val_ */
-  uint32_t    bit_end_pos_;  /* bit-reading end position from LSB of val_ */
+  uint8_t*    next_in;       /* the byte we're reading from */
+  uint32_t    avail_in;
   int         eos_;          /* input stream is finished */
+  BrotliInput input_;        /* input callback */
+
+  /* Input byte buffer, consist of a ringbuffer and a "slack" region where */
+  /* bytes from the start of the ringbuffer are copied. */
+  uint8_t buf_[BROTLI_IBUF_SIZE];
 } BrotliBitReader;
 
-int BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input);
-
-/* Return the prefetched bits, so they can be looked up. */
-static BROTLI_INLINE uint32_t BrotliPrefetchBits(BrotliBitReader* const br) {
-  return (uint32_t)(br->val_ >> br->bit_pos_);
-}
-
-/* For jumping over a number of bits in the bit stream when accessed with */
-/* BrotliPrefetchBits and BrotliFillBitWindow. */
-static BROTLI_INLINE void BrotliSetBitPos(BrotliBitReader* const br,
-                                          uint32_t val) {
-#ifdef BROTLI_DECODE_DEBUG
-  uint32_t n_bits = val - br->bit_pos_;
-  const uint32_t bval = (uint32_t)(br->val_ >> br->bit_pos_) & kBitMask[n_bits];
-  printf("[BrotliReadBits]  %010d %2d  val: %6x\n",
-         (br->pos_ << 3) + br->bit_pos_ - 64, n_bits, bval);
-#endif
-  br->bit_pos_ = val;
-}
+/* Initializes the bitreader fields. After this, BrotliReadInput then
+   BrotliWarmupBitReader must be used. */
+void BrotliInitBitReader(BrotliBitReader* const br, BrotliInput input);
 
-/*
- * Reload up to 32 bits byte-by-byte.
- * This function works on both little and big endian.
- */
-static BROTLI_INLINE void ShiftBytes32(BrotliBitReader* const br) {
-  while (br->bit_pos_ >= 8) {
-    br->val_ >>= 8;
-    br->val_ |= ((uint32_t)br->buf_[br->pos_ & BROTLI_IBUF_MASK]) << 24;
-    ++br->pos_;
-    br->bit_pos_ -= 8;
-    br->bit_end_pos_ -= 8;
-  }
-}
+/* Initializes bit reading and bit position with the first input data available.
+   Requires that there is enough input available (BrotliCheckInputAmount). */
+void BrotliWarmupBitReader(BrotliBitReader* const br);
 
-/* Fills up the input ringbuffer by calling the input callback.
+/* Pulls data from the input to the the read buffer.
 
-   Does nothing if there are at least 32 bytes present after current position.
-
-   Returns 0 if either:
+   Returns 0 if one of:
     - the input callback returned an error, or
     - there is no more input and the position is past the end of the stream.
+    - finish is false and less than BROTLI_READ_SIZE are available - a next call
+      when more data is available makes it continue including the partially read
+      data
 
-   After encountering the end of the input stream, 32 additional zero bytes are
-   copied to the ringbuffer, therefore it is safe to call this function after
-   every 32 bytes of input is read.
+   If finish is true and the end of the stream is reached,
+   BROTLI_IMPLICIT_ZEROES additional zero bytes are copied to the ringbuffer.
 */
-static BROTLI_INLINE int BrotliReadMoreInput(BrotliBitReader* const br) {
-  if (br->bit_end_pos_ > 256) {
-    return 1;
-  } else if (br->eos_) {
-    return br->bit_pos_ <= br->bit_end_pos_;
+static BROTLI_INLINE int BrotliReadInput(
+    BrotliBitReader* const br, int finish) {
+  if (PREDICT_FALSE(br->eos_)) {
+    return 0;
   } else {
-    uint8_t* dst = br->buf_ptr_;
-    int bytes_read = BrotliRead(br->input_, dst, BROTLI_READ_SIZE);
+    size_t i;
+    int bytes_read;
+    if (br->next_in != br->buf_) {
+      for (i = 0; i < br->avail_in; i++) {
+        br->buf_[i] = br->next_in[i];
+      }
+      br->next_in = br->buf_;
+    }
+    bytes_read = BrotliRead(br->input_, br->next_in + br->avail_in,
+        (size_t)(BROTLI_READ_SIZE - br->avail_in));
     if (bytes_read < 0) {
       return 0;
     }
-    if (bytes_read < BROTLI_READ_SIZE) {
+    br->avail_in += (uint32_t)bytes_read;
+    if (br->avail_in < BROTLI_READ_SIZE) {
+      if (!finish) {
+        return 0;
+      }
       br->eos_ = 1;
-      /* Store 32 bytes of zero after the stream end. */
-#if (BROTLI_USE_64_BITS)
-      *(uint64_t*)(dst + bytes_read) = 0;
-      *(uint64_t*)(dst + bytes_read + 8) = 0;
-      *(uint64_t*)(dst + bytes_read + 16) = 0;
-      *(uint64_t*)(dst + bytes_read + 24) = 0;
-#else
-      memset(dst + bytes_read, 0, 32);
-#endif
+      /* Store BROTLI_IMPLICIT_ZEROES bytes of zero after the stream end. */
+      memset(br->next_in + br->avail_in, 0, BROTLI_IMPLICIT_ZEROES);
+      br->avail_in += BROTLI_IMPLICIT_ZEROES;
     }
-    if (dst == br->buf_) {
-      /* Copy the head of the ringbuffer to the slack region. */
-#if (BROTLI_USE_64_BITS)
-      UNALIGNED_COPY64(br->buf_ + BROTLI_IBUF_SIZE - 32, br->buf_);
-      UNALIGNED_COPY64(br->buf_ + BROTLI_IBUF_SIZE - 24, br->buf_ + 8);
-      UNALIGNED_COPY64(br->buf_ + BROTLI_IBUF_SIZE - 16, br->buf_ + 16);
-      UNALIGNED_COPY64(br->buf_ + BROTLI_IBUF_SIZE - 8, br->buf_ + 24);
-#else
-      memcpy(br->buf_ + (BROTLI_READ_SIZE << 1), br->buf_, 32);
-#endif
-      br->buf_ptr_ = br->buf_ + BROTLI_READ_SIZE;
-    } else {
-      br->buf_ptr_ = br->buf_;
-    }
-    br->bit_end_pos_ += ((uint32_t)bytes_read << 3);
     return 1;
   }
 }
 
-/* Guarantees that there are at least 24 bits in the buffer. */
-static BROTLI_INLINE void BrotliFillBitWindow(BrotliBitReader* const br) {
-#if (BROTLI_USE_64_BITS)
-  if (br->bit_pos_ >= 40) {
-    /*
-     * Advances the Read buffer by 5 bytes to make room for reading next
-     * 24 bits.
-     * The expression below needs a little-endian arch to work correctly.
-     * This gives a large speedup for decoding speed.
-     */
-    br->val_ >>= 40;
-    br->val_ |= *(const uint64_t*)(
-        br->buf_ + (br->pos_ & BROTLI_IBUF_MASK)) << 24;
-    br->pos_ += 5;
-    br->bit_pos_ -= 40;
-    br->bit_end_pos_ -= 40;
+/* Returns amount of unread bytes the bit reader still has buffered from the
+   BrotliInput, including whole bytes in br->val_. */
+static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
+  return br->avail_in + sizeof(br->val_) - (br->bit_pos_ >> 3);
+}
+
+/* Checks if there is at least num bytes left in the input ringbuffer (excluding
+   the bits remaining in br->val_). The maximum value for num is
+   BROTLI_IMPLICIT_ZEROES bytes. */
+static BROTLI_INLINE int BrotliCheckInputAmount(
+    BrotliBitReader* const br, size_t num) {
+  return br->avail_in >= num;
+}
+
+/* Guarantees that there are at least n_bits in the buffer.
+   n_bits should be in the range [1..24] */
+static BROTLI_INLINE void BrotliFillBitWindow(
+    BrotliBitReader* const br, int n_bits) {
+#if (BROTLI_64_BITS_LITTLE_ENDIAN)
+  if (IS_CONSTANT(n_bits) && n_bits <= 8) {
+    if (br->bit_pos_ >= 56) {
+      br->val_ >>= 56;
+      br->bit_pos_ ^= 56;  /* here same as -= 56 because of the if condition */
+      br->val_ |= (*(const uint64_t*)(br->next_in)) << 8;
+      br->avail_in -= 7;
+      br->next_in += 7;
+    }
+  } else if (IS_CONSTANT(n_bits) && n_bits <= 16) {
+    if (br->bit_pos_ >= 48) {
+      br->val_ >>= 48;
+      br->bit_pos_ ^= 48;  /* here same as -= 48 because of the if condition */
+      br->val_ |= (*(const uint64_t*)(br->next_in)) << 16;
+      br->avail_in -= 6;
+      br->next_in += 6;
+    }
+  } else {
+    if (br->bit_pos_ >= 32) {
+      br->val_ >>= 32;
+      br->bit_pos_ ^= 32;  /* here same as -= 32 because of the if condition */
+      br->val_ |= ((uint64_t)(*(const uint32_t*)(br->next_in))) << 32;
+      br->avail_in -= 4;
+      br->next_in += 4;
+    }
+  }
+#elif (BROTLI_LITTLE_ENDIAN)
+  if (IS_CONSTANT(n_bits) && n_bits <= 8) {
+    if (br->bit_pos_ >= 24) {
+      br->val_ >>= 24;
+      br->bit_pos_ ^= 24;  /* here same as -= 24 because of the if condition */
+      br->val_ |= (*(const uint32_t*)(br->next_in)) << 8;
+      br->avail_in -= 3;
+      br->next_in += 3;
+    }
+  } else {
+    if (br->bit_pos_ >= 16) {
+      br->val_ >>= 16;
+      br->bit_pos_ ^= 16;  /* here same as -= 16 because of the if condition */
+      br->val_ |= ((uint32_t)(*(const uint16_t*)(br->next_in))) << 16;
+      br->avail_in -= 2;
+      br->next_in += 2;
+    }
+    if (!IS_CONSTANT(n_bits) || (n_bits > 16)) {
+      if (br->bit_pos_ >= 8) {
+        br->val_ >>= 8;
+        br->bit_pos_ ^= 8;  /* here same as -= 8 because of the if condition */
+        br->val_ |= ((uint32_t)*br->next_in) << 24;
+        --br->avail_in;
+        ++br->next_in;
+      }
+    }
   }
 #else
-  ShiftBytes32(br);
+  while (br->bit_pos_ >= 8) {
+    br->val_ >>= 8;
+    br->val_ |= ((uint32_t)*br->next_in) << 24;
+    br->bit_pos_ -= 8;
+    --br->avail_in;
+    ++br->next_in;
+  }
 #endif
 }
 
-/* Reads the specified number of bits from Read Buffer. */
+/* Like BrotliGetBits, but does not mask the result, it is only guaranteed
+that it has minimum n_bits. */
+static BROTLI_INLINE uint32_t BrotliGetBitsUnmasked(
+    BrotliBitReader* const br, int n_bits) {
+  BrotliFillBitWindow(br, n_bits);
+  return (uint32_t)(br->val_ >> br->bit_pos_);
+}
+
+/* Returns the specified number of bits from br without advancing bit pos. */
+static BROTLI_INLINE uint32_t BrotliGetBits(
+    BrotliBitReader* const br, int n_bits) {
+  BrotliFillBitWindow(br, n_bits);
+  return (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
+}
+
+/* Advances the bit pos by n_bits. */
+static BROTLI_INLINE void BrotliDropBits(
+    BrotliBitReader* const br, int n_bits) {
+  br->bit_pos_ += (uint32_t)n_bits;
+}
+
+/* Reads the specified number of bits from br and advances the bit pos. */
 static BROTLI_INLINE uint32_t BrotliReadBits(
     BrotliBitReader* const br, int n_bits) {
   uint32_t val;
-#if (BROTLI_USE_64_BITS)
-  BrotliFillBitWindow(br);
-  val = (uint32_t)(br->val_ >> br->bit_pos_) & kBitMask[n_bits];
-#else
-  /*
-   * The if statement gives 2-4% speed boost on Canterbury data set with
-   * asm.js/firefox/x86-64.
-   */
-  if ((32 - br->bit_pos_) < ((uint32_t) n_bits)) {
-    BrotliFillBitWindow(br);
-  }
-  val = (br->val_ >> br->bit_pos_) & kBitMask[n_bits];
-#endif
+  BrotliFillBitWindow(br, n_bits);
+  val = (uint32_t)(br->val_ >> br->bit_pos_) & BitMask(n_bits);
 #ifdef BROTLI_DECODE_DEBUG
-  printf("[BrotliReadBits]  %010d %2d  val: %6x\n",
-         (br->pos_ << 3) + br->bit_pos_ - 64, n_bits, val);
+  printf("[BrotliReadBits]  %d %d %d val: %6x\n",
+         (int)br->avail_in, (int)br->bit_pos_, n_bits, val);
 #endif
   br->bit_pos_ += (uint32_t)n_bits;
   return val;
 }
 
+/* Advances the bit reader position to the next byte boundary and verifies
+   that any skipped bits are set to zero. */
+static BROTLI_INLINE int BrotliJumpToByteBoundary(BrotliBitReader* br) {
+  uint32_t new_bit_pos = (br->bit_pos_ + 7) & (uint32_t)(~7UL);
+  uint32_t pad_bits = BrotliReadBits(br, (int)(new_bit_pos - br->bit_pos_));
+  return pad_bits == 0;
+}
+
+/* Copies remaining input bytes stored in the bit reader to the output. Value
+   num may not be larger than BrotliGetRemainingBytes. The bit reader must be
+   warmed up again after this. */
+static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
+                                          BrotliBitReader* br, size_t num) {
+  while (br->bit_pos_ + 8 <= (BROTLI_64_BITS_LITTLE_ENDIAN ? 64 : 32)
+      && num > 0) {
+    *dest = (uint8_t)(br->val_ >> br->bit_pos_);
+    br->bit_pos_ += 8;
+    ++dest;
+    --num;
+  }
+  memcpy(dest, br->next_in, num);
+  br->avail_in -= (uint32_t)num;
+  br->next_in += num;
+  br->bit_pos_ = 0;
+}
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }    /* extern "C" */
 #endif
 
 #endif  /* BROTLI_DEC_BIT_READER_H_ */
--- a/modules/brotli/dec/context.h
+++ b/modules/brotli/dec/context.h
@@ -6,18 +6,19 @@
 
    http://www.apache.org/licenses/LICENSE-2.0
 
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
+*/
 
-   Lookup table to map the previous two bytes to a context id.
+/* Lookup table to map the previous two bytes to a context id.
 
    There are four different context modeling modes defined here:
      CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
      CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
      CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
      CONTEXT_SIGNED: second-order context model tuned for signed integers.
 
    The context id for the UTF8 context model is calculated as follows. If p1
--- a/modules/brotli/dec/decode.c
+++ b/modules/brotli/dec/decode.c
@@ -15,634 +15,729 @@
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include "./bit_reader.h"
 #include "./context.h"
 #include "./decode.h"
 #include "./dictionary.h"
+#include "./port.h"
 #include "./transform.h"
 #include "./huffman.h"
 #include "./prefix.h"
-#include "./safe_malloc.h"
+
+#ifdef __ARM_NEON__
+#include <arm_neon.h>
+#endif
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
 #ifdef BROTLI_DECODE_DEBUG
 #define BROTLI_LOG_UINT(name)                                    \
   printf("[%s] %s = %lu\n", __func__, #name, (unsigned long)(name))
 #define BROTLI_LOG_ARRAY_INDEX(array_name, idx)                  \
   printf("[%s] %s[%lu] = %lu\n", __func__, #array_name, \
          (unsigned long)(idx), (unsigned long)array_name[idx])
+#define BROTLI_LOG(x) printf x
 #else
 #define BROTLI_LOG_UINT(name)
 #define BROTLI_LOG_ARRAY_INDEX(array_name, idx)
+#define BROTLI_LOG(x)
 #endif
 
 static const uint8_t kDefaultCodeLength = 8;
 static const uint8_t kCodeLengthRepeatCode = 16;
 static const int kNumLiteralCodes = 256;
 static const int kNumInsertAndCopyCodes = 704;
 static const int kNumBlockLengthCodes = 26;
 static const int kLiteralContextBits = 6;
 static const int kDistanceContextBits = 2;
 
 #define HUFFMAN_TABLE_BITS      8
 #define HUFFMAN_TABLE_MASK      0xff
-/* Maximum possible Huffman table size for an alphabet size of 704, max code
- * length 15 and root table bits 8. */
-#define HUFFMAN_MAX_TABLE_SIZE  1080
 
 #define CODE_LENGTH_CODES 18
 static const uint8_t kCodeLengthCodeOrder[CODE_LENGTH_CODES] = {
   1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,
 };
 
 #define NUM_DISTANCE_SHORT_CODES 16
-static const int kDistanceShortCodeIndexOffset[NUM_DISTANCE_SHORT_CODES] = {
-  3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2
-};
+
 
-static const int kDistanceShortCodeValueOffset[NUM_DISTANCE_SHORT_CODES] = {
-  0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
-};
-
-static BROTLI_INLINE int DecodeWindowBits(BrotliBitReader* br) {
-  if (BrotliReadBits(br, 1)) {
-    return 17 + (int)BrotliReadBits(br, 3);
-  } else {
+static uint32_t DecodeWindowBits(BrotliBitReader* br) {
+  uint32_t n;
+  if (BrotliReadBits(br, 1) == 0) {
     return 16;
   }
+  n = BrotliReadBits(br, 3);
+  if (n != 0) {
+    return 17 + n;
+  }
+  n = BrotliReadBits(br, 3);
+  if (n != 0) {
+    return 8 + n;
+  }
+  return 17;
+}
+
+static BROTLI_INLINE BROTLI_NO_ASAN void memmove16(
+    uint8_t* dst, uint8_t* src) {
+#ifdef __ARM_NEON__
+  vst1q_u8(dst, vld1q_u8(src));
+#else
+  /* memcpy is unsafe for overlapping regions and ASAN detects this.
+     But, because of optimizations, it works exactly as memmove:
+     copies data to registers first, and then stores them to dst. */
+  memcpy(dst, src, 16);
+#endif
 }
 
 /* Decodes a number in the range [0..255], by reading 1 - 11 bits. */
 static BROTLI_INLINE int DecodeVarLenUint8(BrotliBitReader* br) {
   if (BrotliReadBits(br, 1)) {
     int nbits = (int)BrotliReadBits(br, 3);
     if (nbits == 0) {
       return 1;
     } else {
       return (int)BrotliReadBits(br, nbits) + (1 << nbits);
     }
   }
   return 0;
 }
 
-static void DecodeMetaBlockLength(BrotliBitReader* br,
-                                  int* meta_block_length,
-                                  int* input_end,
-                                  int* is_uncompressed) {
+static BrotliResult DecodeMetaBlockLength(BrotliBitReader* br,
+                                          int* meta_block_length,
+                                          int* input_end,
+                                          int* is_metadata,
+                                          int* is_uncompressed) {
   int size_nibbles;
+  int size_bytes;
   int i;
   *input_end = (int)BrotliReadBits(br, 1);
   *meta_block_length = 0;
   *is_uncompressed = 0;
+  *is_metadata = 0;
   if (*input_end && BrotliReadBits(br, 1)) {
-    return;
+    return BROTLI_RESULT_SUCCESS;
   }
   size_nibbles = (int)BrotliReadBits(br, 2) + 4;
-  for (i = 0; i < size_nibbles; ++i) {
-    *meta_block_length |= (int)BrotliReadBits(br, 4) << (i * 4);
+  if (size_nibbles == 7) {
+    *is_metadata = 1;
+    /* Verify reserved bit. */
+    if (BrotliReadBits(br, 1) != 0) {
+      return BROTLI_FAILURE();
+    }
+    size_bytes = (int)BrotliReadBits(br, 2);
+    if (size_bytes == 0) {
+      return BROTLI_RESULT_SUCCESS;
+    }
+    for (i = 0; i < size_bytes; ++i) {
+      int next_byte = (int)BrotliReadBits(br, 8);
+      if (i + 1 == size_bytes && size_bytes > 1 && next_byte == 0) {
+        return BROTLI_FAILURE();
+      }
+      *meta_block_length |= next_byte << (i * 8);
+    }
+  } else {
+    for (i = 0; i < size_nibbles; ++i) {
+      int next_nibble = (int)BrotliReadBits(br, 4);
+      if (i + 1 == size_nibbles && size_nibbles > 4 && next_nibble == 0) {
+        return BROTLI_FAILURE();
+      }
+      *meta_block_length |= next_nibble << (i * 4);
+    }
   }
   ++(*meta_block_length);
-  if (!*input_end) {
+  if (!*input_end && !*is_metadata) {
     *is_uncompressed = (int)BrotliReadBits(br, 1);
   }
+  return BROTLI_RESULT_SUCCESS;
 }
 
 /* Decodes the next Huffman code from bit-stream. */
 static BROTLI_INLINE int ReadSymbol(const HuffmanCode* table,
                                     BrotliBitReader* br) {
-  int nbits;
-  BrotliFillBitWindow(br);
-  table += (int)(br->val_ >> br->bit_pos_) & HUFFMAN_TABLE_MASK;
-  nbits = table->bits - HUFFMAN_TABLE_BITS;
-  if (nbits > 0) {
-    br->bit_pos_ += HUFFMAN_TABLE_BITS;
+  /* Read the bits for two reads at once. */
+  uint32_t val = BrotliGetBitsUnmasked(br, 15);
+  table += val & HUFFMAN_TABLE_MASK;
+  if (table->bits > HUFFMAN_TABLE_BITS) {
+    int nbits = table->bits - HUFFMAN_TABLE_BITS;
+    BrotliDropBits(br, HUFFMAN_TABLE_BITS);
     table += table->value;
-    table += (int)(br->val_ >> br->bit_pos_) & ((1 << nbits) - 1);
+    table += (int)(val >> HUFFMAN_TABLE_BITS) & (int)BitMask(nbits);
   }
-  br->bit_pos_ += table->bits;
+  BrotliDropBits(br, table->bits);
   return table->value;
 }
 
-static void PrintUcharVector(const uint8_t* v, int len) {
-  while (len-- > 0) printf(" %d", *v++);
-  printf("\n");
+static BROTLI_INLINE void PreloadSymbol(const HuffmanCode* table,
+                                        BrotliBitReader* br,
+                                        unsigned* bits,
+                                        unsigned* value) {
+  table += BrotliGetBits(br, HUFFMAN_TABLE_BITS);
+  *bits = table->bits;
+  *value = table->value;
+}
+
+static BROTLI_INLINE unsigned ReadPreloadedSymbol(const HuffmanCode* table,
+                                                  BrotliBitReader* br,
+                                                  unsigned* bits,
+                                                  unsigned* value) {
+  unsigned result = *value;
+  if (PREDICT_FALSE(*bits > HUFFMAN_TABLE_BITS)) {
+    uint32_t val = BrotliGetBitsUnmasked(br, 15);
+    const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value;
+    int mask = (int)BitMask((int)(*bits - HUFFMAN_TABLE_BITS));
+    BrotliDropBits(br, HUFFMAN_TABLE_BITS);
+    ext += (int)(val >> HUFFMAN_TABLE_BITS) & mask;
+    BrotliDropBits(br, ext->bits);
+    result = ext->value;
+  } else {
+    BrotliDropBits(br, (int)*bits);
+  }
+  PreloadSymbol(table, br, bits, value);
+  return result;
 }
 
-static int ReadHuffmanCodeLengths(
-    const uint8_t* code_length_code_lengths,
-    int num_symbols, uint8_t* code_lengths,
-    BrotliBitReader* br) {
-  int symbol = 0;
-  uint8_t prev_code_len = kDefaultCodeLength;
-  int repeat = 0;
-  uint8_t repeat_code_len = 0;
-  int space = 32768;
-  HuffmanCode table[32];
+static BrotliResult ReadHuffmanCode(int alphabet_size,
+                                    HuffmanCode* table,
+                                    int* opt_table_size,
+                                    BrotliState* s) {
+  BrotliBitReader* br = &s->br;
+  /* simple_code_or_skip is used as follows:
+     1 for simple code;
+     0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
+  int simple_code_or_skip;
+  unsigned symbol = s->symbol;
+  uint32_t repeat = s->repeat;
+  uint8_t prev_code_len = s->prev_code_len;
+  uint8_t repeat_code_len = s->repeat_code_len;
+  uint32_t space = s->space;
+  uint16_t* symbol_lists = s->symbol_lists;
+  int* next_symbol = s->next_symbol;
+  int i = 0;
+  /* Unnecessary masking, but might be good for safety. */
+  alphabet_size &= 0x3ff;
+  /* State machine */
+  if (s->sub1_state == BROTLI_STATE_SUB1_NONE) {
+    if (!BrotliCheckInputAmount(br, 32)) {
+      return BROTLI_RESULT_NEEDS_MORE_INPUT;
+    }
+    simple_code_or_skip = (int)BrotliReadBits(br, 2);
+    BROTLI_LOG_UINT(simple_code_or_skip);
+    if (simple_code_or_skip == 1) {
+      /* Read symbols, codes & code lengths directly. */
+      int table_size;
+      int max_bits_counter = alphabet_size - 1;
+      int max_bits = 0;
+      uint16_t symbols[4] = { 0 };
+      uint32_t num_symbols = BrotliReadBits(br, 2);
+      i = 0;
+      while (max_bits_counter) {
+        max_bits_counter >>= 1;
+        ++max_bits;
+      }
+      do {
+        int k;
+        uint32_t v = BrotliReadBits(br, max_bits);
+        if (v >= alphabet_size) {
+          return BROTLI_FAILURE();
+        }
+        symbols[i] = (uint16_t)v;
+        for (k = 0; k < i; k++) {
+          if (symbols[k] == (uint16_t)v) {
+            return BROTLI_FAILURE();
+          }
+        }
+      } while (++i <= num_symbols);
+      if (num_symbols == 3) {
+        num_symbols += BrotliReadBits(br, 1);
+      }
+      BROTLI_LOG_UINT(num_symbols);
+      table_size = BrotliBuildSimpleHuffmanTable(
+          table, HUFFMAN_TABLE_BITS, symbols, num_symbols);
+      if (opt_table_size) {
+        *opt_table_size = table_size;
+      }
+      s->sub1_state = BROTLI_STATE_SUB1_NONE;
+      return BROTLI_RESULT_SUCCESS;
+    } else {  /* Decode Huffman-coded code lengths. */
+      int i;
+      int8_t num_codes = 0;
+      /* Static Huffman code for the code length code lengths. */
+      static const uint8_t huff_len[16] = {
+        2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 4,
+      };
+      static const uint8_t huff_val[16] = {
+        0, 4, 3, 2, 0, 4, 3, 1, 0, 4, 3, 2, 0, 4, 3, 5,
+      };
+      space = 32;
+      memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo));
+      memset(&s->code_length_code_lengths[0], 0,
+             sizeof(s->code_length_code_lengths));
+      for (i = simple_code_or_skip;
+           i < CODE_LENGTH_CODES; ++i) {
+        const uint8_t code_len_idx = kCodeLengthCodeOrder[i];
+        uint8_t ix = (uint8_t)BrotliGetBits(br, 4);
+        uint8_t v = huff_val[ix];
+        BrotliDropBits(br, huff_len[ix]);
+        s->code_length_code_lengths[code_len_idx] = v;
+        BROTLI_LOG_ARRAY_INDEX(s->code_length_code_lengths, code_len_idx);
+        if (v != 0) {
+          space = space - (32U >> v);
+          ++num_codes;
+          ++s->code_length_histo[v];
+          if (space - 1U >= 32U) {
+            /* space is 0 or wrapped around */
+            break;
+          }
+        }
+      }
+      if (!(num_codes == 1 || space == 0)) {
+        return BROTLI_FAILURE();
+      }
+    }
+    BrotliBuildCodeLengthsHuffmanTable(s->table,
+                                       s->code_length_code_lengths,
+                                       s->code_length_histo);
+    memset(&s->code_length_histo[0], 0, sizeof(s->code_length_histo));
+    for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) {
+      next_symbol[i] = i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
+      symbol_lists[i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1)] = 0xFFFF;
+    }
 
-  if (!BrotliBuildHuffmanTable(table, 5,
-                               code_length_code_lengths,
-                               CODE_LENGTH_CODES)) {
-    printf("[ReadHuffmanCodeLengths] Building code length tree failed: ");
-    PrintUcharVector(code_length_code_lengths, CODE_LENGTH_CODES);
-    return 0;
+    symbol = 0;
+    prev_code_len = kDefaultCodeLength;
+    repeat = 0;
+    repeat_code_len = 0;
+    space = 32768;
+    s->sub1_state = BROTLI_STATE_SUB1_HUFFMAN_LENGTH_SYMBOLS;
   }
 
-  while (symbol < num_symbols && space > 0) {
-    const HuffmanCode* p = table;
-    uint8_t code_len;
-    if (!BrotliReadMoreInput(br)) {
-      printf("[ReadHuffmanCodeLengths] Unexpected end of input.\n");
-      return 0;
+  while (symbol < alphabet_size && space > 0) {
+    uint32_t milestone;
+    if (!BrotliCheckInputAmount(br, 128)) {
+      s->symbol = (uint32_t)symbol;
+      s->repeat = repeat;
+      s->prev_code_len = prev_code_len;
+      s->repeat_code_len = repeat_code_len;
+      s->space = space;
+      return BROTLI_RESULT_NEEDS_MORE_INPUT;
+    }
+    /* We use at most 5 bits per symbol. 128 * 8 / 5 = 204.8 */
+    milestone = symbol + 204;
+    if (milestone > alphabet_size) {
+      milestone = (uint32_t)alphabet_size;
     }
-    BrotliFillBitWindow(br);
-    p += (br->val_ >> br->bit_pos_) & 31;
-    br->bit_pos_ += p->bits;
-    code_len = (uint8_t)p->value;
-    if (code_len < kCodeLengthRepeatCode) {
-      repeat = 0;
-      code_lengths[symbol++] = code_len;
-      if (code_len != 0) {
-        prev_code_len = code_len;
-        space -= 32768 >> code_len;
-      }
-    } else {
-      const int extra_bits = code_len - 14;
-      int old_repeat;
-      int repeat_delta;
-      uint8_t new_len = 0;
-      if (code_len == kCodeLengthRepeatCode) {
-        new_len =  prev_code_len;
-      }
-      if (repeat_code_len != new_len) {
+    while (symbol < milestone && space > 0) {
+      const HuffmanCode* p = s->table;
+      uint8_t code_len;
+      p += BrotliGetBits(br, BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
+      BrotliDropBits(br, p->bits);
+      code_len = (uint8_t)p->value;
+      if (code_len < kCodeLengthRepeatCode) {
         repeat = 0;
-        repeat_code_len = new_len;
-      }
-      old_repeat = repeat;
-      if (repeat > 0) {
-        repeat -= 2;
-        repeat <<= extra_bits;
-      }
-      repeat += (int)BrotliReadBits(br, extra_bits) + 3;
-      repeat_delta = repeat - old_repeat;
-      if (symbol + repeat_delta > num_symbols) {
-        return 0;
-      }
-      memset(&code_lengths[symbol], repeat_code_len, (size_t)repeat_delta);
-      symbol += repeat_delta;
-      if (repeat_code_len != 0) {
-        space -= repeat_delta << (15 - repeat_code_len);
+        if (code_len != 0) {
+          symbol_lists[next_symbol[code_len]] = (uint16_t)symbol;
+          next_symbol[code_len] = (int)symbol;
+          prev_code_len = code_len;
+          space -= 32768U >> code_len;
+          s->code_length_histo[code_len]++;
+        }
+        symbol++;
+      } else {
+        const int extra_bits = code_len - 14;
+        uint32_t old_repeat;
+        uint32_t repeat_delta;
+        uint8_t new_len = 0;
+        if (code_len == kCodeLengthRepeatCode) {
+          new_len = prev_code_len;
+        }
+        if (repeat_code_len != new_len) {
+          repeat = 0;
+          repeat_code_len = new_len;
+        }
+        old_repeat = repeat;
+        if (repeat > 0) {
+          repeat -= 2;
+          repeat <<= extra_bits;
+        }
+        repeat += BrotliReadBits(br, extra_bits) + 3;
+        repeat_delta = repeat - old_repeat;
+        if (symbol + repeat_delta > alphabet_size) {
+          return BROTLI_FAILURE();
+        }
+        if (repeat_code_len != 0) {
+          unsigned last = symbol + repeat_delta;
+          i = next_symbol[repeat_code_len];
+          do {
+            symbol_lists[i] = (uint16_t)symbol;
+            i = (int)symbol;
+          } while (++symbol != last);
+          next_symbol[repeat_code_len] = i;
+          space -= repeat_delta << (15 - repeat_code_len);
+          s->code_length_histo[repeat_code_len] = (uint16_t)
+              (s->code_length_histo[repeat_code_len] + repeat_delta);
+        } else {
+          symbol += repeat_delta;
+        }
       }
     }
   }
   if (space != 0) {
-    printf("[ReadHuffmanCodeLengths] space = %d\n", space);
-    return 0;
-  }
-  memset(&code_lengths[symbol], 0, (size_t)(num_symbols - symbol));
-  return 1;
-}
-
-static int ReadHuffmanCode(int alphabet_size,
-                           HuffmanCode* table,
-                           BrotliBitReader* br) {
-  int ok = 1;
-  int table_size = 0;
-  int simple_code_or_skip;
-  uint8_t* code_lengths = NULL;
-
-  code_lengths =
-      (uint8_t*)BrotliSafeMalloc((uint64_t)alphabet_size,
-                                 sizeof(*code_lengths));
-  if (code_lengths == NULL) {
-    return 0;
-  }
-  if (!BrotliReadMoreInput(br)) {
-    printf("[ReadHuffmanCode] Unexpected end of input.\n");
-    return 0;
+    BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", space));
+    return BROTLI_FAILURE();
   }
-  /* simple_code_or_skip is used as follows:
-     1 for simple code;
-     0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */
-  simple_code_or_skip = (int)BrotliReadBits(br, 2);
-  BROTLI_LOG_UINT(simple_code_or_skip);
-  if (simple_code_or_skip == 1) {
-    /* Read symbols, codes & code lengths directly. */
-    int i;
-    int max_bits_counter = alphabet_size - 1;
-    int max_bits = 0;
-    int symbols[4] = { 0 };
-    const int num_symbols = (int)BrotliReadBits(br, 2) + 1;
-    while (max_bits_counter) {
-      max_bits_counter >>= 1;
-      ++max_bits;
-    }
-    memset(code_lengths, 0, (size_t)alphabet_size);
-    for (i = 0; i < num_symbols; ++i) {
-      symbols[i] = (int)BrotliReadBits(br, max_bits) % alphabet_size;
-      code_lengths[symbols[i]] = 2;
-    }
-    code_lengths[symbols[0]] = 1;
-    switch (num_symbols) {
-      case 1:
-        break;
-      case 3:
-        ok = ((symbols[0] != symbols[1]) &&
-              (symbols[0] != symbols[2]) &&
-              (symbols[1] != symbols[2]));
-        break;
-      case 2:
-        ok = (symbols[0] != symbols[1]);
-        code_lengths[symbols[1]] = 1;
-        break;
-      case 4:
-        ok = ((symbols[0] != symbols[1]) &&
-              (symbols[0] != symbols[2]) &&
-              (symbols[0] != symbols[3]) &&
-              (symbols[1] != symbols[2]) &&
-              (symbols[1] != symbols[3]) &&
-              (symbols[2] != symbols[3]));
-        if (BrotliReadBits(br, 1)) {
-          code_lengths[symbols[2]] = 3;
-          code_lengths[symbols[3]] = 3;
-        } else {
-          code_lengths[symbols[0]] = 2;
-        }
-        break;
-    }
-    BROTLI_LOG_UINT(num_symbols);
-  } else {  /* Decode Huffman-coded code lengths. */
-    int i;
-    uint8_t code_length_code_lengths[CODE_LENGTH_CODES] = { 0 };
-    int space = 32;
-    int num_codes = 0;
-    /* Static Huffman code for the code length code lengths */
-    static const HuffmanCode huff[16] = {
-      {2, 0}, {2, 4}, {2, 3}, {3, 2}, {2, 0}, {2, 4}, {2, 3}, {4, 1},
-      {2, 0}, {2, 4}, {2, 3}, {3, 2}, {2, 0}, {2, 4}, {2, 3}, {4, 5},
-    };
-    for (i = simple_code_or_skip; i < CODE_LENGTH_CODES && space > 0; ++i) {
-      const int code_len_idx = kCodeLengthCodeOrder[i];
-      const HuffmanCode* p = huff;
-      uint8_t v;
-      BrotliFillBitWindow(br);
-      p += (br->val_ >> br->bit_pos_) & 15;
-      br->bit_pos_ += p->bits;
-      v = (uint8_t)p->value;
-      code_length_code_lengths[code_len_idx] = v;
-      BROTLI_LOG_ARRAY_INDEX(code_length_code_lengths, code_len_idx);
-      if (v != 0) {
-        space -= (32 >> v);
-        ++num_codes;
-      }
-    }
-    ok = (num_codes == 1 || space == 0) &&
-        ReadHuffmanCodeLengths(code_length_code_lengths,
-                               alphabet_size, code_lengths, br);
-  }
-  if (ok) {
-    table_size = BrotliBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
-                                         code_lengths, alphabet_size);
-    if (table_size == 0) {
-      printf("[ReadHuffmanCode] BuildHuffmanTable failed: ");
-      PrintUcharVector(code_lengths, alphabet_size);
+  {
+    int table_size = BrotliBuildHuffmanTable(
+        table, HUFFMAN_TABLE_BITS, symbol_lists,
+        s->code_length_histo);
+    if (opt_table_size) {
+      *opt_table_size = table_size;
     }
   }
-  free(code_lengths);
-  return table_size;
+  s->sub1_state = BROTLI_STATE_SUB1_NONE;
+  return BROTLI_RESULT_SUCCESS;
 }
 
 static BROTLI_INLINE int ReadBlockLength(const HuffmanCode* table,
                                          BrotliBitReader* br) {
   int code;
   int nbits;
   code = ReadSymbol(table, br);
   nbits = kBlockLengthPrefixCode[code].nbits;
   return kBlockLengthPrefixCode[code].offset + (int)BrotliReadBits(br, nbits);
 }
 
-static int TranslateShortCodes(int code, int* ringbuffer, int index) {
-  int val;
-  if (code < NUM_DISTANCE_SHORT_CODES) {
-    index += kDistanceShortCodeIndexOffset[code];
-    index &= 3;
-    val = ringbuffer[index] + kDistanceShortCodeValueOffset[code];
-  } else {
-    val = code - NUM_DISTANCE_SHORT_CODES + 1;
-  }
-  return val;
-}
+/* Transform:
+    1) initialize list L with values 0, 1,... 255
+    2) For each input element X:
+    2.1) let Y = L[X]
+    2.2) remove X-th element from L
+    2.3) prepend Y to L
+    2.4) append Y to output
+
+   In most cases max(Y) <= 7, so most of L remains intact.
+   To reduce the cost of initialization, we reuse L, remember the upper bound
+   of Y values, and reinitialize only first elements in L.
 
-static void MoveToFront(uint8_t* v, uint8_t index) {
-  uint8_t value = v[index];
-  uint8_t i = index;
-  for (; i; --i) v[i] = v[i - 1];
-  v[0] = value;
-}
+   Most of input values are 0 and 1. To reduce number of brances, we replace
+   inner for loop with do-while.
+ */
+static BROTLI_NOINLINE void InverseMoveToFrontTransform(uint8_t* v, int v_len,
+    BrotliState* state) {
+  /* Reinitialize elements that could have been changed. */
+  int i = 4;
+  int upper_bound = state->mtf_upper_bound;
+  uint8_t* mtf = state->mtf;
+  /* Load endian-aware constant. */
+  const uint8_t b0123[4] = {0, 1, 2, 3};
+  uint32_t pattern;
+  memcpy(&pattern, &b0123, 4);
 
-static void InverseMoveToFrontTransform(uint8_t* v, int v_len) {
-  uint8_t mtf[256];
-  int i;
-  for (i = 0; i < 256; ++i) {
-    mtf[i] = (uint8_t)i;
+  /* Initialize list using 4 consequent values pattern. */
+  *(uint32_t*)mtf = pattern;
+  do {
+    pattern += 0x04040404; /* Advance all 4 values by 4. */
+    *(uint32_t*)(mtf + i) = pattern;
+    i += 4;
+  } while (i <= upper_bound);
+
+  /* Transform the input. */
+  upper_bound = 0;
+  for (i = 0; i < v_len; ++i) {
+    int index = v[i];
+    uint8_t value = mtf[index];
+    v[i] = value;
+    upper_bound |= index;
+    do {
+      index--;
+      mtf[index + 1] = mtf[index];
+    } while (index > 0);
+    mtf[0] = value;
   }
-  for (i = 0; i < v_len; ++i) {
-    uint8_t index = v[i];
-    v[i] = mtf[index];
-    if (index) MoveToFront(mtf, index);
-  }
+  /* Remember amount of elements to be reinitialized. */
+  state->mtf_upper_bound = upper_bound;
 }
 
-/* Contains a collection of huffman trees with the same alphabet size. */
-typedef struct {
-  int alphabet_size;
-  int num_htrees;
-  HuffmanCode* codes;
-  HuffmanCode** htrees;
-} HuffmanTreeGroup;
-
-static void HuffmanTreeGroupInit(HuffmanTreeGroup* group, int alphabet_size,
-                                 int ntrees) {
-  group->alphabet_size = alphabet_size;
-  group->num_htrees = ntrees;
-  group->codes = (HuffmanCode*)malloc(
-      sizeof(HuffmanCode) * (size_t)(ntrees * HUFFMAN_MAX_TABLE_SIZE));
-  group->htrees = (HuffmanCode**)malloc(sizeof(HuffmanCode*) * (size_t)ntrees);
+/* Expose function for testing. Will be removed by linker as unused. */
+void InverseMoveToFrontTransformForTesting(uint8_t* v, int l, BrotliState* s) {
+  InverseMoveToFrontTransform(v, l, s);
 }
 
-static void HuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
-  if (group->codes) {
-    free(group->codes);
-  }
-  if (group->htrees) {
-    free(group->htrees);
+
+static BrotliResult HuffmanTreeGroupDecode(HuffmanTreeGroup* group,
+                                           BrotliState* s) {
+  if (s->sub0_state != BROTLI_STATE_SUB0_TREE_GROUP) {
+    s->next = group->codes;
+    s->htree_index = 0;
+    s->sub0_state = BROTLI_STATE_SUB0_TREE_GROUP;
   }
-}
-
-static int HuffmanTreeGroupDecode(HuffmanTreeGroup* group,
-                                  BrotliBitReader* br) {
-  int i;
-  int table_size;
-  HuffmanCode* next = group->codes;
-  for (i = 0; i < group->num_htrees; ++i) {
-    group->htrees[i] = next;
-    table_size = ReadHuffmanCode(group->alphabet_size, next, br);
-    next += table_size;
+  while (s->htree_index < group->num_htrees) {
+    int table_size;
+    BrotliResult result =
+        ReadHuffmanCode(group->alphabet_size, s->next, &table_size, s);
+    if (result != BROTLI_RESULT_SUCCESS) return result;
+    group->htrees[s->htree_index] = s->next;
+    s->next += table_size;
     if (table_size == 0) {
-      return 0;
+      return BROTLI_FAILURE();
     }
+    ++s->htree_index;
   }
-  return 1;
+  s->sub0_state = BROTLI_STATE_SUB0_NONE;
+  return BROTLI_RESULT_SUCCESS;
 }
 
-static int DecodeContextMap(int context_map_size,
-                            int* num_htrees,
-                            uint8_t** context_map,
-                            BrotliBitReader* br) {
-  int ok = 1;
+static BrotliResult DecodeContextMap(int context_map_size,
+                                     int* num_htrees,
+                                     uint8_t** context_map_arg,
+                                     BrotliState* s) {
+  BrotliBitReader* br = &s->br;
+  BrotliResult result = BROTLI_RESULT_SUCCESS;
   int use_rle_for_zeros;
-  int max_run_length_prefix = 0;
-  HuffmanCode* table;
-  int i;
-  if (!BrotliReadMoreInput(br)) {
-    printf("[DecodeContextMap] Unexpected end of input.\n");
-    return 0;
-  }
-  *num_htrees = DecodeVarLenUint8(br) + 1;
 
-  BROTLI_LOG_UINT(context_map_size);
-  BROTLI_LOG_UINT(*num_htrees);
-
-  *context_map = (uint8_t*)malloc((size_t)context_map_size);
-  if (*context_map == 0) {
-    return 0;
-  }
-  if (*num_htrees <= 1) {
-    memset(*context_map, 0, (size_t)context_map_size);
-    return 1;
+  switch((int)s->sub0_state) {
+    case BROTLI_STATE_SUB0_NONE:
+      if (!BrotliCheckInputAmount(br, 32)) {
+        return BROTLI_RESULT_NEEDS_MORE_INPUT;
+      }
+      *num_htrees = DecodeVarLenUint8(br) + 1;
+      s->context_index = 0;
+      BROTLI_LOG_UINT(context_map_size);
+      BROTLI_LOG_UINT(*num_htrees);
+      *context_map_arg = (uint8_t*)malloc((size_t)context_map_size);
+      if (*context_map_arg == 0) {
+        return BROTLI_FAILURE();
+      }
+      if (*num_htrees <= 1) {
+        memset(*context_map_arg, 0, (size_t)context_map_size);
+        return BROTLI_RESULT_SUCCESS;
+      }
+      use_rle_for_zeros = (int)BrotliReadBits(br, 1);
+      if (use_rle_for_zeros) {
+        s->max_run_length_prefix = (int)BrotliReadBits(br, 4) + 1;
+      } else {
+        s->max_run_length_prefix = 0;
+      }
+      s->sub0_state = BROTLI_STATE_SUB0_CONTEXT_MAP_HUFFMAN;
+      /* No break, continue to next state. */
+    case BROTLI_STATE_SUB0_CONTEXT_MAP_HUFFMAN:
+      result = ReadHuffmanCode(*num_htrees + s->max_run_length_prefix,
+                               s->context_map_table, NULL, s);
+      if (result != BROTLI_RESULT_SUCCESS) return result;
+      s->sub0_state = BROTLI_STATE_SUB0_CONTEXT_MAPS;
+      /* No break, continue to next state. */
+    case BROTLI_STATE_SUB0_CONTEXT_MAPS: {
+      int context_index = s->context_index;
+      int max_run_length_prefix = s->max_run_length_prefix;
+      uint8_t* context_map = *context_map_arg;
+      int code;
+      while (context_index < context_map_size) {
+        if (!BrotliCheckInputAmount(br, 32)) {
+          s->context_index = context_index;
+          return BROTLI_RESULT_NEEDS_MORE_INPUT;
+        }
+        code = ReadSymbol(s->context_map_table, br);
+        if (code == 0) {
+          context_map[context_index++] = 0;
+        } else if (code - max_run_length_prefix <= 0) {
+          int reps = (1 << code) + (int)BrotliReadBits(br, code);
+          if (context_index + reps > context_map_size) {
+            return BROTLI_FAILURE();
+          }
+          do {
+            context_map[context_index++] = 0;
+          } while (--reps);
+        } else {
+          context_map[context_index++] =
+              (uint8_t)(code - max_run_length_prefix);
+        }
+      }
+      if (BrotliReadBits(br, 1)) {
+        InverseMoveToFrontTransform(context_map, context_map_size, s);
+      }
+      s->sub0_state = BROTLI_STATE_SUB0_NONE;
+      return BROTLI_RESULT_SUCCESS;
+    }
   }
 
-  use_rle_for_zeros = (int)BrotliReadBits(br, 1);
-  if (use_rle_for_zeros) {
-    max_run_length_prefix = (int)BrotliReadBits(br, 4) + 1;
-  }
-  table = (HuffmanCode*)malloc(HUFFMAN_MAX_TABLE_SIZE * sizeof(*table));
-  if (table == NULL) {
-    return 0;
-  }
-  if (!ReadHuffmanCode(*num_htrees + max_run_length_prefix, table, br)) {
-    ok = 0;
-    goto End;
-  }
-  for (i = 0; i < context_map_size;) {
-    int code;
-    if (!BrotliReadMoreInput(br)) {
-      printf("[DecodeContextMap] Unexpected end of input.\n");
-      ok = 0;
-      goto End;
-    }
-    code = ReadSymbol(table, br);
-    if (code == 0) {
-      (*context_map)[i] = 0;
-      ++i;
-    } else if (code <= max_run_length_prefix) {
-      int reps = 1 + (1 << code) + (int)BrotliReadBits(br, code);
-      while (--reps) {
-        if (i >= context_map_size) {
-          ok = 0;
-          goto End;
-        }
-        (*context_map)[i] = 0;
-        ++i;
-      }
-    } else {
-      (*context_map)[i] = (uint8_t)(code - max_run_length_prefix);
-      ++i;
-    }
-  }
-  if (BrotliReadBits(br, 1)) {
-    InverseMoveToFrontTransform(*context_map, context_map_size);
-  }
-End:
-  free(table);
-  return ok;
+  return BROTLI_FAILURE();
 }
 
-static BROTLI_INLINE void DecodeBlockType(const int max_block_type,
-                                          const HuffmanCode* trees,
-                                          int tree_type,
-                                          int* block_types,
-                                          int* ringbuffers,
-                                          int* indexes,
-                                          BrotliBitReader* br) {
+static void DecodeBlockType(const int max_block_type,
+                            const HuffmanCode* trees,
+                            int tree_type,
+                            int* ringbuffers,
+                            BrotliBitReader* br) {
   int* ringbuffer = ringbuffers + tree_type * 2;
-  int* index = indexes + tree_type;
-  int type_code = ReadSymbol(&trees[tree_type * HUFFMAN_MAX_TABLE_SIZE], br);
-  int block_type;
-  if (type_code == 0) {
-    block_type = ringbuffer[*index & 1];
-  } else if (type_code == 1) {
-    block_type = ringbuffer[(*index - 1) & 1] + 1;
-  } else {
-    block_type = type_code - 2;
+  int block_type =
+      ReadSymbol(&trees[tree_type * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br) - 2;
+  if (block_type == -1) {
+    block_type = ringbuffer[1] + 1;
+  } else if (block_type == -2) {
+    block_type = ringbuffer[0];
   }
   if (block_type >= max_block_type) {
     block_type -= max_block_type;
   }
-  block_types[tree_type] = block_type;
-  ringbuffer[(*index) & 1] = block_type;
-  ++(*index);
+  ringbuffer[0] = ringbuffer[1];
+  ringbuffer[1] = block_type;
 }
 
-/* Copy len bytes from src to dst. It can write up to ten extra bytes
-   after the end of the copy.
-
-   The main part of this loop is a simple copy of eight bytes at a time until
-   we've copied (at least) the requested amount of bytes.  However, if dst and
-   src are less than eight bytes apart (indicating a repeating pattern of
-   length < 8), we first need to expand the pattern in order to get the correct
-   results. For instance, if the buffer looks like this, with the eight-byte
-   <src> and <dst> patterns marked as intervals:
-
-      abxxxxxxxxxxxx
-      [------]           src
-        [------]         dst
-
-   a single eight-byte copy from <src> to <dst> will repeat the pattern once,
-   after which we can move <dst> two bytes without moving <src>:
-
-      ababxxxxxxxxxx
-      [------]           src
-          [------]       dst
-
-   and repeat the exercise until the two no longer overlap.
+/* Decodes the block type and updates the state for literal context. */
+static void DecodeBlockTypeWithContext(BrotliState* s,
+                                       BrotliBitReader* br) {
+  uint8_t context_mode;
+  int context_offset;
+  DecodeBlockType(s->num_block_types[0], s->block_type_trees, 0,
+                  s->block_type_rb, br);
+  s->block_length[0] = ReadBlockLength(s->block_len_trees, br);
+  context_offset = s->block_type_rb[1] << kLiteralContextBits;
+  s->context_map_slice = s->context_map + context_offset;
+  s->literal_htree_index = s->context_map_slice[0];
+  s->literal_htree = s->literal_hgroup.htrees[s->literal_htree_index];
+  context_mode = s->context_modes[s->block_type_rb[1]];
+  s->context_lookup1 = &kContextLookup[kContextLookupOffsets[context_mode]];
+  s->context_lookup2 = &kContextLookup[kContextLookupOffsets[context_mode + 1]];
+}
 
-   This allows us to do very well in the special case of one single byte
-   repeated many times, without taking a big hit for more general cases.
-
-   The worst case of extra writing past the end of the match occurs when
-   dst - src == 1 and len == 1; the last copy will read from byte positions
-   [0..7] and write to [4..11], whereas it was only supposed to write to
-   position 1. Thus, ten excess bytes.
-*/
-static BROTLI_INLINE void IncrementalCopyFastPath(
-    uint8_t* dst, const uint8_t* src, int len) {
-  if (src < dst) {
-    while (dst - src < 8) {
-      UNALIGNED_MOVE64(dst, src);
-      len -= (int)(dst - src);
-      dst += dst - src;
-    }
+BrotliResult WriteRingBuffer(BrotliOutput output,
+                             BrotliState* s) {
+  int num_written = BrotliWrite(
+      output, s->ringbuffer + s->partially_written,
+      (size_t)(s->to_write - s->partially_written));
+  if (num_written < 0) {
+    return BROTLI_FAILURE();
   }
-  while (len > 0) {
-    UNALIGNED_COPY64(dst, src);
-    src += 8;
-    dst += 8;
-    len -= 8;
+  s->partially_written += num_written;
+  if (s->partially_written < s->to_write) {
+    return BROTLI_RESULT_NEEDS_MORE_OUTPUT;
   }
+  return BROTLI_RESULT_SUCCESS;
 }
 
-int CopyUncompressedBlockToOutput(BrotliOutput output, int len, int pos,
-                                  uint8_t* ringbuffer, int ringbuffer_mask,
-                                  BrotliBitReader* br) {
-  const int rb_size = ringbuffer_mask + 1;
-  uint8_t* ringbuffer_end = ringbuffer + rb_size;
-  int rb_pos = pos & ringbuffer_mask;
-  int br_pos = br->pos_ & BROTLI_IBUF_MASK;
-  int nbytes;
-  uint32_t remaining_bits;
-
-  /* For short lengths copy byte-by-byte */
-  if (len < 8 || br->bit_pos_ + (uint32_t)(len << 3) < br->bit_end_pos_) {
-    while (len-- > 0) {
-      if (!BrotliReadMoreInput(br)) {
-        return 0;
-      }
-      ringbuffer[rb_pos++]= (uint8_t)BrotliReadBits(br, 8);
-      if (rb_pos == rb_size) {
-        if (BrotliWrite(output, ringbuffer, (size_t)rb_size) < rb_size) {
-          return 0;
+BrotliResult BROTLI_NOINLINE CopyUncompressedBlockToOutput(BrotliOutput output,
+                                                           int pos,
+                                                           BrotliState* s) {
+  BrotliResult result;
+  int num_read;
+  /* State machine */
+  for (;;) {
+    switch ((int)s->sub0_state) {
+      case BROTLI_STATE_SUB0_NONE:
+        /* For short lengths copy byte-by-byte */
+        if (s->meta_block_remaining_len < 8 ||
+            s->meta_block_remaining_len < BrotliGetRemainingBytes(&s->br)) {
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_SHORT;
+          break;
+        }
+        /* Copy remaining bytes from s->br.buf_ to ringbuffer. */
+        s->nbytes = (int)BrotliGetRemainingBytes(&s->br);
+        BrotliCopyBytes(&s->ringbuffer[pos], &s->br, (size_t)s->nbytes);
+        pos += s->nbytes;
+        s->meta_block_remaining_len -= s->nbytes;
+        if (pos >= s->ringbuffer_size) {
+          s->to_write = s->ringbuffer_size;
+          s->partially_written = 0;
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_1;
+          break;
+        }
+        if (pos + s->meta_block_remaining_len >= s->ringbuffer_size) {
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_FILL;
+        } else {
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_COPY;
+        }
+        break;
+      case BROTLI_STATE_SUB0_UNCOMPRESSED_SHORT:
+        while (s->meta_block_remaining_len > 0) {
+          if (!BrotliCheckInputAmount(&s->br, 32)) {
+            return BROTLI_RESULT_NEEDS_MORE_INPUT;
+          }
+          s->ringbuffer[pos++] = (uint8_t)BrotliReadBits(&s->br, 8);
+          s->meta_block_remaining_len--;
+        }
+        if (pos >= s->ringbuffer_size) {
+          s->to_write = s->ringbuffer_size;
+          s->partially_written = 0;
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_2;
+        } else {
+          s->sub0_state = BROTLI_STATE_SUB0_NONE;
+          return BROTLI_RESULT_SUCCESS;
+        }
+        /* No break, if state is updated, continue to next state */
+      case BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_1:
+      case BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_2:
+      case BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_3:
+        result = WriteRingBuffer(output, s);
+        if (result != BROTLI_RESULT_SUCCESS) {
+          return result;
         }
-        rb_pos = 0;
-      }
+        pos &= s->ringbuffer_mask;
+        s->max_distance = s->max_backward_distance;
+        if (s->sub0_state == BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_2) {
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_SHORT;
+          break;
+        }
+        if (s->sub0_state == BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_1) {
+          s->meta_block_remaining_len -= s->ringbuffer_size;
+          /* If we wrote past the logical end of the ringbuffer, copy the tail
+             of the ringbuffer to its beginning and flush the ringbuffer to the
+             output. */
+          memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)pos);
+        }
+        if (pos + s->meta_block_remaining_len >= s->ringbuffer_size) {
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_FILL;
+        } else {
+          s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_COPY;
+          break;
+        }
+        /* No break, continue to next state */
+      case BROTLI_STATE_SUB0_UNCOMPRESSED_FILL:
+        /* If we have more to copy than the remaining size of the ringbuffer,
+           then we first fill the ringbuffer from the input and then flush the
+           ringbuffer to the output */
+        s->nbytes = s->ringbuffer_size - pos;
+        num_read = BrotliRead(s->br.input_, &s->ringbuffer[pos],
+                              (size_t)s->nbytes);
+        s->meta_block_remaining_len -= num_read;
+        if (num_read < s->nbytes) {
+          if (num_read < 0) return BROTLI_FAILURE();
+          return BROTLI_RESULT_NEEDS_MORE_INPUT;
+        }
+        s->to_write = s->ringbuffer_size;
+        s->partially_written = 0;
+        s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WRITE_3;
+        break;
+        /* No break, continue to next state */
+      case BROTLI_STATE_SUB0_UNCOMPRESSED_COPY:
+        /* Copy straight from the input onto the ringbuffer. The ringbuffer will
+           be flushed to the output at a later time. */
+        num_read = BrotliRead(s->br.input_, &s->ringbuffer[pos],
+                              (size_t)s->meta_block_remaining_len);
+        s->meta_block_remaining_len -= num_read;
+        if (s->meta_block_remaining_len > 0) {
+          if (num_read < 0) return BROTLI_FAILURE();
+          return BROTLI_RESULT_NEEDS_MORE_INPUT;
+        }
+        s->sub0_state = BROTLI_STATE_SUB0_UNCOMPRESSED_WARMUP;
+        /* No break, continue to next state */
+      case BROTLI_STATE_SUB0_UNCOMPRESSED_WARMUP:
+        if (!BrotliCheckInputAmount(&s->br, 32)) {
+          return BROTLI_RESULT_NEEDS_MORE_INPUT;
+        }
+        BrotliWarmupBitReader(&s->br);
+        s->sub0_state = BROTLI_STATE_SUB0_NONE;
+        return BROTLI_RESULT_SUCCESS;
     }
-    return 1;
-  }
-
-  if (br->bit_end_pos_ < 64) {
-    return 0;
-  }
-
-  /*
-   * Copy remaining 0-4 in 32-bit case or 0-8 bytes in the 64-bit case
-   * from br->val_ to ringbuffer.
-   */
-#if (BROTLI_USE_64_BITS)
-  remaining_bits = 64;
-#else
-  remaining_bits = 32;
-#endif
-  while (br->bit_pos_ < remaining_bits) {
-    ringbuffer[rb_pos] = (uint8_t)(br->val_ >> br->bit_pos_);
-    br->bit_pos_ += 8;
-    ++rb_pos;
-    --len;
   }
-
-  /* Copy remaining bytes from br->buf_ to ringbuffer. */
-  nbytes = (int)(br->bit_end_pos_ - br->bit_pos_) >> 3;
-  if (br_pos + nbytes > BROTLI_IBUF_MASK) {
-    int tail = BROTLI_IBUF_MASK + 1 - br_pos;
-    memcpy(&ringbuffer[rb_pos], &br->buf_[br_pos], (size_t)tail);
-    nbytes -= tail;
-    rb_pos += tail;
-    len -= tail;
-    br_pos = 0;
-  }
-  memcpy(&ringbuffer[rb_pos], &br->buf_[br_pos], (size_t)nbytes);
-  rb_pos += nbytes;
-  len -= nbytes;
-
-  /* If we wrote past the logical end of the ringbuffer, copy the tail of the
-     ringbuffer to its beginning and flush the ringbuffer to the output. */
-  if (rb_pos >= rb_size) {
-    if (BrotliWrite(output, ringbuffer, (size_t)rb_size) < rb_size) {
-      return 0;
-    }
-    rb_pos -= rb_size;
-    memcpy(ringbuffer, ringbuffer_end, (size_t)rb_pos);
-  }
-
-  /* If we have more to copy than the remaining size of the ringbuffer, then we
-     first fill the ringbuffer from the input and then flush the ringbuffer to
-     the output */
-  while (rb_pos + len >= rb_size) {
-    nbytes = rb_size - rb_pos;
-    if (BrotliRead(br->input_, &ringbuffer[rb_pos], (size_t)nbytes) < nbytes ||
-        BrotliWrite(output, ringbuffer, (size_t)rb_size) < nbytes) {
-      return 0;
-    }
-    len -= nbytes;
-    rb_pos = 0;
-  }
-
-  /* Copy straight from the input onto the ringbuffer. The ringbuffer will be
-     flushed to the output at a later time. */
-  if (BrotliRead(br->input_, &ringbuffer[rb_pos], (size_t)len) < len) {
-    return 0;
-  }
-
-  /* Restore the state of the bit reader. */
-  BrotliInitBitReader(br, br->input_);
-  return 1;
+  return BROTLI_FAILURE();
 }
 
 int BrotliDecompressedSize(size_t encoded_size,
                            const uint8_t* encoded_buffer,
                            size_t* decoded_size) {
   int i;
   uint64_t val = 0;
   int bit_pos = 0;
@@ -654,30 +749,40 @@ int BrotliDecompressedSize(size_t encode
     return 0;
   }
   /* Look at the first 8 bytes, it is enough to decode the length of the first
      meta-block. */
   for (i = 0; (size_t)i < encoded_size && i < 8; ++i) {
     val |= (uint64_t)encoded_buffer[i] << (8 * i);
   }
   /* Skip the window bits. */
-  bit_pos += (val & 1) ? 4 : 1;
+  ++bit_pos;
+  if (val & 1) {
+    bit_pos += 3;
+    if (((val >> 1) & 7) == 0) {
+      bit_pos += 3;
+    }
+  }
   /* Decode the ISLAST bit. */
   is_last = (val >> bit_pos) & 1;
   ++bit_pos;
   if (is_last) {
     /* Decode the ISEMPTY bit, if it is set to 1, we are done. */
     if ((val >> bit_pos) & 1) {
       *decoded_size = 0;
       return 1;
     }
     ++bit_pos;
   }
   /* Decode the length of the first meta-block. */
   size_nibbles = (int)((val >> bit_pos) & 3) + 4;
+  if (size_nibbles == 7) {
+    /* First meta-block contains metadata, this case is not supported here. */
+    return 0;
+  }
   bit_pos += 2;
   for (i = 0; i < size_nibbles; ++i) {
     meta_block_len |= (int)((val >> bit_pos) & 0xf) << (4 * i);
     bit_pos += 4;
   }
   ++meta_block_len;
   if (is_last) {
     /* If this meta-block is the only one, we are done. */
@@ -693,473 +798,776 @@ int BrotliDecompressedSize(size_t encode
        followed by an empty one, so the decompressed size is the size of the
        first meta-block. */
     size_t offset = (size_t)((bit_pos + 7) >> 3) + (size_t)meta_block_len;
     if (offset < encoded_size && ((encoded_buffer[offset] & 3) == 3)) {
       *decoded_size = (size_t)meta_block_len;
       return 1;
     }
   }
+  /* Could not get the size because the file has multiple meta-blocks */
   return 0;
 }
 
-int BrotliDecompressBuffer(size_t encoded_size,
-                           const uint8_t* encoded_buffer,
-                           size_t* decoded_size,
-                           uint8_t* decoded_buffer) {
+BrotliResult BrotliDecompressBuffer(size_t encoded_size,
+                                    const uint8_t* encoded_buffer,
+                                    size_t* decoded_size,
+                                    uint8_t* decoded_buffer) {
   BrotliMemInput memin;
   BrotliInput in = BrotliInitMemInput(encoded_buffer, encoded_size, &memin);
   BrotliMemOutput mout;
   BrotliOutput out = BrotliInitMemOutput(decoded_buffer, *decoded_size, &mout);
-  int success = BrotliDecompress(in, out);
+  BrotliResult success = BrotliDecompress(in, out);
   *decoded_size = mout.pos;
   return success;
 }
 
-int BrotliDecompress(BrotliInput input, BrotliOutput output) {
-  int ok = 1;
-  int i;
-  int pos = 0;
-  int input_end = 0;
-  int window_bits = 0;
-  int max_backward_distance;
-  int max_distance = 0;
-  int ringbuffer_size;
-  int ringbuffer_mask;
-  uint8_t* ringbuffer;
-  uint8_t* ringbuffer_end;
-  /* This ring buffer holds a few past copy distances that will be used by */
-  /* some special distance codes. */
-  int dist_rb[4] = { 16, 15, 11, 4 };
-  int dist_rb_idx = 0;
-  /* The previous 2 bytes used for context. */
-  uint8_t prev_byte1 = 0;
-  uint8_t prev_byte2 = 0;
-  HuffmanTreeGroup hgroup[3];
-  HuffmanCode* block_type_trees = NULL;
-  HuffmanCode* block_len_trees = NULL;
-  BrotliBitReader br;
+BrotliResult BrotliDecompress(BrotliInput input, BrotliOutput output) {
+  BrotliState s;
+  BrotliResult result;
+  BrotliStateInit(&s);
+  result = BrotliDecompressStreaming(input, output, 1, &s);
+  if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+    /* Not ok: it didn't finish even though this is a non-streaming function. */
+    result = BROTLI_FAILURE();
+  }
+  BrotliStateCleanup(&s);
+  return result;
+}
 
+BrotliResult BrotliDecompressBufferStreaming(size_t* available_in,
+                                             const uint8_t** next_in,
+                                             int finish,
+                                             size_t* available_out,
+                                             uint8_t** next_out,
+                                             size_t* total_out,
+                                             BrotliState* s) {
+  BrotliMemInput memin;
+  BrotliInput in = BrotliInitMemInput(*next_in, *available_in, &memin);
+  BrotliMemOutput memout;
+  BrotliOutput out = BrotliInitMemOutput(*next_out, *available_out, &memout);
+  BrotliResult result = BrotliDecompressStreaming(in, out, finish, s);
+  /* The current implementation reads everything, so 0 bytes are available. */
+  *next_in += memin.pos;
+  *available_in -= memin.pos;
+  /* Update the output position to where we write next. */
+  *next_out += memout.pos;
+  *available_out -= memout.pos;
+  *total_out += memout.pos;
+  return result;
+}
+
+BrotliResult BrotliDecompressStreaming(BrotliInput input, BrotliOutput output,
+                                       int finish, BrotliState* s) {
+  uint8_t context;
+  int pos = s->pos;
+  int i = s->loop_counter;
+  BrotliResult result = BROTLI_RESULT_SUCCESS;
+  BrotliBitReader* br = &s->br;
+  int initial_remaining_len;
+  int bytes_copied;
+  int is_metadata;
+  int is_uncompressed;
+  uint8_t *copy_src;
+  uint8_t *copy_dst;
   /* We need the slack region for the following reasons:
-       - always doing two 8-byte copies for fast backward copying
+       - doing up to two 16-byte copies for fast backward copying
        - transforms
-       - flushing the input ringbuffer when decoding uncompressed blocks */
-  static const int kRingBufferWriteAheadSlack = 128 + BROTLI_READ_SIZE;
+       - flushing the input s->ringbuffer when decoding uncompressed blocks */
+  static const int kRingBufferWriteAheadSlack =
+      BROTLI_IMPLICIT_ZEROES + BROTLI_READ_SIZE;
+  s->br.input_ = input;
+  /* State machine */
+  for (;;) {
+    if (result != BROTLI_RESULT_SUCCESS) {
+      if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+        if (BrotliReadInput(br, finish)) {
+          result = BROTLI_RESULT_SUCCESS;
+          continue;
+        }
+        if (finish) {
+          BROTLI_LOG(("Unexpected end of input. State: %d\n", s->state));
+          result = BROTLI_FAILURE();
+        }
+      }
+      break;  /* Fail, or partial data. */
+    }
+    switch (s->state) {
+      case BROTLI_STATE_UNINITED:
+        pos = 0;
+        BrotliInitBitReader(br, input);
+
+        s->state = BROTLI_STATE_BITREADER_WARMUP;
+        /* No break, continue to next state */
+      case BROTLI_STATE_BITREADER_WARMUP:
+        if (!BrotliCheckInputAmount(br, 32)) {
+          result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+          break;
+        }
+        BrotliWarmupBitReader(br);
+        /* Decode window size. */
+        s->window_bits = DecodeWindowBits(br);
+        if (s->window_bits == 9) {
+          /* Value 9 is reserved for future use. */
+          result = BROTLI_FAILURE();
+          break;
+        }
+        /* Allocate the ringbuffer */
+        {
+          size_t known_size = 0;
+          s->ringbuffer_size = 1 << s->window_bits;
 
-  if (!BrotliInitBitReader(&br, input)) {
-    return 0;
-  }
+          /* If we know the data size is small, do not allocate more ringbuffer
+             size than needed to reduce memory usage. Since this happens after
+             the first BrotliCheckInputAmount call, we can read the bitreader
+             buffer at position 0.
+             We need at least 2 bytes of ring buffer size to get the last two
+             bytes for context from there */
+          if (BrotliDecompressedSize(BROTLI_READ_SIZE, br->buf_, &known_size)) {
+            while (s->ringbuffer_size >= known_size * 2
+                && s->ringbuffer_size > 32) {
+              s->ringbuffer_size >>= 1;
+            }
+          }
+
+          /* But make it fit the custom dictionary if there is one. */
+          while (s->ringbuffer_size < s->custom_dict_size) {
+            s->ringbuffer_size <<= 1;
+          }
 
-  /* Decode window size. */
-  window_bits = DecodeWindowBits(&br);
-  max_backward_distance = (1 << window_bits) - 16;
+          s->ringbuffer_mask = s->ringbuffer_size - 1;
+          s->ringbuffer = (uint8_t*)malloc((size_t)(s->ringbuffer_size +
+                                                 kRingBufferWriteAheadSlack +
+                                                 kMaxDictionaryWordLength));
+          if (!s->ringbuffer) {
+            result = BROTLI_FAILURE();
+            break;
+          }
+          s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size;
+          s->ringbuffer[s->ringbuffer_size - 2] = 0;
+          s->ringbuffer[s->ringbuffer_size - 1] = 0;
+          if (s->custom_dict) {
+            memcpy(&s->ringbuffer[(-s->custom_dict_size) & s->ringbuffer_mask],
+                                  s->custom_dict, (size_t)s->custom_dict_size);
+          }
+        }
+        s->max_backward_distance = (1 << s->window_bits) - 16;
+        s->max_backward_distance_minus_custom_dict_size =
+            s->max_backward_distance - s->custom_dict_size;
+
+        /* Allocate memory for both block_type_trees and block_len_trees. */
+        s->block_type_trees = (HuffmanCode*)malloc(
+            6 * BROTLI_HUFFMAN_MAX_TABLE_SIZE * sizeof(HuffmanCode));
+
+        if (s->block_type_trees == NULL) {
+          result = BROTLI_FAILURE();
+          break;
+        }
+        s->block_len_trees = s->block_type_trees +
+            3 * BROTLI_HUFFMAN_MAX_TABLE_SIZE;
 
-  ringbuffer_size = 1 << window_bits;
-  ringbuffer_mask = ringbuffer_size - 1;
-  ringbuffer = (uint8_t*)malloc((size_t)(ringbuffer_size +
-                                         kRingBufferWriteAheadSlack +
-                                         kMaxDictionaryWordLength));
-  if (!ringbuffer) {
-    ok = 0;
-  }
-  ringbuffer_end = ringbuffer + ringbuffer_size;
-
-  if (ok) {
-    block_type_trees = (HuffmanCode*)malloc(
-        3 * HUFFMAN_MAX_TABLE_SIZE * sizeof(HuffmanCode));
-    block_len_trees = (HuffmanCode*)malloc(
-        3 * HUFFMAN_MAX_TABLE_SIZE * sizeof(HuffmanCode));
-    if (block_type_trees == NULL || block_len_trees == NULL) {
-      ok = 0;
+        s->state = BROTLI_STATE_METABLOCK_BEGIN;
+        /* No break, continue to next state */
+      case BROTLI_STATE_METABLOCK_BEGIN:
+        if (s->input_end) {
+          s->to_write = pos;
+          s->partially_written = 0;
+          s->state = BROTLI_STATE_DONE;
+          break;
+        }
+        BrotliStateMetablockBegin(s);
+        s->state = BROTLI_STATE_METABLOCK_HEADER_1;
+        /* No break, continue to next state */
+      case BROTLI_STATE_METABLOCK_HEADER_1:
+        if (!BrotliCheckInputAmount(br, 32)) {
+          result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+          break;
+        }
+        BROTLI_LOG_UINT(pos);
+        if (!DecodeMetaBlockLength(br,
+                                   &s->meta_block_remaining_len,
+                                   &s->input_end,
+                                   &is_metadata,
+                                   &is_uncompressed)) {
+          result = BROTLI_FAILURE();
+          break;
+        }
+        BROTLI_LOG_UINT(s->meta_block_remaining_len);
+        if (is_metadata) {
+          if (!BrotliJumpToByteBoundary(br)) {
+            result = BROTLI_FAILURE();
+            break;
+          }
+          s->state = BROTLI_STATE_METADATA;
+          break;
+        }
+        if (s->meta_block_remaining_len == 0) {
+          s->state = BROTLI_STATE_METABLOCK_DONE;
+          break;
+        }
+        if (is_uncompressed) {
+          if (!BrotliJumpToByteBoundary(br)) {
+            result = BROTLI_FAILURE();
+            break;
+          }
+          s->state = BROTLI_STATE_UNCOMPRESSED;
+          break;
+        }
+        i = 0;
+        s->state = BROTLI_STATE_HUFFMAN_CODE_0;
+        break;
+      case BROTLI_STATE_UNCOMPRESSED:
+        initial_remaining_len = s->meta_block_remaining_len;
+        /* pos is given as argument since s->pos is only updated at the end. */
+        result = CopyUncompressedBlockToOutput(output, pos, s);
+        bytes_copied = initial_remaining_len - s->meta_block_remaining_len;
+        pos = (pos + bytes_copied) & s->ringbuffer_mask;
+        if (result != BROTLI_RESULT_SUCCESS) {
+          break;
+        }
+        s->state = BROTLI_STATE_METABLOCK_DONE;
+        break;
+      case BROTLI_STATE_METADATA:
+        for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) {
+          if (!BrotliCheckInputAmount(br, 32)) {
+            result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+            break;
+          }
+          /* Read one byte and ignore it. */
+          BrotliReadBits(br, 8);
+        }
+        if (result == BROTLI_RESULT_SUCCESS) {
+          s->state = BROTLI_STATE_METABLOCK_DONE;
+        }
+        break;
+      case BROTLI_STATE_HUFFMAN_CODE_0:
+        if (i >= 3) {
+          BROTLI_LOG_UINT(s->num_block_type_rb[0]);
+          BROTLI_LOG_UINT(s->num_block_type_rb[2]);
+          BROTLI_LOG_UINT(s->num_block_type_rb[4]);
+          BROTLI_LOG_UINT(s->block_length[0]);
+          BROTLI_LOG_UINT(s->block_length[1]);
+          BROTLI_LOG_UINT(s->block_length[2]);
+          s->state = BROTLI_STATE_METABLOCK_HEADER_2;
+          break;
+        }
+        s->num_block_types[i] = DecodeVarLenUint8(br) + 1;
+        s->state = BROTLI_STATE_HUFFMAN_CODE_1;
+        /* No break, continue to next state */
+      case BROTLI_STATE_HUFFMAN_CODE_1:
+        if (s->num_block_types[i] >= 2) {
+          result = ReadHuffmanCode(s->num_block_types[i] + 2,
+              &s->block_type_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE],
+              NULL, s);
+          if (result != BROTLI_RESULT_SUCCESS) break;
+          s->state = BROTLI_STATE_HUFFMAN_CODE_2;
+        } else {
+          i++;
+          s->state = BROTLI_STATE_HUFFMAN_CODE_0;
+          break;
+        }
+        /* No break, continue to next state */
+      case BROTLI_STATE_HUFFMAN_CODE_2:
+        result = ReadHuffmanCode(kNumBlockLengthCodes,
+            &s->block_len_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE],
+            NULL, s);
+        if (result != BROTLI_RESULT_SUCCESS) break;
+        s->block_length[i] = ReadBlockLength(
+            &s->block_len_trees[i * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br);
+        i++;
+        s->state = BROTLI_STATE_HUFFMAN_CODE_0;
+        break;
+      case BROTLI_STATE_METABLOCK_HEADER_2:
+        /* We need up to 256 * 2 + 6 bits, this fits in 128 bytes. */
+        if (!BrotliCheckInputAmount(br, 128)) {
+          result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+          break;
+        }
+        s->distance_postfix_bits = (int)BrotliReadBits(br, 2);
+        s->num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES +
+            ((int)BrotliReadBits(br, 4) << s->distance_postfix_bits);
+        s->distance_postfix_mask = (int)BitMask(s->distance_postfix_bits);
+        s->context_modes = (uint8_t*)malloc((size_t)s->num_block_types[0]);
+        if (s->context_modes == 0) {
+          result = BROTLI_FAILURE();
+          break;
+        }
+        for (i = 0; i < s->num_block_types[0]; ++i) {
+          s->context_modes[i] = (uint8_t)(BrotliReadBits(br, 2) << 1);
+          BROTLI_LOG_ARRAY_INDEX(s->context_modes, i);
+        }
+        BROTLI_LOG_UINT(s->num_direct_distance_codes);
+        BROTLI_LOG_UINT(s->distance_postfix_bits);
+        s->state = BROTLI_STATE_CONTEXT_MAP_1;
+        /* No break, continue to next state */
+      case BROTLI_STATE_CONTEXT_MAP_1:
+        result = DecodeContextMap(s->num_block_types[0] << kLiteralContextBits,
+                                  &s->num_literal_htrees, &s->context_map, s);
+        if (result != BROTLI_RESULT_SUCCESS) {
+          break;
+        }
+        s->trivial_literal_context = 1;
+        for (i = 0; i < s->num_block_types[0] << kLiteralContextBits; i++) {
+          if (s->context_map[i] != i >> kLiteralContextBits) {
+            s->trivial_literal_context = 0;
+            break;
+          }
+        }
+        s->state = BROTLI_STATE_CONTEXT_MAP_2;
+        /* No break, continue to next state */
+      case BROTLI_STATE_CONTEXT_MAP_2:
+        {
+          int num_dist_htrees;
+          int num_distance_codes =
+              s->num_direct_distance_codes + (48 << s->distance_postfix_bits);
+          result = DecodeContextMap(
+              s->num_block_types[2] << kDistanceContextBits,
+              &num_dist_htrees, &s->dist_context_map, s);
+          if (result != BROTLI_RESULT_SUCCESS) {
+            break;
+          }
+          BrotliHuffmanTreeGroupInit(
+              &s->literal_hgroup, kNumLiteralCodes, s->num_literal_htrees);
+          BrotliHuffmanTreeGroupInit(
+              &s->insert_copy_hgroup, kNumInsertAndCopyCodes,
+              s->num_block_types[1]);
+          BrotliHuffmanTreeGroupInit(
+              &s->distance_hgroup, num_distance_codes, num_dist_htrees);
+        }
+        i = 0;
+        s->state = BROTLI_STATE_TREE_GROUP;
+        /* No break, continue to next state */
+      case BROTLI_STATE_TREE_GROUP:
+        switch (i) {
+          case 0:
+            result = HuffmanTreeGroupDecode(&s->literal_hgroup, s);
+            break;
+          case 1:
+            result = HuffmanTreeGroupDecode(&s->insert_copy_hgroup, s);
+            break;
+          case 2:
+            result = HuffmanTreeGroupDecode(&s->distance_hgroup, s);
+            break;
+        }
+        if (result != BROTLI_RESULT_SUCCESS) break;
+        i++;
+        if (i >= 3) {
+          uint8_t context_mode = s->context_modes[s->block_type_rb[1]];
+          s->context_map_slice = s->context_map;
+          s->dist_context_map_slice = s->dist_context_map;
+          s->context_lookup1 =
+              &kContextLookup[kContextLookupOffsets[context_mode]];
+          s->context_lookup2 =
+              &kContextLookup[kContextLookupOffsets[context_mode + 1]];
+          s->htree_command = s->insert_copy_hgroup.htrees[0];
+          s->literal_htree = s->literal_hgroup.htrees[s->literal_htree_index];
+          s->state = BROTLI_STATE_COMMAND_BEGIN;
+        }
+        break;
+      case BROTLI_STATE_COMMAND_BEGIN:
+        if (s->meta_block_remaining_len <= 0) {
+          /* Next metablock, if any */
+          s->state = BROTLI_STATE_METABLOCK_DONE;
+          break;
+        }
+ /* Decoding of Brotli commands is the inner loop, jumping with goto makes it
+    3% faster */
+ CommandBegin:
+        if (!BrotliCheckInputAmount(br, 32)) {
+          s->state = BROTLI_STATE_COMMAND_BEGIN;
+          result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+          break;
+        }
+          /* Read the insert/copy length in the command */
+        if (s->block_length[1] == 0) {
+          /* Block switch for insert/copy length */
+          DecodeBlockType(s->num_block_types[1],
+                          s->block_type_trees, 1,
+                          s->block_type_rb, br);
+          s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]];
+          s->block_length[1] = ReadBlockLength(
+              &s->block_len_trees[BROTLI_HUFFMAN_MAX_TABLE_SIZE], br);
+        }
+        {
+          int cmd_code = ReadSymbol(s->htree_command, br);
+          CmdLutElement v;
+          --s->block_length[1];
+          v = kCmdLut[cmd_code];
+          s->distance_code = v.distance_code;
+          s->distance_context = v.context;
+          s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
+          i = (int)BrotliReadBits(br, v.insert_len_extra_bits) +
+              v.insert_len_offset;
+          s->copy_length = (int)BrotliReadBits(br, v.copy_len_extra_bits) +
+              v.copy_len_offset;
+        }
+        BROTLI_LOG_UINT(i);
+        BROTLI_LOG_UINT(s->copy_length);
+        BROTLI_LOG_UINT(s->distance_code);
+        if (i == 0) {
+          goto postDecodeLiterals;
+        }
+        s->meta_block_remaining_len -= i;
+        /* No break, go to next state */
+      case BROTLI_STATE_COMMAND_INNER:
+        /* Read the literals in the command */
+        if (s->trivial_literal_context) {
+          unsigned bits;
+          unsigned value;
+          PreloadSymbol(s->literal_htree, br, &bits, &value);
+          do {
+            if (!BrotliCheckInputAmount(br, 64)) {
+              s->state = BROTLI_STATE_COMMAND_INNER;
+              result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+              break;
+            }
+            if (PREDICT_FALSE(s->block_length[0] == 0)) {
+              /* Block switch for literals */
+              DecodeBlockTypeWithContext(s, br);
+              PreloadSymbol(s->literal_htree, br, &bits, &value);
+            }
+            s->ringbuffer[pos] =
+                (uint8_t)ReadPreloadedSymbol(s->literal_htree,
+                                             br, &bits, &value);
+            --s->block_length[0];
+            BROTLI_LOG_UINT(s->literal_htree_index);
+            BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos);
+            ++pos;
+            if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
+              s->to_write = s->ringbuffer_size;
+              s->partially_written = 0;
+              s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
+              --i;
+              goto innerWrite;
+            }
+          } while (--i != 0);
+        } else {
+          uint8_t p1 = s->ringbuffer[(pos - 1) & s->ringbuffer_mask];
+          uint8_t p2 = s->ringbuffer[(pos - 2) & s->ringbuffer_mask];
+          do {
+            const HuffmanCode* hc;
+            if (!BrotliCheckInputAmount(br, 64)) {
+              s->state = BROTLI_STATE_COMMAND_INNER;
+              result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+              break;
+            }
+            if (PREDICT_FALSE(s->block_length[0] == 0)) {
+              /* Block switch for literals */
+              DecodeBlockTypeWithContext(s, br);
+            }
+            context = s->context_lookup1[p1] | s->context_lookup2[p2];
+            BROTLI_LOG_UINT(context);
+            hc = s->literal_hgroup.htrees[s->context_map_slice[context]];
+            --s->block_length[0];
+            p2 = p1;
+            p1 = (uint8_t)ReadSymbol(hc, br);
+            s->ringbuffer[pos] = p1;
+            BROTLI_LOG_UINT(s->context_map_slice[context]);
+            BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos & s->ringbuffer_mask);
+            ++pos;
+            if (PREDICT_FALSE(pos == s->ringbuffer_size)) {
+              s->to_write = s->ringbuffer_size;
+              s->partially_written = 0;
+              s->state = BROTLI_STATE_COMMAND_INNER_WRITE;
+              --i;
+              goto innerWrite;
+            }
+          } while (--i != 0);
+        }
+        if (result != BROTLI_RESULT_SUCCESS) break;
+        if (s->meta_block_remaining_len <= 0) {
+          s->state = BROTLI_STATE_METABLOCK_DONE;
+          break;
+        }
+postDecodeLiterals:
+        if (s->distance_code >= 0) {
+          --s->dist_rb_idx;
+          s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
+          goto postReadDistance;  /* We already have the implicit distance */
+        }
+        /* Read distance code in the command, unless it was implicitely zero. */
+        BROTLI_DCHECK(s->distance_code < 0);
+        if (s->block_length[2] == 0) {
+          /* Block switch for distance codes */
+          int dist_context_offset;
+          DecodeBlockType(s->num_block_types[2],
+                          s->block_type_trees, 2,
+                          s->block_type_rb, br);
+          s->block_length[2] = ReadBlockLength(
+              &s->block_len_trees[2 * BROTLI_HUFFMAN_MAX_TABLE_SIZE], br);
+          dist_context_offset = s->block_type_rb[5] << kDistanceContextBits;
+          s->dist_context_map_slice =
+              s->dist_context_map + dist_context_offset;
+          s->dist_htree_index = s->dist_context_map_slice[s->distance_context];
+        }
+        --s->block_length[2];
+        s->distance_code =
+            ReadSymbol(s->distance_hgroup.htrees[s->dist_htree_index], br);
+        /* Convert the distance code to the actual distance by possibly */
+        /* looking up past distances from the s->ringbuffer. */
+        if ((s->distance_code & ~0xf) == 0) {
+          if (s->distance_code == 0) {
+            --s->dist_rb_idx;
+            s->distance_code = s->dist_rb[s->dist_rb_idx & 3];
+          } else {
+            int distance_code = s->distance_code << 1;
+            /* kDistanceShortCodeIndexOffset has 2-bit values from LSB: */
+            /* 3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 */
+            const uint32_t kDistanceShortCodeIndexOffset = 0xaaafff1b;
+            /* kDistanceShortCodeValueOffset has 2-bit values from LSB: */
+            /* 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 1, 1, 2, 2, 3, 3 */
+            const uint32_t kDistanceShortCodeValueOffset = 0xfa5fa500;
+            int v = (s->dist_rb_idx +
+                (int)(kDistanceShortCodeIndexOffset >> distance_code)) & 0x3;
+            s->distance_code = s->dist_rb[v];
+            v = (int)(kDistanceShortCodeValueOffset >> distance_code) & 0x3;
+            if ((distance_code & 0x3) != 0) {
+              s->distance_code += v;
+            } else {
+              s->distance_code -= v;
+              if (s->distance_code <= 0) {
+                /* A huge distance will cause a BROTLI_FAILURE() soon. */
+                /* This is a little faster than failing here. */
+                s->distance_code = 0x0fffffff;
+              }
+            }
+          }
+        } else {
+          int distval = s->distance_code - s->num_direct_distance_codes;
+          if (distval >= 0) {
+            int nbits;
+            int postfix;
+            int offset;
+            if (s->distance_postfix_bits == 0) {
+              nbits = (distval >> 1) + 1;
+              offset = ((2 + (distval & 1)) << nbits) - 4;
+              s->distance_code = s->num_direct_distance_codes +
+                  offset + (int)BrotliReadBits(br, nbits);
+            } else {
+              postfix = distval & s->distance_postfix_mask;
+              distval >>= s->distance_postfix_bits;
+              nbits = (distval >> 1) + 1;
+              offset = ((2 + (distval & 1)) << nbits) - 4;
+              s->distance_code = s->num_direct_distance_codes +
+                  ((offset + (int)BrotliReadBits(br, nbits)) <<
+                   s->distance_postfix_bits) + postfix;
+            }
+          }
+          s->distance_code = s->distance_code - NUM_DISTANCE_SHORT_CODES + 1;
+        }
+postReadDistance:
+        BROTLI_LOG_UINT(s->distance_code);
+        if (s->max_distance != s->max_backward_distance) {
+          if (pos < s->max_backward_distance_minus_custom_dict_size) {
+            s->max_distance = pos + s->custom_dict_size;
+          } else {
+            s->max_distance = s->max_backward_distance;
+          }
+        }
+        i = s->copy_length;
+        /* Apply copy of LZ77 back-reference, or static dictionary reference if
+        the distance is larger than the max LZ77 distance */
+        if (s->distance_code > s->max_distance) {
+          if (i >= kMinDictionaryWordLength &&
+              i <= kMaxDictionaryWordLength) {
+            int offset = kBrotliDictionaryOffsetsByLength[i];
+            int word_id = s->distance_code - s->max_distance - 1;
+            int shift = kBrotliDictionarySizeBitsByLength[i];
+            int mask = (int)BitMask(shift);
+            int word_idx = word_id & mask;
+            int transform_idx = word_id >> shift;
+            offset += word_idx * i;
+            if (transform_idx < kNumTransforms) {
+              const uint8_t* word = &kBrotliDictionary[offset];
+              int len = i;
+              if (transform_idx == 0) {
+                memcpy(&s->ringbuffer[pos], word, (size_t)len);
+              } else {
+                len = TransformDictionaryWord(
+                    &s->ringbuffer[pos], word, len, transform_idx);
+              }
+              pos += len;
+              s->meta_block_remaining_len -= len;
+              if (pos >= s->ringbuffer_size) {
+                s->to_write = s->ringbuffer_size;
+                s->partially_written = 0;
+                s->state = BROTLI_STATE_COMMAND_POST_WRITE_1;
+                break;
+              }
+            } else {
+              BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+                     "len: %d bytes left: %d\n",
+                  pos, s->distance_code, i,
+                  s->meta_block_remaining_len));
+              result = BROTLI_FAILURE();
+              break;
+            }
+          } else {
+            BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+                   "len: %d bytes left: %d\n", pos, s->distance_code, i,
+                   s->meta_block_remaining_len));
+            result = BROTLI_FAILURE();
+            break;
+          }
+        } else {
+          const uint8_t *ringbuffer_end_minus_copy_length =
+              s->ringbuffer_end - i;
+          copy_src = &s->ringbuffer[(pos - s->distance_code) &
+                                    s->ringbuffer_mask];
+          copy_dst = &s->ringbuffer[pos];
+          /* update the recent distances cache */
+          s->dist_rb[s->dist_rb_idx & 3] = s->distance_code;
+          ++s->dist_rb_idx;
+          s->meta_block_remaining_len -= i;
+          if (PREDICT_FALSE(s->meta_block_remaining_len < 0)) {
+            BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d "
+                   "len: %d bytes left: %d\n", pos, s->distance_code, i,
+                   s->meta_block_remaining_len));
+            result = BROTLI_FAILURE();
+            break;
+          }
+          /* There is 128+ bytes of slack in the ringbuffer allocation.
+             Also, we have 16 short codes, that make these 16 bytes irrelevant
+             in the ringbuffer. Let's copy over them as a first guess.
+           */
+          memmove16(copy_dst, copy_src);
+          /* Now check if the copy extends over the ringbuffer end,
+             or if the copy overlaps with itself, if yes, do wrap-copy. */
+          if (copy_src < copy_dst) {
+            if (copy_dst >= ringbuffer_end_minus_copy_length) {
+              goto postWrapCopy;
+            }
+            if (copy_src + i > copy_dst) {
+              goto postSelfintersecting;
+            }
+          } else {
+            if (copy_src >= ringbuffer_end_minus_copy_length) {
+              goto postWrapCopy;
+            }
+            if (copy_dst + i > copy_src) {
+              goto postSelfintersecting;
+            }
+          }
+          pos += i;
+          if (i > 16) {
+            if (i > 32) {
+              memcpy(copy_dst + 16, copy_src + 16, (size_t)(i - 16));
+            } else {
+              /* This branch covers about 45% cases.
+                 Fixed size short copy allows more compiler optimizations. */
+              memmove16(copy_dst + 16, copy_src + 16);
+            }
+          }
+        }
+        if (s->meta_block_remaining_len <= 0) {
+          /* Next metablock, if any */
+          s->state = BROTLI_STATE_METABLOCK_DONE;
+          break;
+        } else {
+          goto CommandBegin;
+        }
+      postSelfintersecting:
+        while (--i >= 0) {
+          s->ringbuffer[pos] =
+              s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask];
+          ++pos;
+        }
+        if (s->meta_block_remaining_len <= 0) {
+          /* Next metablock, if any */
+          s->state = BROTLI_STATE_METABLOCK_DONE;
+          break;
+        } else {
+          goto CommandBegin;
+        }
+      postWrapCopy:
+        s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
+        /* No break, go to next state */
+      case BROTLI_STATE_COMMAND_POST_WRAP_COPY:
+        while (--i >= 0) {
+          s->ringbuffer[pos] =
+              s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask];
+          ++pos;
+          if (pos == s->ringbuffer_size) {
+            s->to_write = s->ringbuffer_size;
+            s->partially_written = 0;
+            s->state = BROTLI_STATE_COMMAND_POST_WRITE_2;
+            break;
+          }
+        }
+        if (s->state == BROTLI_STATE_COMMAND_POST_WRAP_COPY) {
+          if (s->meta_block_remaining_len <= 0) {
+            /* Next metablock, if any */
+            s->state = BROTLI_STATE_METABLOCK_DONE;
+            break;
+          } else {
+            goto CommandBegin;
+          }
+        }
+        break;
+      case BROTLI_STATE_COMMAND_INNER_WRITE:
+      case BROTLI_STATE_COMMAND_POST_WRITE_1:
+      case BROTLI_STATE_COMMAND_POST_WRITE_2:
+innerWrite:
+        result = WriteRingBuffer(output, s);
+        if (result != BROTLI_RESULT_SUCCESS) {
+          break;
+        }
+        pos -= s->ringbuffer_size;
+        s->max_distance = s->max_backward_distance;
+        if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) {
+          memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)pos);
+          if (s->meta_block_remaining_len <= 0) {
+            /* Next metablock, if any */
+            s->state = BROTLI_STATE_METABLOCK_DONE;
+            break;
+          } else {
+            goto CommandBegin;
+          }
+        } else if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_2) {
+          s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY;
+        } else {  /* BROTLI_STATE_COMMAND_INNER_WRITE */
+          if (i == 0) {
+            if (s->meta_block_remaining_len <= 0) {
+              s->state = BROTLI_STATE_METABLOCK_DONE;
+              break;
+            }
+            goto postDecodeLiterals;
+          }
+          s->state = BROTLI_STATE_COMMAND_INNER;
+        }
+        break;
+      case BROTLI_STATE_METABLOCK_DONE:
+        BrotliStateCleanupAfterMetablock(s);
+        s->state = BROTLI_STATE_METABLOCK_BEGIN;
+        break;
+      case BROTLI_STATE_DONE:
+        if (s->ringbuffer != 0) {
+          result = WriteRingBuffer(output, s);
+          if (result != BROTLI_RESULT_SUCCESS) {
+            break;
+          }
+        }
+        if (!BrotliJumpToByteBoundary(br)) {
+          result = BROTLI_FAILURE();
+        }
+        if (BrotliGetRemainingBytes(br) < BROTLI_IMPLICIT_ZEROES) {
+          /* The brotli input stream was too small, does not follow the spec. It
+          might have decompressed fine because of the implicit 128 zeroes added.
+          NOTE: larger input is allowed, smaller not. */
+          result = BROTLI_FAILURE();
+        }
+        return result;
     }
   }
-
-  while (!input_end && ok) {
-    int meta_block_remaining_len = 0;
-    int is_uncompressed;
-    int block_length[3] = { 1 << 28, 1 << 28, 1 << 28 };
-    int block_type[3] = { 0 };
-    int num_block_types[3] = { 1, 1, 1 };
-    int block_type_rb[6] = { 0, 1, 0, 1, 0, 1 };
-    int block_type_rb_index[3] = { 0 };
-    int distance_postfix_bits;
-    int num_direct_distance_codes;
-    int distance_postfix_mask;
-    int num_distance_codes;
-    uint8_t* context_map = NULL;
-    uint8_t* context_modes = NULL;
-    int num_literal_htrees;
-    uint8_t* dist_context_map = NULL;
-    int num_dist_htrees;
-    int context_offset = 0;
-    uint8_t* context_map_slice = NULL;
-    uint8_t literal_htree_index = 0;
-    int dist_context_offset = 0;
-    uint8_t* dist_context_map_slice = NULL;
-    uint8_t dist_htree_index = 0;
-    int context_lookup_offset1 = 0;
-    int context_lookup_offset2 = 0;
-    uint8_t context_mode;
-    HuffmanCode* htree_command;
-
-    for (i = 0; i < 3; ++i) {
-      hgroup[i].codes = NULL;
-      hgroup[i].htrees = NULL;
-    }
-
-    if (!BrotliReadMoreInput(&br)) {
-      printf("[BrotliDecompress] Unexpected end of input.\n");
-      ok = 0;
-      goto End;
-    }
-    BROTLI_LOG_UINT(pos);
-    DecodeMetaBlockLength(&br, &meta_block_remaining_len,
-                          &input_end, &is_uncompressed);
-    BROTLI_LOG_UINT(meta_block_remaining_len);
-    if (meta_block_remaining_len == 0) {
-      goto End;
-    }
-    if (is_uncompressed) {
-      BrotliSetBitPos(&br, (br.bit_pos_ + 7) & (uint32_t)(~7UL));
-      ok = CopyUncompressedBlockToOutput(output, meta_block_remaining_len, pos,
-                                         ringbuffer, ringbuffer_mask, &br);
-      pos += meta_block_remaining_len;
-      goto End;
-    }
-    for (i = 0; i < 3; ++i) {
-      num_block_types[i] = DecodeVarLenUint8(&br) + 1;
-      if (num_block_types[i] >= 2) {
-        if (!ReadHuffmanCode(num_block_types[i] + 2,
-                             &block_type_trees[i * HUFFMAN_MAX_TABLE_SIZE],
-                             &br) ||
-            !ReadHuffmanCode(kNumBlockLengthCodes,
-                             &block_len_trees[i * HUFFMAN_MAX_TABLE_SIZE],
-                             &br)) {
-          ok = 0;
-          goto End;
-        }
-        block_length[i] = ReadBlockLength(
-            &block_len_trees[i * HUFFMAN_MAX_TABLE_SIZE], &br);
-        block_type_rb_index[i] = 1;
-      }
-    }
-
-    BROTLI_LOG_UINT(num_block_types[0]);
-    BROTLI_LOG_UINT(num_block_types[1]);
-    BROTLI_LOG_UINT(num_block_types[2]);
-    BROTLI_LOG_UINT(block_length[0]);
-    BROTLI_LOG_UINT(block_length[1]);
-    BROTLI_LOG_UINT(block_length[2]);
-
-    if (!BrotliReadMoreInput(&br)) {
-      printf("[BrotliDecompress] Unexpected end of input.\n");
-      ok = 0;
-      goto End;
-    }
-    distance_postfix_bits = (int)BrotliReadBits(&br, 2);
-    num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES +
-        ((int)BrotliReadBits(&br, 4) << distance_postfix_bits);
-    distance_postfix_mask = (1 << distance_postfix_bits) - 1;
-    num_distance_codes = (num_direct_distance_codes +
-                          (48 << distance_postfix_bits));
-    context_modes = (uint8_t*)malloc((size_t)num_block_types[0]);
-    if (context_modes == 0) {
-      ok = 0;
-      goto End;
-    }
-    for (i = 0; i < num_block_types[0]; ++i) {
-      context_modes[i] = (uint8_t)(BrotliReadBits(&br, 2) << 1);
-      BROTLI_LOG_ARRAY_INDEX(context_modes, i);
-    }
-    BROTLI_LOG_UINT(num_direct_distance_codes);
-    BROTLI_LOG_UINT(distance_postfix_bits);
-
-    if (!DecodeContextMap(num_block_types[0] << kLiteralContextBits,
-                          &num_literal_htrees, &context_map, &br) ||
-        !DecodeContextMap(num_block_types[2] << kDistanceContextBits,
-                          &num_dist_htrees, &dist_context_map, &br)) {
-      ok = 0;
-      goto End;
-    }
-
-    HuffmanTreeGroupInit(&hgroup[0], kNumLiteralCodes, num_literal_htrees);
-    HuffmanTreeGroupInit(&hgroup[1], kNumInsertAndCopyCodes,
-                         num_block_types[1]);
-    HuffmanTreeGroupInit(&hgroup[2], num_distance_codes, num_dist_htrees);
-
-    for (i = 0; i < 3; ++i) {
-      if (!HuffmanTreeGroupDecode(&hgroup[i], &br)) {
-        ok = 0;
-        goto End;
-      }
-    }
-
-    context_map_slice = context_map;
-    dist_context_map_slice = dist_context_map;
-    context_mode = context_modes[block_type[0]];
-    context_lookup_offset1 = kContextLookupOffsets[context_mode];
-    context_lookup_offset2 = kContextLookupOffsets[context_mode + 1];
-    htree_command = hgroup[1].htrees[0];
+  s->pos = pos;
+  s->loop_counter = i;
+  return result;
+}
 
-    while (meta_block_remaining_len > 0) {
-      int cmd_code;
-      int range_idx;
-      int insert_code;
-      int copy_code;
-      int insert_length;
-      int copy_length;
-      int distance_code;
-      int distance;
-      uint8_t context;
-      int j;
-      const uint8_t* copy_src;
-      uint8_t* copy_dst;
-      if (!BrotliReadMoreInput(&br)) {
-        printf("[BrotliDecompress] Unexpected end of input.\n");
-        ok = 0;
-        goto End;
-      }
-      if (block_length[1] == 0) {
-        DecodeBlockType(num_block_types[1],
-                        block_type_trees, 1, block_type, block_type_rb,
-                        block_type_rb_index, &br);
-        block_length[1] = ReadBlockLength(
-            &block_len_trees[HUFFMAN_MAX_TABLE_SIZE], &br);
-        htree_command = hgroup[1].htrees[block_type[1]];
-      }
-      --block_length[1];
-      cmd_code = ReadSymbol(htree_command, &br);
-      range_idx = cmd_code >> 6;
-      if (range_idx >= 2) {
-        range_idx -= 2;
-        distance_code = -1;
-      } else {
-        distance_code = 0;
-      }
-      insert_code = kInsertRangeLut[range_idx] + ((cmd_code >> 3) & 7);
-      copy_code = kCopyRangeLut[range_idx] + (cmd_code & 7);
-      insert_length = kInsertLengthPrefixCode[insert_code].offset +
-          (int)BrotliReadBits(&br, kInsertLengthPrefixCode[insert_code].nbits);
-      copy_length = kCopyLengthPrefixCode[copy_code].offset +
-          (int)BrotliReadBits(&br, kCopyLengthPrefixCode[copy_code].nbits);
-      BROTLI_LOG_UINT(insert_length);
-      BROTLI_LOG_UINT(copy_length);
-      BROTLI_LOG_UINT(distance_code);
-      for (j = 0; j < insert_length; ++j) {
-        if (!BrotliReadMoreInput(&br)) {
-          printf("[BrotliDecompress] Unexpected end of input.\n");
-          ok = 0;
-          goto End;
-        }
-        if (block_length[0] == 0) {
-          DecodeBlockType(num_block_types[0],
-                          block_type_trees, 0, block_type, block_type_rb,
-                          block_type_rb_index, &br);
-          block_length[0] = ReadBlockLength(block_len_trees, &br);
-          context_offset = block_type[0] << kLiteralContextBits;
-          context_map_slice = context_map + context_offset;
-          context_mode = context_modes[block_type[0]];
-          context_lookup_offset1 = kContextLookupOffsets[context_mode];
-          context_lookup_offset2 = kContextLookupOffsets[context_mode + 1];
-        }
-        context = (kContextLookup[context_lookup_offset1 + prev_byte1] |
-                   kContextLookup[context_lookup_offset2 + prev_byte2]);
-        BROTLI_LOG_UINT(context);
-        literal_htree_index = context_map_slice[context];
-        --block_length[0];
-        prev_byte2 = prev_byte1;
-        prev_byte1 = (uint8_t)ReadSymbol(hgroup[0].htrees[literal_htree_index],
-                                         &br);
-        ringbuffer[pos & ringbuffer_mask] = prev_byte1;
-        BROTLI_LOG_UINT(literal_htree_index);
-        BROTLI_LOG_ARRAY_INDEX(ringbuffer, pos & ringbuffer_mask);
-        if ((pos & ringbuffer_mask) == ringbuffer_mask) {
-          if (BrotliWrite(output, ringbuffer, (size_t)ringbuffer_size) < 0) {
-            ok = 0;
-            goto End;
-          }
-        }
-        ++pos;
-      }
-      meta_block_remaining_len -= insert_length;
-      if (meta_block_remaining_len <= 0) break;
-
-      if (distance_code < 0) {
-        uint8_t context;
-        if (!BrotliReadMoreInput(&br)) {
-          printf("[BrotliDecompress] Unexpected end of input.\n");
-          ok = 0;
-          goto End;
-        }
-        if (block_length[2] == 0) {
-          DecodeBlockType(num_block_types[2],
-                          block_type_trees, 2, block_type, block_type_rb,
-                          block_type_rb_index, &br);
-          block_length[2] = ReadBlockLength(
-              &block_len_trees[2 * HUFFMAN_MAX_TABLE_SIZE], &br);
-          dist_context_offset = block_type[2] << kDistanceContextBits;
-          dist_context_map_slice = dist_context_map + dist_context_offset;
-        }
-        --block_length[2];
-        context = (uint8_t)(copy_length > 4 ? 3 : copy_length - 2);
-        dist_htree_index = dist_context_map_slice[context];
-        distance_code = ReadSymbol(hgroup[2].htrees[dist_htree_index], &br);
-        if (distance_code >= num_direct_distance_codes) {
-          int nbits;
-          int postfix;
-          int offset;
-          distance_code -= num_direct_distance_codes;
-          postfix = distance_code & distance_postfix_mask;
-          distance_code >>= distance_postfix_bits;
-          nbits = (distance_code >> 1) + 1;
-          offset = ((2 + (distance_code & 1)) << nbits) - 4;
-          distance_code = num_direct_distance_codes +
-              ((offset + (int)BrotliReadBits(&br, nbits)) <<
-               distance_postfix_bits) + postfix;
-        }
-      }
-
-      /* Convert the distance code to the actual distance by possibly looking */
-      /* up past distnaces from the ringbuffer. */
-      distance = TranslateShortCodes(distance_code, dist_rb, dist_rb_idx);
-      if (distance < 0) {
-        ok = 0;
-        goto End;
-      }
-      BROTLI_LOG_UINT(distance);
-
-      if (pos < max_backward_distance &&
-          max_distance != max_backward_distance) {
-        max_distance = pos;
-      } else {
-        max_distance = max_backward_distance;
-      }
-
-      copy_dst = &ringbuffer[pos & ringbuffer_mask];
-
-      if (distance > max_distance) {
-        if (copy_length >= kMinDictionaryWordLength &&
-            copy_length <= kMaxDictionaryWordLength) {
-          int offset = kBrotliDictionaryOffsetsByLength[copy_length];
-          int word_id = distance - max_distance - 1;
-          int shift = kBrotliDictionarySizeBitsByLength[copy_length];
-          int mask = (1 << shift) - 1;
-          int word_idx = word_id & mask;
-          int transform_idx = word_id >> shift;
-          offset += word_idx * copy_length;
-          if (transform_idx < kNumTransforms) {
-            const uint8_t* word = &kBrotliDictionary[offset];
-            int len = TransformDictionaryWord(
-                copy_dst, word, copy_length, transform_idx);
-            copy_dst += len;
-            pos += len;
-            meta_block_remaining_len -= len;
-            if (copy_dst >= ringbuffer_end) {
-              if (BrotliWrite(output, ringbuffer,
-                              (size_t)ringbuffer_size) < 0) {
-                ok = 0;
-                goto End;
-              }
-              memcpy(ringbuffer, ringbuffer_end,
-                     (size_t)(copy_dst - ringbuffer_end));
-            }
-          } else {
-            printf("Invalid backward reference. pos: %d distance: %d "
-                   "len: %d bytes left: %d\n", pos, distance, copy_length,
-                   meta_block_remaining_len);
-            ok = 0;
-            goto End;
-          }
-        } else {
-          printf("Invalid backward reference. pos: %d distance: %d "
-                 "len: %d bytes left: %d\n", pos, distance, copy_length,
-                 meta_block_remaining_len);
-          ok = 0;
-          goto End;
-        }
-      } else {
<