merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 11 Feb 2016 11:52:01 +0100
changeset 283920 d4d72e7b30da251ad3027e234444251adad5e335
parent 283919 b21946a2e9933fa9167456ce6b3866381f6f52c5 (current diff)
parent 283859 97c7a71cce023044f6c1bf84d8a3a0affa7cc219 (diff)
child 283921 7d7b25df9fe88961e5b1c4ce04c6d8a306f284c6
child 284094 904f3554c08488c53d24deb20a486600ddddd56b
child 284103 7a7c04a6d9df6a5d4c7272208b6b6972dd5f71b8
push id71744
push usercbook@mozilla.com
push dateThu, 11 Feb 2016 10:56:31 +0000
treeherdermozilla-inbound@7d7b25df9fe8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone47.0a1
first release with
nightly linux32
d4d72e7b30da / 47.0a1 / 20160211030242 / files
nightly linux64
d4d72e7b30da / 47.0a1 / 20160211030242 / files
nightly mac
d4d72e7b30da / 47.0a1 / 20160211030242 / files
nightly win32
d4d72e7b30da / 47.0a1 / 20160211030242 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
merge mozilla-inbound to mozilla-central a=merge
mobile/android/app/mobile.js
testing/mozbase/docs/mozhttpd.rst
testing/mozbase/mozhttpd/mozhttpd/__init__.py
testing/mozbase/mozhttpd/mozhttpd/handlers.py
testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py
testing/mozbase/mozhttpd/setup.py
testing/mozbase/mozhttpd/tests/api.py
testing/mozbase/mozhttpd/tests/filelisting.py
testing/mozbase/mozhttpd/tests/manifest.ini
testing/mozbase/mozhttpd/tests/requestlog.py
testing/mozharness/scripts/merge_day/b2g_tag.py
toolkit/components/telemetry/Histograms.json
--- a/accessible/tests/mochitest/relations/test_embeds.xul
+++ b/accessible/tests/mochitest/relations/test_embeds.xul
@@ -94,33 +94,33 @@
       {
         return "load uri '" + aURI + "' in new tab";
       }
     }
 
     ////////////////////////////////////////////////////////////////////////////
     // Testing
 
-    //gA11yEventDumpToConsole = true; // debug
+    gA11yEventDumpToConsole = true; // debug
 
     var gQueue = null;
     function doTests()
     {
       testRelation(browserDocument(), RELATION_EMBEDS,
                    getAccessible(currentTabDocument()));
 
-      //enableLogging("docload");
+      enableLogging("docload");
       gQueue = new eventQueue();
 
       gQueue.push(new loadURI("about:about"));
       gQueue.push(new loadOneTab("about:mozilla"));
 
       gQueue.onFinish = function()
       {
-        //disableLogging();
+        disableLogging();
         closeBrowserWindow();
       }
       gQueue.invoke();
     }
 
     SimpleTest.waitForExplicitFinish();
     openBrowserWindow(doTests, "about:");
   ]]>
--- a/b2g/config/emulator-ics/releng-emulator-ics.tt
+++ b/b2g/config/emulator-ics/releng-emulator-ics.tt
@@ -2,15 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/b2g/config/emulator-jb/releng-emulator-jb.tt
+++ b/b2g/config/emulator-jb/releng-emulator-jb.tt
@@ -2,15 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/b2g/config/emulator-kk/releng-emulator-kk.tt
+++ b/b2g/config/emulator-kk/releng-emulator-kk.tt
@@ -2,15 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/b2g/config/emulator-l/releng-emulator-l.tt
+++ b/b2g/config/emulator-l/releng-emulator-l.tt
@@ -2,15 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/b2g/config/emulator-x86-kk/releng-emulator-kk.tt
+++ b/b2g/config/emulator-x86-kk/releng-emulator-kk.tt
@@ -2,15 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/b2g/config/emulator-x86-l/releng-emulator-l.tt
+++ b/b2g/config/emulator-x86-l/releng-emulator-l.tt
@@ -2,15 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/b2g/config/emulator/releng-emulator.tt
+++ b/b2g/config/emulator/releng-emulator.tt
@@ -2,15 +2,16 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/b2g/config/tooltool-manifests/linux32/releng.manifest
+++ b/b2g/config/tooltool-manifests/linux32/releng.manifest
@@ -2,18 +2,18 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 11179576,
-"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
+"size": 11189216,
+"digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
--- a/b2g/dev/config/tooltool-manifests/linux64/releng.manifest
+++ b/b2g/dev/config/tooltool-manifests/linux64/releng.manifest
@@ -2,18 +2,18 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 },
 {
 "size": 80164520,
 "digest": "26fd5301aaf6174a0e4f2ac3a8d19f39573f78a051aa78e876c065d60421b2b62207c11fbf1f20f92ba61acc4b9ce58d05409bf5af886943891b04c3d22f5e04",
--- a/b2g/graphene/graphene.js
+++ b/b2g/graphene/graphene.js
@@ -25,19 +25,16 @@ pref("layout.css.scroll-snap.enabled", t
 pref("dom.mozInputMethod.enabled", false);
 pref("browser.autofocus", true);
 pref("layers.async-pan-zoom.enabled", false);
 pref("network.predictor.enabled", true);
 
 // No AccessibleCaret
 pref("layout.accessiblecaret.enabled", false);
 
-pref("gfx.vsync.hw-vsync.enabled", true);
-pref("gfx.vsync.compositor", true);
-
 // To be removed once bug 942756 is fixed.
 pref("devtools.debugger.unix-domain-socket", "6000");
 
 pref("devtools.debugger.forbid-certified-apps", false);
 pref("devtools.debugger.prompt-connection", false);
 
 // Update url.
 pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -57,16 +57,22 @@ pref("extensions.blocklist.enabled", tru
 pref("extensions.blocklist.interval", 86400);
 // Controls what level the blocklist switches from warning about items to forcibly
 // blocking them.
 pref("extensions.blocklist.level", 2);
 pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
 pref("extensions.blocklist.detailsURL", "https://www.mozilla.org/%LOCALE%/blocklist/");
 pref("extensions.blocklist.itemURL", "https://blocklist.addons.mozilla.org/%LOCALE%/%APP%/blocked/%blockID%");
 
+// Kinto blocklist preferences
+pref("services.kinto.base", "https://firefox.settings.services.mozilla.com/v1");
+pref("services.kinto.bucket", "blocklists");
+pref("services.kinto.onecrl.collection", "certificates");
+pref("services.kinto.onecrl.checked", 0);
+
 pref("extensions.update.autoUpdateDefault", true);
 
 pref("extensions.hotfix.id", "firefox-hotfix@mozilla.org");
 pref("extensions.hotfix.cert.checkAttributes", true);
 pref("extensions.hotfix.certs.1.sha1Fingerprint", "91:53:98:0C:C1:86:DF:47:8F:35:22:9E:11:C9:A7:31:04:49:A1:AA");
 pref("extensions.hotfix.certs.2.sha1Fingerprint", "39:E7:2B:7A:5B:CF:37:78:F9:5D:4A:E0:53:2D:2F:3D:68:53:C5:60");
 
 // Check AUS for system add-on updates.
--- a/browser/config/mozconfigs/linux64/beta
+++ b/browser/config/mozconfigs/linux64/beta
@@ -6,9 +6,10 @@ fi
 
 . "$topsrcdir/browser/config/mozconfigs/linux64/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 mk_add_options MOZ_PGO=1
 
+. "$topsrcdir/build/mozconfig.rust"
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/linux64/release
+++ b/browser/config/mozconfigs/linux64/release
@@ -13,9 +13,10 @@ ac_add_options --enable-official-brandin
 ac_add_options --enable-verify-mar
 
 mk_add_options MOZ_PGO=1
 
 # safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
 # defines.sh during the beta cycle
 export BUILDING_RELEASE=1
 
+. "$topsrcdir/build/mozconfig.rust"
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/config/mozconfigs/macosx-universal/beta
+++ b/browser/config/mozconfigs/macosx-universal/beta
@@ -5,10 +5,11 @@ if [ -n "$ENABLE_RELEASE_PROMOTION" ]; t
   MOZ_AUTOMATION_UPDATE_PACKAGING=1
 fi
 
 . "$topsrcdir/browser/config/mozconfigs/macosx-universal/common-opt"
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
+. "$topsrcdir/build/mozconfig.rust"
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/macosx-universal/release
+++ b/browser/config/mozconfigs/macosx-universal/release
@@ -11,10 +11,11 @@ fi
 
 ac_add_options --enable-official-branding
 ac_add_options --enable-verify-mar
 
 # safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
 # defines.sh during the beta cycle
 export BUILDING_RELEASE=1
 
+. "$topsrcdir/build/mozconfig.rust"
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/whitelist
+++ b/browser/config/mozconfigs/whitelist
@@ -35,30 +35,28 @@ whitelist['nightly']['linux32'] += [
 
 whitelist['nightly']['linux64'] += [
     'export MOZILLA_OFFICIAL=1',
     'export MOZ_TELEMETRY_REPORTING=1',
     "mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'",
     'STRIP_FLAGS="--strip-debug"',
     'ac_add_options --with-ccache=/usr/bin/ccache',
     '. "$topsrcdir/build/mozconfig.cache"',
-    '. "$topsrcdir/build/mozconfig.rust"',
 ]
 
 whitelist['nightly']['macosx-universal'] += [
     'if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then',
     'ac_add_options --with-macbundlename-prefix=Firefox',
     'fi',
     'mk_add_options MOZ_MAKE_FLAGS="-j12"',
     'ac_add_options --with-ccache',
     '. "$topsrcdir/build/mozconfig.cache"',
     'ac_add_options --disable-install-strip',
     'ac_add_options --enable-instruments',
     'ac_add_options --enable-dtrace',
-    '. "$topsrcdir/build/mozconfig.rust"',
 ]
 
 whitelist['nightly']['win32'] += [
     '. $topsrcdir/configs/mozilla2/win32/include/choose-make-flags',
     'mk_add_options MOZ_MAKE_FLAGS=-j1',
     '. "$topsrcdir/build/mozconfig.cache"',
     'if test "$IS_NIGHTLY" != ""; then',
     'ac_add_options --disable-auto-deps',
--- a/browser/config/tooltool-manifests/linux32/releng.manifest
+++ b/browser/config/tooltool-manifests/linux32/releng.manifest
@@ -2,20 +2,21 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512", 
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 11179576,
-"digest": "91567ce8e2bb8ab0ebc60c31e90731d88a1ea889fb71bcf55c735746a60fa7610b7e040ea3d8f727b6f692ae3ee703d6f3b30cdbd76fdf5617f77d9c38aa20ed",
+"size": 11189216,
+"digest": "18bc52b0599b1308b667e282abb45f47597bfc98a5140cfcab8da71dacf89dd76d0dee22a04ce26fe7ad1f04e2d6596991f9e5b01fd2aaaab5542965f596b0e6",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
--- a/browser/config/tooltool-manifests/linux64/asan.manifest
+++ b/browser/config/tooltool-manifests/linux64/asan.manifest
@@ -5,16 +5,16 @@
 {
 "size": 71282740, 
 "digest": "ee9edb1ef3afd9ab29e39565145545ad57e8d8d2538be4d822d7dbd64038f4529b0b287cecf48bf83def52a26ac2c6faa331686c3ad5e8b4ba4c22686ee0808f", 
 "algorithm": "sha512", 
 "filename": "clang.tar.bz2",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
 "setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/clang.manifest
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest
@@ -5,20 +5,21 @@
 {
 "size": 106877168,
 "digest": "1c50c6348eaf429ed59bb603cff63bcc1f870f59216dd3c234db5b1156cfd351d5ee7b820ec31be4d2661eb4213b2e0030e2ba2782b42905d1ec19c7f8bd322a",
 "algorithm": "sha512",
 "filename": "clang.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
 "filename": "sccache.tar.bz2",
 "unpack": true
--- a/browser/config/tooltool-manifests/linux64/clang.manifest.centos6
+++ b/browser/config/tooltool-manifests/linux64/clang.manifest.centos6
@@ -5,15 +5,16 @@
 {
 "size": 106877168,
 "digest": "1c50c6348eaf429ed59bb603cff63bcc1f870f59216dd3c234db5b1156cfd351d5ee7b820ec31be4d2661eb4213b2e0030e2ba2782b42905d1ec19c7f8bd322a",
 "algorithm": "sha512",
 "filename": "clang.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/browser/config/tooltool-manifests/linux64/releng.manifest
+++ b/browser/config/tooltool-manifests/linux64/releng.manifest
@@ -2,20 +2,21 @@
 {
 "size": 80458572,
 "digest": "e5101f9dee1e462f6cbd3897ea57eede41d23981825c7b20d91d23ab461875d54d3dfc24999aa58a31e8b01f49fb3140e05ffe5af2957ef1d1afb89fd0dfe1ad",
 "algorithm": "sha512", 
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 },
 {
 "size": 80164520,
 "digest": "26fd5301aaf6174a0e4f2ac3a8d19f39573f78a051aa78e876c065d60421b2b62207c11fbf1f20f92ba61acc4b9ce58d05409bf5af886943891b04c3d22f5e04",
 "algorithm": "sha512",
 "filename": "rustc.tar.xz",
 "unpack": true
--- a/browser/config/tooltool-manifests/linux64/tsan.manifest
+++ b/browser/config/tooltool-manifests/linux64/tsan.manifest
@@ -5,15 +5,16 @@
 {
 "size": 89690541, 
 "digest": "470d258d9785a120fcba65eee90daa632a42affa0f97f57d70fc8285bd76bcc27d4d0d70b6c37577ab271a04c843b6269425391a8d6df1967718dba26dd3a73d", 
 "algorithm": "sha512", 
 "filename": "clang.tar.bz2",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -1,19 +1,22 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import print_function, unicode_literals
 
 import errno
+import json
 import os
 import platform
+import random
 import sys
 import time
+import uuid
 import __builtin__
 
 from types import ModuleType
 
 
 STATE_DIR_FIRST_RUN = '''
 mach and the build system store shared state in a common directory on the
 filesystem. The following directory will be created:
@@ -62,16 +65,17 @@ SEARCH_PATHS = [
     'python/pystache',
     'python/pyyaml/lib',
     'python/requests',
     'python/slugid',
     'build',
     'config',
     'dom/bindings',
     'dom/bindings/parser',
+    'dom/media/test/external',
     'layout/tools/reftest',
     'other-licenses/ply',
     'testing',
     'testing/firefox-ui/harness',
     'testing/firefox-ui/tests',
     'testing/luciddream',
     'testing/marionette/client',
     'testing/marionette/client/marionette/runner/mixins/browsermob-proxy-py',
@@ -104,16 +108,17 @@ SEARCH_PATHS = [
     'xpcom/idl-parser',
 ]
 
 # Individual files providing mach commands.
 MACH_MODULES = [
     'addon-sdk/mach_commands.py',
     'build/valgrind/mach_commands.py',
     'dom/bindings/mach_commands.py',
+    'dom/media/test/external/mach_commands.py',
     'layout/tools/reftest/mach_commands.py',
     'python/mach_commands.py',
     'python/mach/mach/commands/commandinfo.py',
     'python/compare-locales/mach_commands.py',
     'python/mozboot/mozboot/mach_commands.py',
     'python/mozbuild/mozbuild/mach_commands.py',
     'python/mozbuild/mozbuild/backend/mach_commands.py',
     'python/mozbuild/mozbuild/compilation/codecomplete.py',
@@ -176,16 +181,24 @@ CATEGORIES = {
     'disabled': {
         'short': 'Disabled',
         'long': 'The disabled commands are hidden by default. Use -v to display them. These commands are unavailable for your current context, run "mach <command>" to see why.',
         'priority': 0,
     }
 }
 
 
+# Server to which to submit telemetry data
+BUILD_TELEMETRY_SERVER = 'http://52.88.27.118/build-metrics-dev'
+
+
+# We submit data to telemetry approximately every this many mach invocations
+TELEMETRY_SUBMISSION_FREQUENCY = 10
+
+
 def get_state_dir():
     """Obtain the path to a directory to hold state.
 
     Returns a tuple of the path and a bool indicating whether the value came
     from an environment variable.
     """
     state_user_dir = os.path.expanduser('~/.mozbuild')
     state_env_dir = os.environ.get('MOZBUILD_STATE_PATH', None)
@@ -217,43 +230,74 @@ def bootstrap(topsrcdir, mozilla_dir=Non
     # to react. We always exit after creating the directory because users don't
     # like surprises.
     try:
         import mach.main
     except ImportError:
         sys.path[0:0] = [os.path.join(mozilla_dir, path) for path in SEARCH_PATHS]
         import mach.main
 
+    def telemetry_handler(context, data):
+        # We have not opted-in to telemetry
+        if 'BUILD_SYSTEM_TELEMETRY' not in os.environ:
+            return
+
+        telemetry_dir = os.path.join(get_state_dir()[0], 'telemetry')
+        try:
+            os.mkdir(telemetry_dir)
+        except OSError as e:
+            if e.errno != errno.EEXIST:
+                raise
+        outgoing_dir = os.path.join(telemetry_dir, 'outgoing')
+        try:
+            os.mkdir(outgoing_dir)
+        except OSError as e:
+            if e.errno != errno.EEXIST:
+                raise
+
+        # Add common metadata to help submit sorted data later on.
+        # For now, we'll just record the mach command that was invoked.
+        data['argv'] = sys.argv
+
+        with open(os.path.join(outgoing_dir, str(uuid.uuid4()) + '.json'),
+                  'w') as f:
+            json.dump(data, f, sort_keys=True)
+
+    def should_skip_dispatch(context, handler):
+        # The user is performing a maintenance command.
+        if handler.name in ('bootstrap', 'doctor', 'mach-commands', 'mercurial-setup'):
+            return True
+
+        # We are running in automation.
+        if 'MOZ_AUTOMATION' in os.environ or 'TASK_ID' in os.environ:
+            return True
+
+        # The environment is likely a machine invocation.
+        if sys.stdin.closed or not sys.stdin.isatty():
+            return True
+
+        return False
+
     def pre_dispatch_handler(context, handler, args):
         """Perform global checks before command dispatch.
 
         Currently, our goal is to ensure developers periodically run
         `mach mercurial-setup` (when applicable) to ensure their Mercurial
         tools are up to date.
         """
         # Don't do anything when...
-
-        # The user is performing a maintenance command.
-        if handler.name in ('bootstrap', 'doctor', 'mach-commands', 'mercurial-setup'):
-            return
-
-        # We are running in automation.
-        if 'MOZ_AUTOMATION' in os.environ or 'TASK_ID' in os.environ:
+        if should_skip_dispatch(context, handler):
             return
 
         # User has disabled first run check.
         if 'I_PREFER_A_SUBOPTIMAL_MERCURIAL_EXPERIENCE' in os.environ:
             return
         if 'NO_MERCURIAL_SETUP_CHECK' in os.environ:
             return
 
-        # The environment is likely a machine invocation.
-        if sys.stdin.closed or not sys.stdin.isatty():
-            return
-
         # Mercurial isn't managing this source checkout.
         if not os.path.exists(os.path.join(topsrcdir, '.hg')):
             return
 
         state_dir = get_state_dir()[0]
         last_check_path = os.path.join(state_dir, 'mercurial',
                                        'setup.lastcheck')
 
@@ -264,16 +308,78 @@ def bootstrap(topsrcdir, mozilla_dir=Non
             if e.errno != errno.ENOENT:
                 raise
 
         # No last run file means mercurial-setup has never completed.
         if mtime is None:
             print(NO_MERCURIAL_SETUP.format(mach=sys.argv[0]), file=sys.stderr)
             sys.exit(2)
 
+    def post_dispatch_handler(context, handler, args):
+        """Perform global operations after command dispatch.
+
+
+        For now,  we will use this to handle build system telemetry.
+        """
+        # Don't do anything when...
+        if should_skip_dispatch(context, handler):
+            return
+
+        # We have not opted-in to telemetry
+        if 'BUILD_SYSTEM_TELEMETRY' not in os.environ:
+            return
+
+        # Every n-th operation
+        if random.randint(1, TELEMETRY_SUBMISSION_FREQUENCY) != 1:
+            return
+
+        # No data to work with anyway
+        outgoing = os.path.join(get_state_dir()[0], 'telemetry', 'outgoing')
+        if not os.path.isdir(outgoing):
+            return
+
+        # We can't import requests until after it has been added during the
+        # bootstrapping below.
+        import requests
+
+        submitted = os.path.join(get_state_dir()[0], 'telemetry', 'submitted')
+        try:
+            os.mkdir(submitted)
+        except OSError as e:
+            if e.errno != errno.EEXIST:
+                raise
+
+        session = requests.Session()
+        for filename in os.listdir(outgoing):
+            path = os.path.join(outgoing, filename)
+            if os.path.isdir(path) or not path.endswith('.json'):
+                continue
+            with open(path, 'r') as f:
+                data = f.read()
+                r = session.post(BUILD_TELEMETRY_SERVER, data=data,
+                                 headers={'Content-Type': 'application/json'})
+                # TODO: some of these errors are likely not recoverable, as
+                # written, we'll retry indefinitely
+                if r.status_code != 200:
+                    print('Error posting to telemetry: %s %s' %
+                          (r.status_code, r.text))
+                    continue
+
+            os.rename(os.path.join(outgoing, filename),
+                      os.path.join(submitted, filename))
+
+        session.close()
+
+        # Discard submitted data that is >= 30 days old
+        now = time.time()
+        for filename in os.listdir(submitted):
+            ctime = os.stat(os.path.join(submitted, filename)).st_ctime
+            if now - ctime >= 60*60*24*30:
+                os.remove(os.path.join(submitted, filename))
+
     def populate_context(context, key=None):
         if key is None:
             return
         if key == 'state_dir':
             state_dir, is_environ = get_state_dir()
             if is_environ:
                 if not os.path.exists(state_dir):
                     print('Creating global state directory from environment variable: %s'
@@ -300,16 +406,22 @@ def bootstrap(topsrcdir, mozilla_dir=Non
             return state_dir
 
         if key == 'topdir':
             return topsrcdir
 
         if key == 'pre_dispatch_handler':
             return pre_dispatch_handler
 
+        if key == 'telemetry_handler':
+            return telemetry_handler
+
+        if key == 'post_dispatch_handler':
+            return post_dispatch_handler
+
         raise AttributeError(key)
 
     mach = mach.main.Mach(os.getcwd())
     mach.populate_context_handler = populate_context
 
     for category, meta in CATEGORIES.items():
         mach.define_category(category, meta['short'], meta['long'],
             meta['priority'])
--- a/build/mobile/remoteautomation.py
+++ b/build/mobile/remoteautomation.py
@@ -8,17 +8,17 @@ import time
 import re
 import os
 import tempfile
 import shutil
 import subprocess
 import sys
 
 from automation import Automation
-from devicemanager import DMError, DeviceManager
+from mozdevice import DMError, DeviceManager
 from mozlog import get_default_logger
 import mozcrash
 
 # signatures for logcat messages that we don't care about much
 fennecLogcatFilters = [ "The character encoding of the HTML document was not declared",
                         "Use of Mutation Events is deprecated. Use MutationObserver instead.",
                         "Unexpected value from nativeGetEnabledTags: 0" ]
 
--- a/build/unix/build-gtk3/build-gtk3.sh
+++ b/build/unix/build-gtk3/build-gtk3.sh
@@ -113,34 +113,38 @@ cat << EOF > $root_dir/gtk3/usr/local/et
   <dir>/usr/share/X11/fonts</dir>
 </fontconfig>
 EOF
 
 cat <<EOF > $root_dir/gtk3/setup.sh
 #!/bin/sh
 
 cd \$(dirname \$0)
+HERE=\$(pwd)
 
 # pango expects absolute paths in pango.modules, and TOOLTOOL_DIR may vary...
-LD_LIBRARY_PATH=./usr/local/lib \
-PANGO_SYSCONFDIR=./usr/local/etc \
-PANGO_LIBDIR=./usr/local/lib \
-./usr/local/bin/pango-querymodules > ./usr/local/etc/pango/pango.modules
+LD_LIBRARY_PATH=\$HERE/usr/local/lib \
+PANGO_SYSCONFDIR=\$HERE/usr/local/etc \
+PANGO_LIBDIR=\$HERE/usr/local/lib \
+\$HERE/usr/local/bin/pango-querymodules > \$HERE/usr/local/etc/pango/pango.modules
 
 # same with gdb-pixbuf and loaders.cache
-LD_LIBRARY_PATH=./usr/local/lib \
-GDK_PIXBUF_MODULE_FILE=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
-GDK_PIXBUF_MODULEDIR=./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
-./usr/local/bin/gdk-pixbuf-query-loaders > ./usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
+LD_LIBRARY_PATH=\$HERE/usr/local/lib \
+GDK_PIXBUF_MODULE_FILE=\$HERE/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache \
+GDK_PIXBUF_MODULEDIR=\$HERE/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders \
+\$HERE/usr/local/bin/gdk-pixbuf-query-loaders > \
+\$HERE/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
 
 # The fontconfig version in the tooltool package has known uses of
 # uninitialized memory when creating its cache, and while most users
 # will already have an existing cache, running Firefox on automation
 # will create it. Combined with valgrind, this generates irrelevant
 # errors.
 # So create the fontconfig cache beforehand.
-./usr/local/bin/fc-cache
+FONTCONFIG_PATH=\$HERE/usr/local/etc/fonts \
+LD_LIBRARY_PATH=\$HERE/usr/local/lib \
+\$HERE/usr/local/bin/fc-cache
 EOF
 
 chmod +x $root_dir/gtk3/setup.sh
 
 cd $cwd
 tar -C $root_dir -Jcf gtk3.tar.xz gtk3
--- a/build/unix/mozconfig.gtk
+++ b/build/unix/mozconfig.gtk
@@ -19,11 +19,8 @@ ac_add_options --enable-default-toolkit=
 
 # Set things up to use Gtk+3 from the tooltool package
 mk_add_options "export FONTCONFIG_PATH=$TOOLTOOL_DIR/gtk3/usr/local/etc/fonts"
 mk_add_options "export PANGO_SYSCONFDIR=$TOOLTOOL_DIR/gtk3/usr/local/etc"
 mk_add_options "export PANGO_LIBDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib"
 mk_add_options "export GDK_PIXBUF_MODULE_FILE=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
 mk_add_options "export GDK_PIXBUF_MODULEDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
 mk_add_options "export LD_LIBRARY_PATH=$TOOLTOOL_DIR/gtk3/usr/local/lib"
-
-# Until a tooltool with bug 1188571 landed is available everywhere
-$TOOLTOOL_DIR/gtk3/setup.sh
--- a/config/check_macroassembler_style.py
+++ b/config/check_macroassembler_style.py
@@ -36,16 +36,18 @@ all_shared_architecture_names = set([ 'x
 reBeforeArg = "(?<=[(,\s])"
 reArgType = "(?P<type>[\w\s:*&]+)"
 reArgName = "(?P<name>\s\w+)"
 reArgDefault = "(?P<default>(?:\s=[^,)]+)?)"
 reAfterArg = "(?=[,)])"
 reMatchArg = re.compile(reBeforeArg + reArgType + reArgName + reArgDefault + reAfterArg)
 
 def get_normalized_signatures(signature, fileAnnot = None):
+    # Remove static
+    signature = signature.replace('static', '')
     # Remove semicolon.
     signature = signature.replace(';', ' ')
     # Normalize spaces.
     signature = re.sub(r'\s+', ' ', signature).strip()
     # Match arguments, and keep only the type.
     signature = reMatchArg.sub('\g<type>', signature)
     # Remove class name
     signature = signature.replace('MacroAssembler::', '')
--- a/dom/apps/AppsUtils.jsm
+++ b/dom/apps/AppsUtils.jsm
@@ -221,17 +221,17 @@ this.AppsUtils = {
           // unrecoverable error, don't bug the user
           deferred.reject({ msg: "NETWORK_ERROR", downloadAvailable: false});
           return;
         }
 
         deferred.resolve(file);
       }
     });
-    aRequestChannel.asyncOpen(listener, null);
+    aRequestChannel.asyncOpen2(listener);
 
     return deferred.promise;
   },
 
   // Eliminate query and hash string.
   getFilePath: function(aPagePath) {
     let urlParser = Cc["@mozilla.org/network/url-parser;1?auth=no"]
                     .getService(Ci.nsIURLParser);
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -3485,31 +3485,25 @@ this.DOMApplicationRegistry = {
     return true;
   },
 
   _getRequestChannel: function(aFullPackagePath, aIsLocalFileInstall, aOldApp,
                                aNewApp) {
     let requestChannel;
 
     let appURI = NetUtil.newURI(aNewApp.origin, null, null);
-    let principal =
-      Services.scriptSecurityManager.createCodebasePrincipal(appURI,
-                                                             {appId: aNewApp.localId});
-
     if (aIsLocalFileInstall) {
       requestChannel = NetUtil.newChannel({
         uri: aFullPackagePath,
-        loadingPrincipal: principal,
-        contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER}
+        loadUsingSystemPrincipal: true}
       ).QueryInterface(Ci.nsIFileChannel);
     } else {
       requestChannel = NetUtil.newChannel({
         uri: aFullPackagePath,
-        loadingPrincipal: principal,
-        contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER}
+        loadUsingSystemPrincipal: true}
       ).QueryInterface(Ci.nsIHttpChannel);
       requestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
     }
 
     if (aOldApp.packageEtag && !aIsLocalFileInstall) {
       debug("Add If-None-Match header: " + aOldApp.packageEtag);
       requestChannel.setRequestHeader("If-None-Match", aOldApp.packageEtag,
                                       false);
--- a/dom/base/ShadowRoot.cpp
+++ b/dom/base/ShadowRoot.cpp
@@ -214,17 +214,17 @@ ShadowRoot::AddToIdTable(Element* aEleme
 void
 ShadowRoot::RemoveFromIdTable(Element* aElement, nsIAtom* aId)
 {
   nsIdentifierMapEntry *entry =
     mIdentifierMap.GetEntry(nsDependentAtomString(aId));
   if (entry) {
     entry->RemoveIdElement(aElement);
     if (entry->IsEmpty()) {
-      mIdentifierMap.RawRemoveEntry(entry);
+      mIdentifierMap.RemoveEntry(entry);
     }
   }
 }
 
 already_AddRefed<nsContentList>
 ShadowRoot::GetElementsByClassName(const nsAString& aClasses)
 {
   return nsContentUtils::GetElementsByClassName(this, aClasses);
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7265,39 +7265,45 @@ nsContentUtils::GetInnerWindowID(nsIRequ
   if (!pwindow) {
     return 0;
   }
 
   nsPIDOMWindowInner* inner = pwindow->GetCurrentInnerWindow();
   return inner ? inner->WindowID() : 0;
 }
 
-void
+nsresult
 nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost)
 {
   aHost.Truncate();
   nsresult rv = aURI->GetHost(aHost);
   if (NS_FAILED(rv)) { // Some URIs do not have a host
-    return;
+    return rv;
   }
 
   if (aHost.FindChar(':') != -1) { // Escape IPv6 address
     MOZ_ASSERT(!aHost.Length() ||
       (aHost[0] !='[' && aHost[aHost.Length() - 1] != ']'));
     aHost.Insert('[', 0);
     aHost.Append(']');
   }
-}
-
-void
+
+  return NS_OK;
+}
+
+nsresult
 nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost)
 {
   nsAutoCString hostname;
-  GetHostOrIPv6WithBrackets(aURI, hostname);
+  nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
   CopyUTF8toUTF16(hostname, aHost);
+  return NS_OK;
 }
 
 void
 nsContentUtils::CallOnAllRemoteChildren(nsIMessageBroadcaster* aManager,
                                         CallOnRemoteChildFunction aCallback,
                                         void* aArg)
 {
   uint32_t tabChildCount = 0;
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2397,18 +2397,18 @@ public:
    * Returns the inner window ID for the window associated with a request,
    */
   static uint64_t GetInnerWindowID(nsIRequest* aRequest);
 
   /**
    * If the hostname for aURI is an IPv6 it encloses it in brackets,
    * otherwise it just outputs the hostname in aHost.
    */
-  static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
-  static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
+  static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
+  static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
 
   /*
    * Call the given callback on all remote children of the given top-level
    * window.
    */
   static void CallOnAllRemoteChildren(nsPIDOMWindowOuter* aWindow,
                                       CallOnRemoteChildFunction aCallback,
                                       void* aArg);
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2998,17 +2998,17 @@ nsDocument::RemoveFromIdTable(Element *a
 
   entry->RemoveIdElement(aElement);
   if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) &&
       !entry->HasNameElement() &&
       !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
     ++mExpandoAndGeneration.generation;
   }
   if (entry->IsEmpty()) {
-    mIdentifierMap.RawRemoveEntry(entry);
+    mIdentifierMap.RemoveEntry(entry);
   }
 }
 
 nsIPrincipal*
 nsDocument::GetPrincipal()
 {
   return NodePrincipal();
 }
--- a/dom/base/nsDocumentEncoder.cpp
+++ b/dom/base/nsDocumentEncoder.cpp
@@ -1433,17 +1433,17 @@ nsHTMLCopyEncoder::SetSelection(nsISelec
        selContent = selContent->GetParent())
   {
     // checking for selection inside a plaintext form widget
     if (selContent->IsAnyOfHTMLElements(nsGkAtoms::input, nsGkAtoms::textarea))
     {
       mIsTextWidget = true;
       break;
     }
-#ifdef MOZ_THUNDERBIRD
+#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
     else if (selContent->IsHTMLElement(nsGkAtoms::body)) {
       // Currently, setting mIsTextWidget to 'true' will result in the selection
       // being encoded/copied as pre-formatted plain text.
       // This is fine for copying pre-formatted plain text with Firefox, it is
       // already not correct for copying pre-formatted "rich" text (bold, colour)
       // with Firefox. As long as the serialisers aren't fixed, copying
       // pre-formatted text in Firefox is broken. If we set mIsTextWidget,
       // pre-formatted plain text is copied, but pre-formatted "rich" text loses
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -99,17 +99,16 @@ GK_ATOM(anonid, "anonid")
 GK_ATOM(anonlocation, "anonlocation")
 GK_ATOM(any, "any")
 GK_ATOM(mozapp, "mozapp")
 GK_ATOM(mozwidget, "mozwidget")
 GK_ATOM(applet, "applet")
 GK_ATOM(applyImports, "apply-imports")
 GK_ATOM(applyTemplates, "apply-templates")
 GK_ATOM(mozapptype, "mozapptype")
-GK_ATOM(apz, "apz")
 GK_ATOM(archive, "archive")
 GK_ATOM(area, "area")
 GK_ATOM(arrow, "arrow")
 GK_ATOM(article, "article")
 GK_ATOM(ascending, "ascending")
 GK_ATOM(aside, "aside")
 GK_ATOM(aspectRatio, "aspect-ratio")
 GK_ATOM(assign, "assign")
@@ -2265,23 +2264,30 @@ GK_ATOM(Close, "Close")
 GK_ATOM(Save, "Save")
 GK_ATOM(Find, "Find")
 GK_ATOM(Help, "Help")
 GK_ATOM(Print, "Print")
 GK_ATOM(SendMail, "SendMail")
 GK_ATOM(ForwardMail, "ForwardMail")
 GK_ATOM(ReplyToMail, "ReplyToMail")
 
-// Smooth scroll events origins
+// Scroll origins (these are used in various scrolling functions in
+// nsIScrollableFrame and ScrollFrameHelper). These are divided into two lists
+// - origins in the first one have smooth-scrolling prefs associated with them,
+// under the "general.smoothScroll.<origin>.*" pref branch. Origins in the
+// second one do not.
 GK_ATOM(mouseWheel, "mouseWheel")  // For discrete wheel events (e.g. not OSX magic mouse)
 GK_ATOM(pixels,     "pixels")
 GK_ATOM(lines,      "lines")
 GK_ATOM(pages,      "pages")
 GK_ATOM(scrollbars, "scrollbars")
 GK_ATOM(other,      "other")
+// Scroll origins without smooth-scrolling prefs
+GK_ATOM(apz,        "apz")
+GK_ATOM(restore,    "restore")
 
 #ifdef ACCESSIBILITY
 GK_ATOM(alert, "alert")
 GK_ATOM(alertdialog, "alertdialog")
 GK_ATOM(application, "application")
 GK_ATOM(aria_activedescendant, "aria-activedescendant")
 GK_ATOM(aria_atomic, "aria-atomic")
 GK_ATOM(aria_autocomplete, "aria-autocomplete")
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -35,17 +35,17 @@ namespace dom {
 // so we can use IsBaseOf to detect dictionary template arguments.
 struct DictionaryBase
 {
 protected:
   bool ParseJSON(JSContext* aCx, const nsAString& aJSON,
                  JS::MutableHandle<JS::Value> aVal);
 
   bool StringifyToJSON(JSContext* aCx,
-                       JS::MutableHandle<JS::Value> aValue,
+                       JS::Handle<JSObject*> aObj,
                        nsAString& aJSON) const;
 
   // Struct used as a way to force a dictionary constructor to not init the
   // dictionary (via constructing from a pointer to this class).  We're putting
   // it here so that all the dictionaries will have access to it, but outside
   // code will not.
   struct FastDictionaryInitializer {
   };
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -40,18 +40,19 @@
 #include "mozilla/dom/ElementBinding.h"
 #include "mozilla/dom/HTMLObjectElement.h"
 #include "mozilla/dom/HTMLObjectElementBinding.h"
 #include "mozilla/dom/HTMLSharedObjectElement.h"
 #include "mozilla/dom/HTMLEmbedElementBinding.h"
 #include "mozilla/dom/HTMLAppletElementBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ResolveSystemBinding.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerScope.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
-#include "WorkerPrivate.h"
 #include "nsDOMClassInfo.h"
 #include "ipc/ErrorIPCUtils.h"
 #include "mozilla/UseCounter.h"
 
 namespace mozilla {
 namespace dom {
 
 JSErrorFormatString ErrorFormatString[] = {
@@ -1862,21 +1863,20 @@ DictionaryBase::ParseJSON(JSContext* aCx
   if (aJSON.IsEmpty()) {
     return true;
   }
   return JS_ParseJSON(aCx, PromiseFlatString(aJSON).get(), aJSON.Length(), aVal);
 }
 
 bool
 DictionaryBase::StringifyToJSON(JSContext* aCx,
-                                JS::MutableHandle<JS::Value> aValue,
+                                JS::Handle<JSObject*> aObj,
                                 nsAString& aJSON) const
 {
-  return JS_Stringify(aCx, aValue, nullptr, JS::NullHandleValue,
-                      AppendJSONToString, &aJSON);
+  return JS::ToJSONMaybeSafely(aCx, aObj, AppendJSONToString, &aJSON);
 }
 
 /* static */
 bool
 DictionaryBase::AppendJSONToString(const char16_t* aJSONData,
                                    uint32_t aDataLength,
                                    void* aString)
 {
@@ -3234,10 +3234,23 @@ DeprecationWarning(JSContext* aCx, JSObj
   }
 
   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports());
   if (window && window->GetExtantDoc()) {
     window->GetExtantDoc()->WarnOnceAbout(aOperation);
   }
 }
 
+namespace binding_detail {
+JSObject*
+UnprivilegedJunkScopeOrWorkerGlobal()
+{
+  if (NS_IsMainThread()) {
+    return xpc::UnprivilegedJunkScope();
+  }
+
+  return workers::GetCurrentThreadWorkerPrivate()->
+    GlobalScope()->GetGlobalJSObject();
+}
+} // namespace binding_detail
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3322,12 +3322,32 @@ SetDocumentAndPageUseCounter(JSContext* 
 void
 DeprecationWarning(JSContext* aCx, JSObject* aObject,
                    nsIDocument::DeprecatedOperations aOperation);
 
 // A callback to perform funToString on an interface object
 JSString*
 InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
                         unsigned /* indent */);
+
+namespace binding_detail {
+// Get a JS global object that can be used for some temporary allocations.  The
+// idea is that this should be used for situations when you need to operate in
+// _some_ compartment but don't care which one.  A typical example is when you
+// have non-JS input, non-JS output, but have to go through some sort of JS
+// representation in the middle, so need a compartment to allocate things in.
+//
+// It's VERY important that any consumers of this function only do things that
+// are guaranteed to be side-effect-free, even in the face of a script
+// environment controlled by a hostile adversary.  This is because in the worker
+// case the global is in fact the worker global, so it and its standard objects
+// are controlled by the worker script.  This is why this function is in the
+// binding_detail namespace.  Any use of this function MUST be very carefully
+// reviewed by someone who is sufficiently devious and has a very good
+// understanding of all the code that will run while we're using the return
+// value, including the SpiderMonkey parts.
+JSObject* UnprivilegedJunkScopeOrWorkerGlobal();
+} // namespace binding_detail
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_BindingUtils_h__ */
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -12252,23 +12252,31 @@ class CGDictionary(CGThing):
                 return Init(cx, json);
                 """))
 
     def toJSONMethod(self):
         return ClassMethod(
             "ToJSON", "bool",
             [Argument('nsAString&', 'aJSON')],
             body=dedent("""
-                MOZ_ASSERT(NS_IsMainThread());
                 AutoJSAPI jsapi;
                 jsapi.Init();
                 JSContext *cx = jsapi.cx();
-                JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope()); // Usage approved by bholley
-                JS::Rooted<JS::Value> obj(cx);
-                return ToObjectInternal(cx, &obj) && StringifyToJSON(cx, &obj, aJSON);
+                // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
+                // because we'll only be creating objects, in ways that have no
+                // side-effects, followed by a call to JS::ToJSONMaybeSafely,
+                // which likewise guarantees no side-effects for the sorts of
+                // things we will pass it.
+                JSAutoCompartment ac(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
+                JS::Rooted<JS::Value> val(cx);
+                if (!ToObjectInternal(cx, &val)) {
+                  return false;
+                }
+                JS::Rooted<JSObject*> obj(cx, &val.toObject());
+                return StringifyToJSON(cx, obj, aJSON);
             """), const=True)
 
     def toObjectInternalMethod(self):
         body = ""
         if self.needToInitIds:
             body += fill(
                 """
                 ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx);
@@ -12398,17 +12406,18 @@ class CGDictionary(CGThing):
 
         if self.needToInitIds:
             methods.append(self.initIdsMethod())
 
         methods.append(self.initMethod())
         methods.append(self.initFromJSONMethod())
         try:
             methods.append(self.toObjectInternalMethod())
-            methods.append(self.toJSONMethod())
+            if self.dictionarySafeToJSONify(self.dictionary):
+                methods.append(self.toJSONMethod())
         except MethodNotNewObjectError:
             # If we can't have a ToObjectInternal() because one of our members
             # can only be returned from [NewObject] methods, then just skip
             # generating ToObjectInternal() and ToJSON (since the latter depens
             # on the former).
             pass
         methods.append(self.traceDictionaryMethod())
 
@@ -12705,16 +12714,62 @@ class CGDictionary(CGThing):
 
     @staticmethod
     def isDictionaryCopyConstructible(dictionary):
         if (dictionary.parent and
             not CGDictionary.isDictionaryCopyConstructible(dictionary.parent)):
             return False
         return all(isTypeCopyConstructible(m.type) for m in dictionary.members)
 
+    @staticmethod
+    def typeSafeToJSONify(type):
+        """
+        Determine whether the given type is safe to convert to JSON.  The
+        restriction is that this needs to be safe while in a global controlled
+        by an adversary, and "safe" means no side-effects when the JS
+        representation of this type is converted to JSON.  That means that we
+        have to be pretty restrictive about what things we can allow.  For
+        example, "object" is out, because it may have accessor properties on it.
+        """
+        if type.nullable():
+            # Converting null to JSON is always OK.
+            return CGDictionary.typeSafeToJSONify(type.inner)
+
+        if type.isSequence():
+            # Sequences are arrays we create ourselves, with no holes.  They
+            # should be safe if their contents are safe, as long as we suppress
+            # invocation of .toJSON on objects.
+            return CGDictionary.typeSafeToJSONify(type.inner)
+
+        if type.isUnion():
+            # OK if everything in it is ok.
+            return all(CGDictionary.typeSafeToJSONify(t)
+                       for t in type.flatMemberTypes)
+
+        if type.isDictionary():
+            # OK if the dictionary is OK
+            return CGDictionary.dictionarySafeToJSONify(type.inner)
+
+        if type.isString() or type.isEnum():
+            # Strings are always OK.
+            return True
+
+        if type.isPrimitive():
+            # Primitives (numbers and booleans) are ok, as long as
+            # they're not unrestricted float/double.
+            return not type.isFloat() or not type.isUnrestricted()
+
+        return False
+
+    @staticmethod
+    def dictionarySafeToJSONify(dictionary):
+        # The dictionary itself is OK, so we're good if all our types are.
+        return all(CGDictionary.typeSafeToJSONify(m.type)
+                   for m in dictionary.members)
+
 
 class CGRegisterWorkerBindings(CGAbstractMethod):
     def __init__(self, config):
         CGAbstractMethod.__init__(self, None, 'RegisterWorkerBindings', 'bool',
                                   [Argument('JSContext*', 'aCx'),
                                    Argument('JS::Handle<JSObject*>', 'aObj')])
         self.config = config
 
@@ -13186,17 +13241,16 @@ class CGBindingRoot(CGThing):
         bindingHeaders["mozilla/dom/BindingUtils.h"] = hasCode
         bindingHeaders["mozilla/OwningNonNull.h"] = hasCode
         bindingHeaders["mozilla/dom/BindingDeclarations.h"] = (
             not hasCode and enums)
 
         bindingHeaders["WrapperFactory.h"] = descriptors
         bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors
         bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries  # AutoJSAPI
-        bindingHeaders["xpcpublic.h"] = dictionaries  # xpc::UnprivilegedJunkScope
         # Ensure we see our enums in the generated .cpp file, for the ToJSValue
         # method body.  Also ensure that we see jsapi.h.
         if enums:
             bindingHeaders[CGHeaders.getDeclarationFilename(enums[0])] = True
             bindingHeaders["jsapi.h"] = True
 
         # For things that have [UseCounter]
         def descriptorRequiresTelemetry(desc):
@@ -15632,17 +15686,20 @@ class CGMaplikeOrSetlikeHelperFunctionGe
     def getCallSetup(self):
         return dedent(
             """
             MOZ_ASSERT(self);
             AutoJSAPI jsapi;
             jsapi.Init();
             jsapi.TakeOwnershipOfErrorReporting();
             JSContext* cx = jsapi.cx();
-            JSAutoCompartment tempCompartment(cx, xpc::UnprivilegedJunkScope());
+            // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
+            // all we want is to wrap into _some_ scope and then unwrap to find
+            // the reflector, and wrapping has no side-effects.
+            JSAutoCompartment tempCompartment(cx, binding_detail::UnprivilegedJunkScopeOrWorkerGlobal());
             JS::Rooted<JS::Value> v(cx);
             if(!ToJSValue(cx, self, &v)) {
               aRv.Throw(NS_ERROR_UNEXPECTED);
               return%s;
             }
             // This is a reflector, but due to trying to name things
             // similarly across method generators, it's called obj here.
             JS::Rooted<JSObject*> obj(cx);
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -10,16 +10,17 @@ var Cc = Components.classes;
 var Cr = Components.results;
 
 /* BrowserElementParent injects script to listen for certain events in the
  * child.  We then listen to messages from the child script and take
  * appropriate action here in the parent.
  */
 
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "DOMApplicationRegistry", function () {
   Cu.import("resource://gre/modules/Webapps.jsm");
   return DOMApplicationRegistry;
 });
 
@@ -996,46 +997,27 @@ BrowserElementParent.prototype = {
                                 aOffset, aCount) {
         this.extListener.onDataAvailable(aRequest, aContext, aInputStream,
                                          aOffset, aCount);
       },
       QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
                                              Ci.nsIRequestObserver])
     };
 
-    // If we have a URI we'll use it to get the triggering principal to use,
-    // if not available a null principal is acceptable.
-    let referrer = null;
-    let principal = null;
-    if (_options.referrer) {
-      // newURI can throw on malformed URIs.
-      try {
-        referrer = Services.io.newURI(_options.referrer, null, null);
-      }
-      catch(e) {
-        debug('Malformed referrer -- ' + e);
-      }
+    let referrer = Services.io.newURI(_options.referrer, null, null);
+    let principal =
+      Services.scriptSecurityManager.createCodebasePrincipal(
+        referrer, this._frameLoader.loadContext.originAttributes);
 
-      // This simply returns null if there is no principal available
-      // for the requested uri. This is an acceptable fallback when
-      // calling newChannelFromURI2.
-      principal =
-        Services.scriptSecurityManager.createCodebasePrincipal(
-          referrer, this._frameLoader.loadContext.originAttributes);
-    }
-
-    debug('Using principal? ' + !!principal);
-
-    let channel =
-      Services.io.newChannelFromURI2(url,
-                                     null,       // No document.
-                                     principal,  // Loading principal
-                                     principal,  // Triggering principal
-                                     Ci.nsILoadInfo.SEC_NORMAL,
-                                     Ci.nsIContentPolicy.TYPE_OTHER);
+    let channel = NetUtil.newChannel({
+      uri: url,
+      loadingPrincipal: principal,
+      securityFlags: SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS,
+      contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER
+    });
 
     // XXX We would set private browsing information prior to calling this.
     channel.notificationCallbacks = interfaceRequestor;
 
     // Since we're downloading our own local copy we'll want to bypass the
     // cache and local cache if the channel let's us specify this.
     let flags = Ci.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS |
                 Ci.nsIChannel.LOAD_BYPASS_CACHE;
@@ -1050,17 +1032,17 @@ BrowserElementParent.prototype = {
       debug('Setting HTTP referrer = ' + (referrer && referrer.spec));
       channel.referrer = referrer;
       if (channel instanceof Ci.nsIHttpChannelInternal) {
         channel.forceAllowThirdPartyCookie = true;
       }
     }
 
     // Set-up complete, let's get things started.
-    channel.asyncOpen(new DownloadListener(), null);
+    channel.asyncOpen2(new DownloadListener());
 
     return req;
   },
 
   getScreenshot: function(_width, _height, _mimeType) {
     if (!this._isAlive()) {
       throw Components.Exception("Dead content process",
                                  Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -43,16 +43,17 @@
 #include "nsIScriptGlobalObject.h"
 #include "nsISupports.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsNameSpaceManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsSandboxFlags.h"
 #include "xpcpublic.h"
+#include "nsIFrame.h"
 
 namespace mozilla {
 
 using namespace dom;
 using namespace hal;
 
 #define EVENT_TYPE_EQUALS(ls, message, userType, typeString, allEvents) \
   ((ls->mEventMessage == message &&                                     \
@@ -411,32 +412,67 @@ EventListenerManager::AddEventListenerIn
              aTypeAtom == nsGkAtoms::oncompositionupdate ||
              aTypeAtom == nsGkAtoms::oninput) {
     if (!aFlags.mInSystemGroup) {
       mMayHaveInputOrCompositionEventListener = true;
     }
   }
 
   if (IsApzAwareEvent(aTypeAtom)) {
-    nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
-    if (node) {
-      node->SetMayHaveApzAwareListeners();
-    }
+    ProcessApzAwareEventListenerAdd();
   }
 
   if (aTypeAtom && mTarget) {
     mTarget->EventListenerAdded(aTypeAtom);
   }
 
   if (mIsMainThreadELM && mTarget) {
     EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
                                                               aTypeAtom);
   }
 }
 
+void
+EventListenerManager::ProcessApzAwareEventListenerAdd()
+{
+  // Mark the node as having apz aware listeners
+  nsCOMPtr<nsINode> node = do_QueryInterface(mTarget);
+  if (node) {
+    node->SetMayHaveApzAwareListeners();
+  }
+
+  // Schedule a paint so event regions on the layer tree gets updated
+  nsIDocument* doc = nullptr;
+  if (node) {
+    doc = node->OwnerDoc();
+  }
+  if (!doc) {
+    if (nsCOMPtr<nsPIDOMWindowInner> window = GetTargetAsInnerWindow()) {
+      doc = window->GetExtantDoc();
+    }
+  }
+  if (!doc) {
+    if (nsCOMPtr<DOMEventTargetHelper> helper = do_QueryInterface(mTarget)) {
+      if (nsPIDOMWindowInner* window = helper->GetOwner()) {
+        doc = window->GetExtantDoc();
+      }
+    }
+  }
+
+  if (doc) {
+    nsIPresShell* ps = doc->GetShell();
+    if (ps) {
+      nsIFrame* f = ps->GetRootFrame();
+      if (f) {
+        f->SchedulePaint();
+      }
+    }
+  }
+}
+
 bool
 EventListenerManager::IsDeviceType(EventMessage aEventMessage)
 {
   switch (aEventMessage) {
     case eDeviceOrientation:
     case eAbsoluteDeviceOrientation:
     case eDeviceMotion:
     case eDeviceLight:
--- a/dom/events/EventListenerManager.h
+++ b/dom/events/EventListenerManager.h
@@ -462,16 +462,18 @@ protected:
    * If the given EventMessage has a legacy version that we support, then this
    * function returns that legacy version. Otherwise, this function simply
    * returns the passed-in EventMessage.
    */
   EventMessage GetLegacyEventMessage(EventMessage aEventMessage) const;
 
   nsIDocShell* GetDocShellForTarget();
 
+  void ProcessApzAwareEventListenerAdd();
+
   /**
    * Compile the "inline" event listener for aListener.  The
    * body of the listener can be provided in aBody; if this is null we
    * will look for it on mTarget.  If aBody is provided, aElement should be
    * as well; otherwise it will also be inferred from mTarget.
    */
   nsresult CompileEventHandlerInternal(Listener* aListener,
                                        const nsAString* aBody,
--- a/dom/events/test/test_legacy_event.html
+++ b/dom/events/test/test_legacy_event.html
@@ -182,69 +182,117 @@ function mpTestModernBeatsLegacy(eventIn
       eventInfo.trigger_event(div);
     }
   );
 }
 
 // Test that an event which bubbles may fire listeners of different flavors
 // (modern vs. legacy) at each bubbling level, depending on what's registered
 // at that level.
-function mpTestAncestorsWithDiffListeners(eventInfo) {
+function mpTestDiffListenersEventBubbling(eventInfo) {
   return new Promise(
     function(resolve, reject) {
       var grandparent = createChildDiv();
       var parent = createChildDiv(grandparent);
       var target = createChildDiv(parent);
       var didEventFireOnTarget = false;
       var didEventFireOnParent = false;
       var eventSentToTarget;
 
       target.addEventListener(eventInfo.modern_name,
-        createHandlerWithTypeCheck(eventInfo.modern_name,
-                                   function(e) {
-                                     ok(e.bubbles, "Expecting event to bubble");
-                                     eventSentToTarget = e;
-                                     didEventFireOnTarget = true;
-                                   }));
+        createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+          ok(e.bubbles, "Expecting event to bubble");
+          eventSentToTarget = e;
+          didEventFireOnTarget = true;
+        }));
 
       parent.addEventListener(eventInfo.legacy_name,
-        createHandlerWithTypeCheck(eventInfo.legacy_name,
-                                   function(e) {
-                                     is(e, eventSentToTarget,
-                                        "Same event object should bubble, " +
-                                        "despite difference in type");
-                                     didEventFireOnParent = true;
-                                   }));
+        createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
+          is(e, eventSentToTarget,
+             "Same event object should bubble, despite difference in type");
+          didEventFireOnParent = true;
+        }));
 
       grandparent.addEventListener(eventInfo.modern_name,
-        createHandlerWithTypeCheck(eventInfo.modern_name,
-                                   function(e) {
-                                     ok(didEventFireOnTarget,
-                                        "Event should have fired on child");
-                                     ok(didEventFireOnParent,
-                                        "Event should have fired on parent");
-                                     is(e, eventSentToTarget,
-                                        "Same event object should bubble, " +
-                                        "despite difference in type");
-                                     parent.removeChild(target);
-                                     resolve();
-                                   }));
+        createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+        ok(didEventFireOnTarget,
+           "Event should have fired on child");
+        ok(didEventFireOnParent,
+           "Event should have fired on parent");
+        is(e, eventSentToTarget,
+           "Same event object should bubble, despite difference in type");
+        // Clean up.
+        grandparent.parentNode.removeChild(grandparent);
+        resolve();
+      }));
+
+      eventInfo.trigger_event(target);
+    }
+  );
+}
+
+// Test that an event in the capture phase may fire listeners of different
+// flavors (modern vs. legacy) at each level, depending on what's registered
+// at that level.
+function mpTestDiffListenersEventCapturing(eventInfo) {
+  return new Promise(
+    function(resolve, reject) {
+      var grandparent = createChildDiv();
+      var parent = createChildDiv(grandparent);
+      var target = createChildDiv(parent);
+      var didEventFireOnTarget = false;
+      var didEventFireOnParent = false;
+      var didEventFireOnGrandparent = false;
+      var eventSentToGrandparent;
+
+      grandparent.addEventListener(eventInfo.modern_name,
+        createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+          eventSentToGrandparent = e;
+          didEventFireOnGrandparent = true;
+        }), true);
+
+      parent.addEventListener(eventInfo.legacy_name,
+        createHandlerWithTypeCheck(eventInfo.legacy_name, function(e) {
+          is(e.eventPhase, Event.CAPTURING_PHASE,
+             "event should be in capturing phase");
+          is(e, eventSentToGrandparent,
+             "Same event object should capture, despite difference in type");
+          ok(didEventFireOnGrandparent,
+             "Event should have fired on grandparent");
+          didEventFireOnParent = true;
+      }), true);
+
+      target.addEventListener(eventInfo.modern_name,
+        createHandlerWithTypeCheck(eventInfo.modern_name, function(e) {
+          is(e.eventPhase, Event.AT_TARGET,
+             "event should be at target phase");
+          is(e, eventSentToGrandparent,
+             "Same event object should capture, despite difference in type");
+          ok(didEventFireOnParent,
+             "Event should have fired on parent");
+          // Clean up.
+          grandparent.parentNode.removeChild(grandparent);
+          resolve();
+      }), true);
+
       eventInfo.trigger_event(target);
     }
   );
 }
 
 // MAIN FUNCTION: Kick off the tests.
 function main() {
   Promise.resolve().then(function() {
     return Promise.all(gLegacyEventInfo.map(mpTestLegacyEventSent))
   }).then(function() {
     return Promise.all(gLegacyEventInfo.map(mpTestModernBeatsLegacy));
   }).then(function() {
-    return Promise.all(gLegacyEventInfo.map(mpTestAncestorsWithDiffListeners));
+    return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventCapturing));
+  }).then(function() {
+    return Promise.all(gLegacyEventInfo.map(mpTestDiffListenersEventBubbling));
   }).then(function() {
     SimpleTest.finish();
   }).catch(function(reason) {
     ok(false, "Test failed: " + reason);
     SimpleTest.finish();
   });
 }
 
--- a/dom/events/test/test_moz_mouse_pixel_scroll_event.html
+++ b/dom/events/test/test_moz_mouse_pixel_scroll_event.html
@@ -1,14 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <title>Test for MozMousePixelScroll events</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <style>
     .scrollable {
       overflow: auto;
       line-height: 1;
       margin: 15px;
     }
     .scrollable > div {
@@ -58,16 +59,18 @@ function* prepareScrollUnits()
   function handler(aEvent)
   {
     result = aEvent.detail;
     aEvent.preventDefault();
     setTimeout(runTest, 0);
   }
   window.addEventListener("MozMousePixelScroll", handler, true);
 
+  yield waitForAllPaints(function () { setTimeout(runTest, 0); });
+
   yield synthesizeWheel(gScrollable128, 10, 10,
                   { deltaMode: WheelEvent.DOM_DELTA_LINE,
                     deltaY: 1.0, lineOrPageDeltaY: 1 });
   gScrollable128.wheelLineHeight = result;
   ok(result > 96 && result < 200, "prepareScrollUnits: gScrollable128.wheelLineHeight may be illegal value, got " + result);
 
   result = -1;
   yield synthesizeWheel(gScrollable96, 10, 10,
--- a/dom/html/HTMLDetailsElement.cpp
+++ b/dom/html/HTMLDetailsElement.cpp
@@ -19,17 +19,17 @@ NS_NewHTMLDetailsElement(already_AddRefe
   }
 
   return new mozilla::dom::HTMLDetailsElement(aNodeInfo);
 }
 
 namespace mozilla {
 namespace dom {
 
-bool
+/* static */ bool
 HTMLDetailsElement::IsDetailsEnabled()
 {
   static bool isDetailsEnabled = false;
   static bool added = false;
 
   if (!added) {
     Preferences::AddBoolVarCache(&isDetailsEnabled,
                                  "dom.details_element.enabled");
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -886,18 +886,18 @@ nsHTMLDocument::GetDomain(nsAString& aDo
   nsCOMPtr<nsIURI> uri = GetDomainURI();
 
   if (!uri) {
     SetDOMStringToNull(aDomain);
     return NS_OK;
   }
 
   nsAutoCString hostName;
-
-  if (NS_SUCCEEDED(uri->GetHost(hostName))) {
+  nsresult rv = nsContentUtils::GetHostOrIPv6WithBrackets(uri, hostName);
+  if (NS_SUCCEEDED(rv)) {
     CopyUTF8toUTF16(hostName, aDomain);
   } else {
     // If we can't get the host from the URI (e.g. about:, javascript:,
     // etc), just return an null string.
     SetDOMStringToNull(aDomain);
   }
   return NS_OK;
 }
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -8561,16 +8561,26 @@ public:
                                   bool* aResult);
 
 private:
   ~GetFileReferencesHelper() {}
 
   NS_DECL_NSIRUNNABLE
 };
 
+class FlushPendingFileDeletionsRunnable final
+  : public nsRunnable
+{
+private:
+  ~FlushPendingFileDeletionsRunnable()
+  { }
+
+  NS_DECL_NSIRUNNABLE
+};
+
 class PermissionRequestHelper final
   : public PermissionRequestBase
   , public PIndexedDBPermissionRequestParent
 {
   bool mActorDestroyed;
 
 public:
   PermissionRequestHelper(Element* aOwnerElement,
@@ -9563,16 +9573,29 @@ DeallocPBackgroundIndexedDBUtilsParent(P
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   RefPtr<Utils> actor = dont_AddRef(static_cast<Utils*>(aActor));
   return true;
 }
 
+bool
+RecvFlushPendingFileDeletions()
+{
+  AssertIsOnBackgroundThread();
+
+  RefPtr<FlushPendingFileDeletionsRunnable> runnable =
+    new FlushPendingFileDeletionsRunnable();
+
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
+
+  return true;
+}
+
 PIndexedDBPermissionRequestParent*
 AllocPIndexedDBPermissionRequestParent(Element* aOwnerElement,
                                        nsIPrincipal* aPrincipal)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   RefPtr<PermissionRequestHelper> actor =
     new PermissionRequestHelper(aOwnerElement, aPrincipal);
@@ -27057,16 +27080,34 @@ GetFileReferencesHelper::Run()
   MOZ_ASSERT(mWaiting);
 
   mWaiting = false;
   mCondVar.Notify();
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+FlushPendingFileDeletionsRunnable::Run()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
+  if (NS_WARN_IF(!mgr)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsresult rv = mgr->FlushPendingFileDeletions();
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 void
 PermissionRequestHelper::OnPromptComplete(PermissionValue aPermissionValue)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!mActorDestroyed) {
     Unused <<
       PIndexedDBPermissionRequestParent::Send__delete__(this, aPermissionValue);
--- a/dom/indexedDB/ActorsParent.h
+++ b/dom/indexedDB/ActorsParent.h
@@ -40,16 +40,19 @@ bool
 DeallocPBackgroundIDBFactoryParent(PBackgroundIDBFactoryParent* aActor);
 
 PBackgroundIndexedDBUtilsParent*
 AllocPBackgroundIndexedDBUtilsParent();
 
 bool
 DeallocPBackgroundIndexedDBUtilsParent(PBackgroundIndexedDBUtilsParent* aActor);
 
+bool
+RecvFlushPendingFileDeletions();
+
 PIndexedDBPermissionRequestParent*
 AllocPIndexedDBPermissionRequestParent(Element* aOwnerElement,
                                        nsIPrincipal* aPrincipal);
 
 bool
 RecvPIndexedDBPermissionRequestConstructor(
                                      PIndexedDBPermissionRequestParent* aActor);
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -17,17 +17,16 @@
 
 #include "jsapi.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/CondVar.h"
 #include "mozilla/ContentEvents.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
-#include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/ErrorEvent.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "nsContentUtils.h"
@@ -929,22 +928,22 @@ IndexedDatabaseManager::FlushPendingFile
       return rv;
     }
 
     rv = Notify(mDeleteTimer);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   } else {
-    ContentChild* contentChild = ContentChild::GetSingleton();
-    if (NS_WARN_IF(!contentChild)) {
+    PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread();
+    if (NS_WARN_IF(!bgActor)) {
       return NS_ERROR_FAILURE;
     }
 
-    if (!contentChild->SendFlushPendingFileDeletions()) {
+    if (!bgActor->SendFlushPendingFileDeletions()) {
       return NS_ERROR_FAILURE;
     }
   }
 
   return NS_OK;
 }
 
 // static
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -177,17 +177,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_array.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_cross_database_copying.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_delete.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_os_delete.html]
-skip-if = e10s || (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116, Bug 1183959 for e10s
+skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_put_get_object.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_put_get_values.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_replace.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_file_resurrection_delete.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -59,17 +59,16 @@
 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
 #include "mozilla/dom/PFMRadioParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "mozilla/dom/icc/IccParent.h"
-#include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/PresentationParent.h"
 #include "mozilla/dom/PPresentationParent.h"
 #include "mozilla/dom/quota/QuotaManagerService.h"
 #include "mozilla/dom/telephony/TelephonyParent.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
@@ -286,17 +285,16 @@ using mozilla::ProfileGatherer;
 
 #ifdef MOZ_CRASHREPORTER
 using namespace CrashReporter;
 #endif
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::icc;
-using namespace mozilla::dom::indexedDB;
 using namespace mozilla::dom::power;
 using namespace mozilla::dom::mobileconnection;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
 using namespace mozilla::media;
 using namespace mozilla::embedding;
 using namespace mozilla::gmp;
@@ -5105,36 +5103,16 @@ ContentParent::AllocPFileDescriptorSetPa
 bool
 ContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
 {
   delete static_cast<FileDescriptorSetParent*>(aActor);
   return true;
 }
 
 bool
-ContentParent::RecvFlushPendingFileDeletions()
-{
-  RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
-  if (NS_WARN_IF(!mgr)) {
-    return false;
-  }
-
-  if (NS_WARN_IF(!mgr->IsMainProcess())) {
-    return false;
-  }
-
-  nsresult rv = mgr->FlushPendingFileDeletions();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return false;
-  }
-
-  return true;
-}
-
-bool
 ContentParent::IgnoreIPCPrincipal()
 {
   static bool sDidAddVarCache = false;
   static bool sIgnoreIPCPrincipal = false;
   if (!sDidAddVarCache) {
     sDidAddVarCache = true;
     Preferences::AddBoolVarCache(&sIgnoreIPCPrincipal,
                                  "dom.testing.ignore_ipc_principal", false);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1040,19 +1040,16 @@ private:
                            nsTArray<nsString>* aContent) override;
 
   virtual PFileDescriptorSetParent*
   AllocPFileDescriptorSetParent(const mozilla::ipc::FileDescriptor&) override;
 
   virtual bool
   DeallocPFileDescriptorSetParent(PFileDescriptorSetParent*) override;
 
-  virtual bool
-  RecvFlushPendingFileDeletions() override;
-
   virtual PWebrtcGlobalParent* AllocPWebrtcGlobalParent() override;
   virtual bool DeallocPWebrtcGlobalParent(PWebrtcGlobalParent *aActor) override;
 
 
   virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
                                     const uint32_t& aDropEffect) override;
 
   virtual bool RecvGetBrowserConfiguration(const nsCString& aURI,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1050,19 +1050,16 @@ parent:
         returns (nsString newValue);
 
     /**
      * Called to provide the options for <keygen> elements.
      */
     sync KeygenProvideContent()
         returns (nsString aAttribute, nsString[] aContent);
 
-    // Use only for testing!
-    async FlushPendingFileDeletions();
-
     /**
      * Tell the chrome process there is an creation of PBrowser.
      * return a system-wise unique Id.
      */
     sync AllocateTabId(TabId openerTabId, IPCTabContext context, ContentParentId cpId)
         returns (TabId tabId);
     async DeallocateTabId(TabId tabId,
                           ContentParentId cpId,
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -2626,16 +2626,19 @@ MediaManager::Shutdown()
 #endif
     prefs->RemoveObserver("media.navigator.audio.full_duplex", this);
   }
 
   // Close off any remaining active windows.
   GetActiveWindows()->Clear();
   mActiveCallbacks.Clear();
   mCallIds.Clear();
+#ifdef MOZ_WEBRTC
+  StopWebRtcLog();
+#endif
 
   // Because mMediaThread is not an nsThread, we must dispatch to it so it can
   // clean up BackgroundChild. Continue stopping thread once this is done.
 
   class ShutdownTask : public Task
   {
   public:
     ShutdownTask(MediaManager* aManager,
--- a/dom/media/mediasource/test/mediasource.js
+++ b/dom/media/mediasource/test/mediasource.js
@@ -48,18 +48,18 @@ function range(start, end) {
   for (var i = start; i < end; ++i) {
     rv.push(i);
   }
   return rv;
 }
 
 function once(target, name, cb) {
   var p = new Promise(function(resolve, reject) {
-    target.addEventListener(name, function() {
-      target.removeEventListener(name, arguments.callee);
+    target.addEventListener(name, function onceEvent() {
+      target.removeEventListener(name, onceEvent);
       resolve();
     });
   });
   if (cb) {
     p.then(cb);
   }
   return p;
 }
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -735,30 +735,35 @@ MediaCodecDataDecoder::Drain()
 }
 
 
 nsresult
 MediaCodecDataDecoder::Shutdown()
 {
   MonitorAutoLock lock(mMonitor);
 
-  if (!mThread || State() == kStopping) {
+  if (State() == kStopping) {
     // Already shutdown or in the process of doing so
     return NS_OK;
   }
 
   State(kStopping);
   lock.Notify();
 
-  while (State() == kStopping) {
+  while (mThread && State() == kStopping) {
     lock.Wait();
   }
 
-  mThread->Shutdown();
-  mThread = nullptr;
+  if (mThread) {
+    mThread->Shutdown();
+    mThread = nullptr;
+  }
 
-  mDecoder->Stop();
-  mDecoder->Release();
+  if (mDecoder) {
+    mDecoder->Stop();
+    mDecoder->Release();
+    mDecoder = nullptr;
+  }
 
   return NS_OK;
 }
 
 } // mozilla
--- a/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp
@@ -35,18 +35,18 @@ FFmpegLibWrapper::Link()
     (decltype(avcodec_version))PR_FindSymbol(mAVCodecLib, "avcodec_version");
   if (!avcodec_version) {
     Unlink();
     return false;
   }
   uint32_t version = avcodec_version();
   mVersion = (version >> 16) & 0xff;
   uint32_t micro = version & 0xff;
-  if (mVersion == 57 && micro != 100) {
-    // a micro version of 100 indicates that it's FFmpeg (as opposed to LibAV).
+  if (mVersion == 57 && micro < 100) {
+    // a micro version >= 100 indicates that it's FFmpeg (as opposed to LibAV).
     // Due to current AVCodecContext binary incompatibility we can only
     // support FFmpeg 57 at this stage.
     Unlink();
     return false;
   }
 
   enum {
     AV_FUNC_AVUTIL_MASK = 1 << 8,
new file mode 100644
--- /dev/null
+++ b/dom/media/test/external/mach_commands.py
@@ -0,0 +1,73 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import, unicode_literals
+
+import os
+import sys
+
+from mozbuild.base import (
+    MachCommandBase,
+    MachCommandConditions as conditions,
+)
+
+from mach.decorators import (
+    CommandProvider,
+    Command,
+)
+
+def setup_argument_parser():
+    from external_media_harness.runtests import MediaTestArguments
+    return MediaTestArguments()
+
+
+def run_external_media_test(tests, testtype=None, topsrcdir=None, **kwargs):
+    from external_media_harness.runtests import (
+        FirefoxMediaHarness,
+        MediaTestArguments,
+        MediaTestRunner,
+        mn_cli,
+    )
+
+    from mozlog.structured import commandline
+
+    parser = MediaTestArguments()
+    commandline.add_logging_group(parser)
+    args = parser.parse_args()
+
+    if not tests:
+        tests = [os.path.join(topsrcdir,
+                 'dom/media/test/external/external_media_tests/manifest.ini')]
+    args.tests = tests
+
+    if not args.binary:
+        args.binary = kwargs['binary']
+
+    for k, v in kwargs.iteritems():
+        setattr(args, k, v)
+
+    parser.verify_usage(args)
+
+    args.logger = commandline.setup_logging("Firefox External Media Tests",
+                                            args,
+                                            {"mach": sys.stdout})
+    failed = mn_cli(MediaTestRunner, MediaTestArguments, FirefoxMediaHarness,
+                    args=args)
+
+    if failed > 0:
+        return 1
+    else:
+        return 0
+
+
+@CommandProvider
+class MachCommands(MachCommandBase):
+    @Command('external-media-tests', category='testing',
+             description='Run Firefox external media tests.',
+             conditions=[conditions.is_firefox],
+             parser=setup_argument_parser,
+             )
+    def run_external_media_test(self, tests, **kwargs):
+        kwargs['binary'] = self.get_binary_path('app')
+        return run_external_media_test(tests, topsrcdir=self.topsrcdir, **kwargs)
--- a/dom/media/test/external/requirements.txt
+++ b/dom/media/test/external/requirements.txt
@@ -10,14 +10,14 @@ mozInstall==1.12
 mozlog==3.1
 moznetwork==0.27
 mozprocess==0.22
 mozprofile==0.28
 mozrunner==6.11
 moztest==0.7
 mozversion==1.4
 wptserve==1.3.0
-marionette-client==2.1.0
-marionette-driver==1.2.0
-firefox-puppeteer==3.1.0
+marionette-client == 2.2.0
+marionette-driver == 1.3.0
+firefox-puppeteer==3.2.0
 
 # Install the firefox media tests package
 ./
--- a/dom/media/test/external/setup.py
+++ b/dom/media/test/external/setup.py
@@ -2,21 +2,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/.
 
 from setuptools import setup, find_packages
 
 PACKAGE_VERSION = '1.0'
 
 deps = [
-    'marionette-client == 2.1.0',
-    'marionette-driver == 1.2.0',
+    'marionette-client == 2.2.0',
+    'marionette-driver == 1.3.0',
     'mozlog == 3.1',
     'manifestparser == 1.1',
-    'firefox-puppeteer >= 3.1.0, <4.0.0',
+    'firefox-puppeteer >= 3.2.0, <4.0.0',
 ]
 
 setup(name='external-media-tests',
       version=PACKAGE_VERSION,
       description=('A collection of Mozilla Firefox media playback tests run '
                    'with Marionette'),
       classifiers=[
           'Environment :: Console',
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -1352,18 +1352,18 @@ function removeNodeAndSource(n) {
   n.src = "";
   while (n.firstChild) {
     n.removeChild(n.firstChild);
   }
 }
 
 function once(target, name, cb) {
   var p = new Promise(function(resolve, reject) {
-    target.addEventListener(name, function() {
-      target.removeEventListener(name, cb);
+    target.addEventListener(name, function onceEvent() {
+      target.removeEventListener(name, onceEvent);
       resolve();
     });
   });
   if (cb) {
     p.then(cb);
   }
   return p;
 }
new file mode 100644
--- /dev/null
+++ b/dom/media/webspeech/synth/crashtests/1230428.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<meta charset="utf-8">
+<script type="application/javascript">
+function f()
+{
+  if (speechSynthesis.getVoices().length == 0) {
+    // No synthesis backend to test this
+    document.documentElement.removeAttribute('class');
+    return;
+  }
+
+  var s = new SpeechSynthesisUtterance("hello world");
+  s.onerror = () => {
+    // No synthesis backend to test this
+    document.documentElement.removeAttribute('class');
+    return;
+  }
+  s.onend = () => {
+    document.documentElement.removeAttribute('class');
+  };
+  speechSynthesis.speak(s);
+  speechSynthesis.cancel();
+  speechSynthesis.pause();
+  speechSynthesis.resume();
+}
+  </script>
+</head>
+<body onload="f();">
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/media/webspeech/synth/crashtests/crashtests.list
@@ -0,0 +1,1 @@
+skip-if(!cocoaWidget) pref(media.webspeech.synth.enabled,true) load 1230428.html # bug 1230428
--- a/dom/media/webspeech/synth/nsSpeechTask.cpp
+++ b/dom/media/webspeech/synth/nsSpeechTask.cpp
@@ -53,19 +53,26 @@ public:
   }
 
   void NotifyEvent(MediaStreamGraph* aGraph,
                    MediaStreamListener::MediaStreamGraphEvent event) override
   {
     switch (event) {
       case EVENT_FINISHED:
         {
-          nsCOMPtr<nsIRunnable> runnable =
+          if (!mStarted) {
+            mStarted = true;
+            nsCOMPtr<nsIRunnable> startRunnable =
+              NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyStarted);
+            aGraph->DispatchToMainThreadAfterStreamStateUpdate(startRunnable.forget());
+          }
+
+          nsCOMPtr<nsIRunnable> endRunnable =
             NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyFinished);
-          aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget());
+          aGraph->DispatchToMainThreadAfterStreamStateUpdate(endRunnable.forget());
         }
         break;
       case EVENT_REMOVED:
         mSpeechTask = nullptr;
         // Dereference MediaStream to destroy safety
         mStream = nullptr;
         break;
       default:
--- a/dom/plugins/base/nsPluginNativeWindowGtk.cpp
+++ b/dom/plugins/base/nsPluginNativeWindowGtk.cpp
@@ -19,16 +19,17 @@
 
 #if (GTK_MAJOR_VERSION == 3)
 #include <gtk/gtkx.h>
 #else
 #include "gtk2xtbin.h"
 #endif
 #include "mozilla/X11Util.h"
 
+static void plug_added_cb(GtkWidget *widget, gpointer data);
 static gboolean plug_removed_cb   (GtkWidget *widget, gpointer data);
 static void socket_unrealize_cb   (GtkWidget *widget, gpointer data);
 
 nsPluginNativeWindowGtk::nsPluginNativeWindowGtk() : nsPluginNativeWindow()
 {
   // initialize the struct fields
   window = nullptr; 
   x = 0; 
@@ -158,16 +159,19 @@ nsresult nsPluginNativeWindowGtk::Create
 
   //attach the socket to the container widget
   gtk_widget_set_parent_window(mSocketWidget, parent_win);
 
   // enable/disable focus event handlers,
   // see plugin_window_filter_func() for details
   g_object_set_data(G_OBJECT(mSocketWidget), "enable-xt-focus", (void *)aEnableXtFocus);
 
+  g_signal_connect(mSocketWidget, "plug_added",
+                   G_CALLBACK(plug_added_cb), nullptr);
+
   // Make sure to handle the plug_removed signal.  If we don't the
   // socket will automatically be destroyed when the plug is
   // removed, which means we're destroying it more than once.
   // SYNTAX ERROR.
   g_signal_connect(mSocketWidget, "plug_removed",
                    G_CALLBACK(plug_removed_cb), nullptr);
 
   g_signal_connect(mSocketWidget, "unrealize",
@@ -273,16 +277,42 @@ nsresult nsPluginNativeWindowGtk::Create
   // Leave mWsInfo.type = 0 - Who knows what this is meant to be?
 
   XFlush(mWsInfo.display);
 
   return NS_OK;
 }
 #endif
 
+static void
+plug_window_finalize_cb(gpointer socket, GObject* plug_window)
+{
+  g_object_unref(socket);
+}
+
+static void
+plug_added_cb(GtkWidget *socket, gpointer data)
+{
+  // The plug window has been embedded, and gtk_socket_add_window() has added
+  // a filter to the socket's plug_window, passing the socket as data for the
+  // filter, so the socket must live as long as events may be received on the
+  // plug window.
+  //
+  // https://git.gnome.org/browse/gtk+/tree/gtk/gtksocket.c?h=3.18.7#n1124
+  g_object_ref(socket);
+  // When the socket is unrealized, perhaps during gtk_widget_destroy() from
+  // ~nsPluginNativeWindowGtk, the plug is removed.  The plug in the child
+  // process then destroys its widget and window.  When the browser process
+  // receives the DestroyNotify event for the plug window, GDK releases its
+  // reference to plugWindow.  This is typically the last reference and so the
+  // weak ref callback triggers release of the socket.
+  GdkWindow* plugWindow = gtk_socket_get_plug_window(GTK_SOCKET(socket));
+  g_object_weak_ref(G_OBJECT(plugWindow), plug_window_finalize_cb, socket);
+}
+
 /* static */
 gboolean
 plug_removed_cb (GtkWidget *widget, gpointer data)
 {
   // Gee, thanks for the info!
   return TRUE;
 }
 
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -1969,22 +1969,16 @@ void
 RuntimeService::Shutdown()
 {
   AssertIsOnMainThread();
 
   MOZ_ASSERT(!mShuttingDown);
   // That's it, no more workers.
   mShuttingDown = true;
 
-  // Remove all listeners from the worker debugger manager to ensure that it
-  // gets properly destroyed.
-  if (NS_FAILED(ClearWorkerDebuggerManagerListeners())) {
-    NS_WARNING("Failed to clear worker debugger manager listeners!");
-  }
-
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_WARN_IF_FALSE(obs, "Failed to get observer service?!");
 
   // Tell anyone that cares that they're about to lose worker support.
   if (obs && NS_FAILED(obs->NotifyObservers(nullptr, WORKERS_SHUTDOWN_TOPIC,
                                             nullptr))) {
     NS_WARNING("NotifyObservers failed!");
   }
--- a/dom/workers/WorkerDebuggerManager.cpp
+++ b/dom/workers/WorkerDebuggerManager.cpp
@@ -3,72 +3,80 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WorkerDebuggerManager.h"
 
 #include "nsISimpleEnumerator.h"
 
+#include "mozilla/ClearOnShutdown.h"
+
 #include "WorkerPrivate.h"
 
 USING_WORKERS_NAMESPACE
 
+namespace {
+
 class RegisterDebuggerMainThreadRunnable final : public nsRunnable
 {
-  RefPtr<WorkerDebuggerManager> mManager;
   WorkerPrivate* mWorkerPrivate;
   bool mNotifyListeners;
 
 public:
-  RegisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager,
-                                     WorkerPrivate* aWorkerPrivate,
+  RegisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate,
                                      bool aNotifyListeners)
-  : mManager(aManager),
-    mWorkerPrivate(aWorkerPrivate),
+  : mWorkerPrivate(aWorkerPrivate),
     mNotifyListeners(aNotifyListeners)
   { }
 
 private:
   ~RegisterDebuggerMainThreadRunnable()
   { }
 
   NS_IMETHOD
   Run() override
   {
-    mManager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners);
+    WorkerDebuggerManager* manager = WorkerDebuggerManager::Get();
+    MOZ_ASSERT(manager);
 
+    manager->RegisterDebuggerMainThread(mWorkerPrivate, mNotifyListeners);
     return NS_OK;
   }
 };
 
 class UnregisterDebuggerMainThreadRunnable final : public nsRunnable
 {
-  RefPtr<WorkerDebuggerManager> mManager;
   WorkerPrivate* mWorkerPrivate;
 
 public:
-  UnregisterDebuggerMainThreadRunnable(WorkerDebuggerManager* aManager,
-                                       WorkerPrivate* aWorkerPrivate)
-  : mManager(aManager), mWorkerPrivate(aWorkerPrivate)
+  explicit UnregisterDebuggerMainThreadRunnable(WorkerPrivate* aWorkerPrivate)
+  : mWorkerPrivate(aWorkerPrivate)
   { }
 
 private:
   ~UnregisterDebuggerMainThreadRunnable()
   { }
 
   NS_IMETHOD
   Run() override
   {
-    mManager->UnregisterDebuggerMainThread(mWorkerPrivate);
+    WorkerDebuggerManager* manager = WorkerDebuggerManager::Get();
+    MOZ_ASSERT(manager);
 
+    manager->UnregisterDebuggerMainThread(mWorkerPrivate);
     return NS_OK;
   }
 };
 
+// Does not hold an owning reference.
+static WorkerDebuggerManager* gWorkerDebuggerManager;
+
+} /* anonymous namespace */
+
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerDebuggerEnumerator final : public nsISimpleEnumerator
 {
   nsTArray<RefPtr<WorkerDebugger>> mDebuggers;
   uint32_t mIndex;
 
 public:
@@ -111,17 +119,64 @@ WorkerDebuggerManager::WorkerDebuggerMan
   AssertIsOnMainThread();
 }
 
 WorkerDebuggerManager::~WorkerDebuggerManager()
 {
   AssertIsOnMainThread();
 }
 
-NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIWorkerDebuggerManager);
+// static
+already_AddRefed<WorkerDebuggerManager>
+WorkerDebuggerManager::GetInstance()
+{
+  RefPtr<WorkerDebuggerManager> manager = WorkerDebuggerManager::GetOrCreate();
+  return manager.forget();
+}
+
+// static
+WorkerDebuggerManager*
+WorkerDebuggerManager::GetOrCreate()
+{
+  AssertIsOnMainThread();
+
+  if (!gWorkerDebuggerManager) {
+    // The observer service now owns us until shutdown.
+    gWorkerDebuggerManager = new WorkerDebuggerManager();
+    if (NS_FAILED(gWorkerDebuggerManager->Init())) {
+      NS_WARNING("Failed to initialize worker debugger manager!");
+      gWorkerDebuggerManager = nullptr;
+      return nullptr;
+    }
+  }
+
+  return gWorkerDebuggerManager;
+}
+
+WorkerDebuggerManager*
+WorkerDebuggerManager::Get()
+{
+  MOZ_ASSERT(gWorkerDebuggerManager);
+  return gWorkerDebuggerManager;
+}
+
+NS_IMPL_ISUPPORTS(WorkerDebuggerManager, nsIObserver, nsIWorkerDebuggerManager);
+
+NS_IMETHODIMP
+WorkerDebuggerManager::Observe(nsISupports* aSubject, const char* aTopic,
+                               const char16_t* aData)
+{
+  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
+    Shutdown();
+    return NS_OK;
+  }
+
+  NS_NOTREACHED("Unknown observer topic!");
+  return NS_OK;
+}
 
 NS_IMETHODIMP
 WorkerDebuggerManager::GetWorkerDebuggerEnumerator(
                                                   nsISimpleEnumerator** aResult)
 {
   AssertIsOnMainThread();
 
   RefPtr<WorkerDebuggerEnumerator> enumerator =
@@ -156,18 +211,30 @@ WorkerDebuggerManager::RemoveListener(
   if (!mListeners.Contains(aListener)) {
     return NS_OK;
   }
 
   mListeners.RemoveElement(aListener);
   return NS_OK;
 }
 
+nsresult
+WorkerDebuggerManager::Init()
+{
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
+
+  nsresult rv = obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
 void
-WorkerDebuggerManager::ClearListeners()
+WorkerDebuggerManager::Shutdown()
 {
   AssertIsOnMainThread();
 
   MutexAutoLock lock(mMutex);
 
   mListeners.Clear();
 }
 
@@ -200,18 +267,17 @@ WorkerDebuggerManager::RegisterDebugger(
     bool hasListeners = false;
     {
       MutexAutoLock lock(mMutex);
 
       hasListeners = !mListeners.IsEmpty();
     }
 
     nsCOMPtr<nsIRunnable> runnable =
-      new RegisterDebuggerMainThreadRunnable(this, aWorkerPrivate,
-                                             hasListeners);
+      new RegisterDebuggerMainThreadRunnable(aWorkerPrivate, hasListeners);
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
       NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
 
     if (hasListeners) {
       aWorkerPrivate->WaitForIsDebuggerRegistered(true);
     }
   }
 }
@@ -220,17 +286,17 @@ void
 WorkerDebuggerManager::UnregisterDebugger(WorkerPrivate* aWorkerPrivate)
 {
   aWorkerPrivate->AssertIsOnParentThread();
 
   if (NS_IsMainThread()) {
     UnregisterDebuggerMainThread(aWorkerPrivate);
   } else {
     nsCOMPtr<nsIRunnable> runnable =
-      new UnregisterDebuggerMainThreadRunnable(this, aWorkerPrivate);
+      new UnregisterDebuggerMainThreadRunnable(aWorkerPrivate);
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
       NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)));
 
     aWorkerPrivate->WaitForIsDebuggerRegistered(false);
   }
 }
 
 void
--- a/dom/workers/WorkerDebuggerManager.h
+++ b/dom/workers/WorkerDebuggerManager.h
@@ -4,103 +4,116 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_workers_workerdebuggermanager_h
 #define mozilla_dom_workers_workerdebuggermanager_h
 
 #include "Workers.h"
 
+#include "nsIObserver.h"
 #include "nsIWorkerDebuggerManager.h"
 
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 
 #define WORKERDEBUGGERMANAGER_CID \
   { 0x62ec8731, 0x55ad, 0x4246, \
     { 0xb2, 0xea, 0xf2, 0x6c, 0x1f, 0xe1, 0x9d, 0x2d } }
 #define WORKERDEBUGGERMANAGER_CONTRACTID \
   "@mozilla.org/dom/workers/workerdebuggermanager;1"
 
 BEGIN_WORKERS_NAMESPACE
 
 class WorkerDebugger;
 
-class WorkerDebuggerManager final : public nsIWorkerDebuggerManager
+class WorkerDebuggerManager final : public nsIObserver,
+                                    public nsIWorkerDebuggerManager
 {
   Mutex mMutex;
 
   // Protected by mMutex.
   nsTArray<nsCOMPtr<nsIWorkerDebuggerManagerListener>> mListeners;
 
   // Only touched on the main thread.
   nsTArray<RefPtr<WorkerDebugger>> mDebuggers;
 
 public:
+  static already_AddRefed<WorkerDebuggerManager>
+  GetInstance();
+
   static WorkerDebuggerManager*
-  GetOrCreateService()
-  {
-    nsCOMPtr<nsIWorkerDebuggerManager> manager =
-      do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID);
-    return static_cast<WorkerDebuggerManager*>(manager.get());
-  }
+  GetOrCreate();
+
+  static WorkerDebuggerManager*
+  Get();
 
   WorkerDebuggerManager();
 
-  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
   NS_DECL_NSIWORKERDEBUGGERMANAGER
 
-  void ClearListeners();
+  nsresult
+  Init();
 
-  void RegisterDebugger(WorkerPrivate* aWorkerPrivate);
+  void
+  Shutdown();
+
+  void
+  RegisterDebugger(WorkerPrivate* aWorkerPrivate);
 
-  void UnregisterDebugger(WorkerPrivate* aWorkerPrivate);
+  void
+  RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate,
+                             bool aNotifyListeners);
 
-  void RegisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate,
-                                  bool aNotifyListeners);
+  void
+  UnregisterDebugger(WorkerPrivate* aWorkerPrivate);
 
-  void UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate);
+  void
+  UnregisterDebuggerMainThread(WorkerPrivate* aWorkerPrivate);
 
 private:
   virtual ~WorkerDebuggerManager();
 };
 
 inline nsresult
-ClearWorkerDebuggerManagerListeners()
-{
-  RefPtr<WorkerDebuggerManager> manager =
-    WorkerDebuggerManager::GetOrCreateService();
-  if (!manager) {
-    return NS_ERROR_FAILURE;
-  }
-
-  manager->ClearListeners();
-  return NS_OK;
-}
-
-inline nsresult
 RegisterWorkerDebugger(WorkerPrivate* aWorkerPrivate)
 {
-  RefPtr<WorkerDebuggerManager> manager =
-    WorkerDebuggerManager::GetOrCreateService();
-  if (!manager) {
-    return NS_ERROR_FAILURE;
+  WorkerDebuggerManager* manager;
+
+  if (NS_IsMainThread()) {
+    manager = WorkerDebuggerManager::GetOrCreate();
+    if (!manager) {
+      NS_WARNING("Failed to create worker debugger manager!");
+      return NS_ERROR_FAILURE;
+    }
+  }
+  else {
+    manager = WorkerDebuggerManager::Get();
   }
 
   manager->RegisterDebugger(aWorkerPrivate);
   return NS_OK;
 }
 
 inline nsresult
 UnregisterWorkerDebugger(WorkerPrivate* aWorkerPrivate)
 {
-  RefPtr<WorkerDebuggerManager> manager =
-    WorkerDebuggerManager::GetOrCreateService();
-  if (!manager) {
-    return NS_ERROR_FAILURE;
+  WorkerDebuggerManager* manager;
+
+  if (NS_IsMainThread()) {
+    manager = WorkerDebuggerManager::GetOrCreate();
+    if (!manager) {
+      NS_WARNING("Failed to create worker debugger manager!");
+      return NS_ERROR_FAILURE;
+    }
+  }
+  else {
+    manager = WorkerDebuggerManager::Get();
   }
 
   manager->UnregisterDebugger(aWorkerPrivate);
   return NS_OK;
 }
 
 END_WORKERS_NAMESPACE
 
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -1827,17 +1827,17 @@ XULDocument::RemoveElementFromRefMap(Ele
     // Remove the element from the resource-to-element map.
     nsAutoString value;
     GetRefMapAttribute(aElement, &value);
     if (!value.IsEmpty()) {
         nsRefMapEntry *entry = mRefMap.GetEntry(value);
         if (!entry)
             return;
         if (entry->RemoveElement(aElement)) {
-            mRefMap.RawRemoveEntry(entry);
+            mRefMap.RemoveEntry(entry);
         }
     }
 }
 
 //----------------------------------------------------------------------
 //
 // nsIDOMNode interface
 //
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -1566,17 +1566,17 @@ nsPermissionManager::AddInternal(nsIPrin
   NS_ENSURE_TRUE(typeIndex != -1, NS_ERROR_OUT_OF_MEMORY);
 
   // When an entry already exists, PutEntry will return that, instead
   // of adding a new one
   RefPtr<PermissionKey> key = new PermissionKey(aPrincipal);
   PermissionHashKey* entry = mPermissionTable.PutEntry(key);
   if (!entry) return NS_ERROR_FAILURE;
   if (!entry->GetKey()) {
-    mPermissionTable.RawRemoveEntry(entry);
+    mPermissionTable.RemoveEntry(entry);
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // figure out the transaction type, and get any existing permission value
   OperationType op;
   int32_t index = entry->GetPermissionIndex(typeIndex);
   if (index == -1) {
     if (aPermission == nsIPermissionManager::UNKNOWN_ACTION)
@@ -1689,17 +1689,17 @@ nsPermissionManager::AddInternal(nsIPrin
                                       oldPermissionEntry.mPermission,
                                       oldPermissionEntry.mExpireType,
                                       oldPermissionEntry.mExpireTime,
                                       MOZ_UTF16("deleted"));
       }
 
       // If there are no more permissions stored for that entry, clear it.
       if (entry->GetPermissions().IsEmpty()) {
-        mPermissionTable.RawRemoveEntry(entry);
+        mPermissionTable.RemoveEntry(entry);
       }
 
       break;
     }
 
   case eOperationChanging:
     {
       id = entry->GetPermissions()[index].mID;
--- a/gfx/graphite2/src/Face.cpp
+++ b/gfx/graphite2/src/Face.cpp
@@ -233,17 +233,17 @@ uint16 Face::findPseudo(uint32 uid) cons
 
 uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
 {
     switch (metrics(metric))
     {
         case kgmetAscent : return m_ascent;
         case kgmetDescent : return m_descent;
         default: 
-            if (gid > glyphs().numGlyphs()) return 0;
+            if (gid >= glyphs().numGlyphs()) return 0;
             return glyphs().glyph(gid)->getMetric(metric);
     }
 }
 
 void Face::takeFileFace(FileFace* pFileFace GR_MAYBE_UNUSED/*takes ownership*/)
 {
 #ifndef GRAPHITE2_NFILEFACE
     if (m_pFileFace==pFileFace)
--- a/gfx/graphite2/src/FileFace.cpp
+++ b/gfx/graphite2/src/FileFace.cpp
@@ -55,18 +55,22 @@ FileFace::FileFace(const char *filename)
         if (fread(_header_tbl, 1, tbl_len, _file) != tbl_len) return;
         if (!TtfUtil::CheckHeader(_header_tbl)) return;
     }
 
     // Get the table directory
     if (!TtfUtil::GetTableDirInfo(_header_tbl, tbl_offset, tbl_len)) return;
     _table_dir = (TtfUtil::Sfnt::OffsetSubTable::Entry*)gralloc<char>(tbl_len);
     if (fseek(_file, tbl_offset, SEEK_SET)) return;
-    if (_table_dir)
-        if (fread(_table_dir, 1, tbl_len, _file) != tbl_len) return;
+    if (_table_dir && fread(_table_dir, 1, tbl_len, _file) != tbl_len)
+    {
+        free(_table_dir);
+        _table_dir = NULL;
+    }
+    return;
 }
 
 FileFace::~FileFace()
 {
     free(_table_dir);
     free(_header_tbl);
     if (_file)
         fclose(_file);
--- a/gfx/graphite2/src/Pass.cpp
+++ b/gfx/graphite2/src/Pass.cpp
@@ -95,17 +95,19 @@ bool Pass::readPass(const byte * const p
 {
     const byte * p              = pass_start,
                * const pass_end = p + pass_length;
     size_t numRanges;
 
     if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e); 
     // Read in basic values
     const byte flags = be::read<byte>(p);
-    if (e.test((flags & 0x1f) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS))
+    if (e.test((flags & 0x1f) && 
+            (pt < PASS_TYPE_POSITIONING || !m_silf->aCollision() || !face.glyphs().hasBoxes()),
+            E_BADCOLLISIONPASS))
         return face.error(e);
     m_numCollRuns = flags & 0x7;
     m_kernColls   = (flags >> 3) & 0x3;
     m_isReverseDir = (flags >> 5) & 0x1;
     m_iMaxLoop = be::read<byte>(p);
     if (m_iMaxLoop < 1) m_iMaxLoop = 1;
     be::skip<byte>(p,2); // skip maxContext & maxBackup
     m_numRules = be::read<uint16>(p);
--- a/gfx/graphite2/src/inc/GlyphCache.h
+++ b/gfx/graphite2/src/inc/GlyphCache.h
@@ -107,16 +107,17 @@ public:
     uint8            numSubBounds(unsigned short glyphid) const;
     float            getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const;
     const Rect &     slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : _empty_slant_box; }
     const SlantBox & getBoundingSlantBox(unsigned short glyphid) const;
     const BBox &     getBoundingBBox(unsigned short glyphid) const;
     const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
     const BBox &     getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const;
     bool             check(unsigned short glyphid) const;
+    bool             hasBoxes() const { return _boxes != 0; }
 
     CLASS_NEW_DELETE;
     
 private:
     const Rect            _empty_slant_box;
     const Loader        * _glyph_loader;
     const GlyphFace *   * _glyphs;
     GlyphBox        *   * _boxes;
--- a/gfx/layers/apz/test/mochitest/mochitest.ini
+++ b/gfx/layers/apz/test/mochitest/mochitest.ini
@@ -26,8 +26,9 @@ skip-if = (os == 'android') || (os == 'b
 [test_basic_pan.html]
 skip-if = toolkit != 'gonk'
 [test_scroll_inactive_flattened_frame.html]
 skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
 [test_scroll_inactive_bug1190112.html]
 skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
 [test_scroll_subframe_scrollbar.html]
 skip-if = (os == 'android') || (os == 'b2g') || (buildapp == 'mulet') # wheel events not supported on mobile; see bug 1164274 for mulet
+[test_frame_reconstruction.html]
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/test/mochitest/test_frame_reconstruction.html
@@ -0,0 +1,231 @@
+<!DOCTYPE html>
+<html>
+ <!--
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1235899
+ -->
+ <head>
+  <title>Test for bug 1235899</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
+  <script type="application/javascript" src="apz_test_utils.js"></script>
+  <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <style>
+    .outer {
+        height: 400px;
+        width: 415px;
+        overflow: hidden;
+        position: relative;
+    }
+    .inner {
+        height: 100%;
+        outline: none;
+        overflow-x: hidden;
+        overflow-y: scroll;
+        position: relative;
+        scroll-behavior: smooth;
+    }
+    .outer.contentBefore::before {
+        top: 0;
+        content: '';
+        display: block;
+        height: 2px;
+        position: absolute;
+        width: 100%;
+        z-index: 99;
+    }
+  </style>
+ </head>
+ <body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1235899">Mozilla Bug 1235899</a>
+<p id="display"></p>
+<div id="content">
+ <p>You should be able to fling this list without it stopping abruptly</p>
+ <div class="outer">
+  <div class="inner">
+   <ol>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+    <li>Some text</li>
+   </ol>
+  </div>
+ </div>
+</div>
+
+<pre id="test">
+<script type="application/javascript;version=1.7">
+function* runTest() {
+  var elm = document.getElementsByClassName('inner')[0];
+  elm.scrollTop = 0;
+  yield flushApzRepaints(driveTest);
+
+  // Take over control of the refresh driver and compositor
+  var utils = SpecialPowers.DOMWindowUtils;
+  utils.advanceTimeAndRefresh(0);
+
+  // Kick off an APZ smooth-scroll to 0,200
+  elm.scrollTo(0, 200);
+  yield waitForAllPaints(function() { setTimeout(driveTest, 0); });
+
+  // Let's do a couple of frames of the animation, and make sure it's going
+  utils.advanceTimeAndRefresh(16);
+  utils.advanceTimeAndRefresh(16);
+  yield flushApzRepaints(driveTest);
+  ok(elm.scrollTop > 0, "APZ animation in progress", "scrollTop is now " + elm.scrollTop);
+  ok(elm.scrollTop < 200, "APZ animation not yet completed", "scrollTop is now " + elm.scrollTop);
+
+  var frameReconstructionTriggered = 0;
+  // Register the listener that triggers the frame reconstruction
+  elm.onscroll = function() {
+    // Do the reconstruction
+    elm.parentNode.classList.add('contentBefore');
+    frameReconstructionTriggered++;
+    // schedule a thing to undo the changes above
+    setTimeout(function() {
+      elm.parentNode.classList.remove('contentBefore');
+    }, 0);
+  }
+
+  // and do a few more frames of the animation, this should trigger the listener
+  // and the frame reconstruction
+  utils.advanceTimeAndRefresh(16);
+  utils.advanceTimeAndRefresh(16);
+  yield flushApzRepaints(driveTest);
+  ok(elm.scrollTop < 200, "APZ animation not yet completed", "scrollTop is now " + elm.scrollTop);
+  ok(frameReconstructionTriggered > 0, "Frame reconstruction triggered", "reconstruction triggered " + frameReconstructionTriggered + " times");
+
+  // and now run to completion
+  for (var i = 0; i < 100; i++) {
+    utils.advanceTimeAndRefresh(16);
+  }
+  utils.restoreNormalRefresh();
+  yield waitForAllPaints(function() { setTimeout(driveTest, 0); });
+  yield flushApzRepaints(driveTest);
+
+  is(elm.scrollTop, 200, "Element should have scrolled by 200px");
+}
+
+var gTestContinuation = null;
+function driveTest() {
+  if (!gTestContinuation) {
+    gTestContinuation = runTest();
+  }
+  var ret = gTestContinuation.next();
+  if (ret.done) {
+    SimpleTest.finish();
+  }
+}
+
+SimpleTest.waitForExplicitFinish();
+var apzEnabled = SpecialPowers.getDOMWindowUtils(window).asyncPanZoomEnabled;
+if (!apzEnabled) {
+  ok(true, "APZ not enabled, skipping test");
+  SimpleTest.finish();
+} else {
+  SimpleTest.expectAssertions(0, 1); // this test triggers an assertion, see bug 1247050
+  SimpleTest.waitForFocus(driveTest, window);
+}
+
+</script>
+</body>
+</html>
--- a/gfx/layers/apz/test/mochitest/test_smoothness.html
+++ b/gfx/layers/apz/test/mochitest/test_smoothness.html
@@ -56,22 +56,16 @@
 
     window.onload = function() {
       var apzEnabled = SpecialPowers.getBoolPref("layers.async-pan-zoom.enabled");
       if (!apzEnabled) {
         SimpleTest.ok(true, "APZ not enabled, skipping test");
         SimpleTest.finish();
       }
 
-      var hwVsyncEnabled = SpecialPowers.getBoolPref("gfx.vsync.hw-vsync.enabled");
-      if (!hwVsyncEnabled) {
-        SimpleTest.ok(true, "Hardware vsync not enabled, skipping test");
-        SimpleTest.finish();
-      }
-
       SpecialPowers.pushPrefEnv({
         "set" : [
           [testPref, true]
         ]
       }, startTest);
     }
     </script>
 </head>
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -87,21 +87,21 @@ ScrollFrameTo(nsIScrollableFrame* aFrame
     targetScrollPosition.y = geckoScrollPosition.y;
   }
   if (aFrame->GetScrollbarStyles().mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
     targetScrollPosition.x = geckoScrollPosition.x;
   }
 
   // If the scrollable frame is currently in the middle of an async or smooth
   // scroll then we don't want to interrupt it (see bug 961280).
-  // Also if the scrollable frame got a scroll request from something other than us
+  // Also if the scrollable frame got a scroll request from a higher priority origin
   // since the last layers update, then we don't want to push our scroll request
   // because we'll clobber that one, which is bad.
   bool scrollInProgress = aFrame->IsProcessingAsyncScroll()
-      || (aFrame->LastScrollOrigin() && aFrame->LastScrollOrigin() != nsGkAtoms::apz)
+      || nsLayoutUtils::CanScrollOriginClobberApz(aFrame->LastScrollOrigin())
       || aFrame->LastSmoothScrollOrigin();
   if (!scrollInProgress) {
     aFrame->ScrollToCSSPixelsApproximate(targetScrollPosition, nsGkAtoms::apz);
     geckoScrollPosition = CSSPoint::FromAppUnits(aFrame->GetScrollPosition());
     aSuccessOut = true;
   }
   // Return the final scroll position after setting it so that anything that relies
   // on it can have an accurate value. Note that even if we set it above re-querying it
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -559,18 +559,18 @@ RenderLayers(ContainerT* aContainer,
       aManager->GetCompositor()->DrawQuad(gfx::Rect(layerBounds.x, layerBounds.y, layerBounds.width, layerBounds.height),
                                           gfx::Rect(clipRect.ToUnknownRect()),
                                           effectChain, layer->GetEffectiveOpacity(),
                                           layer->GetEffectiveTransform());
     }
 
     if (layerToRender->HasLayerBeenComposited()) {
       // Composer2D will compose this layer so skip GPU composition
-      // this time & reset composition flag for next composition phase
-      layerToRender->SetLayerComposited(false);
+      // this time. The flag will be reset for the next composition phase
+      // at the beginning of LayerManagerComposite::Rener().
       gfx::IntRect clearRect = layerToRender->GetClearRect();
       if (!clearRect.IsEmpty()) {
         // Clear layer's visible rect on FrameBuffer with transparent pixels
         gfx::Rect fbRect(clearRect.x, clearRect.y, clearRect.width, clearRect.height);
         compositor->ClearRect(fbRect);
         layerToRender->SetClearRect(gfx::IntRect(0, 0, 0, 0));
       }
     } else {
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -757,27 +757,44 @@ LayerManagerComposite::PopGroupForLayerE
   effectChain.mPrimaryEffect = new EffectRenderTarget(mTwoPassTmpTarget);
   effectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX] = new EffectColorMatrix(effectMatrix);
 
   gfx::Rect clipRectF(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
   mCompositor->DrawQuad(Rect(Point(0, 0), Size(mTwoPassTmpTarget->GetSize())), clipRectF, effectChain, 1.,
                         Matrix4x4());
 }
 
+// Used to clear the 'mLayerComposited' flag at the beginning of each Render().
+static void
+ClearLayerFlags(Layer* aLayer) {
+  if (!aLayer) {
+    return;
+  }
+  if (aLayer->AsLayerComposite()) {
+    aLayer->AsLayerComposite()->SetLayerComposited(false);
+  }
+  for (Layer* child = aLayer->GetFirstChild(); child;
+       child = child->GetNextSibling()) {
+    ClearLayerFlags(child);
+  }
+}
+
 void
 LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion)
 {
   PROFILER_LABEL("LayerManagerComposite", "Render",
     js::ProfileEntry::Category::GRAPHICS);
 
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
+  ClearLayerFlags(mRoot);
+
   // At this time, it doesn't really matter if these preferences change
   // during the execution of the function; we should be safe in all
   // permutations. However, may as well just get the values onces and
   // then use them, just in case the consistency becomes important in
   // the future.
   bool invertVal = gfxPrefs::LayersEffectInvert();
   bool grayscaleVal = gfxPrefs::LayersEffectGrayscale();
   float contrastVal = gfxPrefs::LayersEffectContrast();
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -53,16 +53,47 @@ using base::Thread;
 using base::ProcessId;
 using namespace mozilla::ipc;
 using namespace mozilla::gfx;
 using namespace mozilla::media;
 
 typedef std::vector<CompositableOperation> OpVector;
 typedef nsTArray<OpDestroy> OpDestroyVector;
 
+namespace {
+class ImageBridgeThread : public Thread {
+public:
+
+  ImageBridgeThread() : Thread("ImageBridgeChild") {
+  }
+
+protected:
+
+  void Init() {
+#ifdef MOZ_ENABLE_PROFILER_SPS
+    mPseudoStackHack = mozilla_get_pseudo_stack();
+#endif
+  }
+
+  void CleanUp() {
+#ifdef MOZ_ENABLE_PROFILER_SPS
+    mPseudoStackHack = nullptr;
+#endif
+  }
+
+private:
+
+#ifdef MOZ_ENABLE_PROFILER_SPS
+  // This is needed to avoid a spurious leak report.  There's no other
+  // use for it.  See bug 1239504 and bug 1215265.
+  PseudoStack* mPseudoStackHack;
+#endif
+};
+}
+
 struct CompositableTransaction
 {
   CompositableTransaction()
   : mSwapRequired(false)
   , mFinished(true)
   {}
   ~CompositableTransaction()
   {
@@ -371,17 +402,17 @@ ImageBridgeChild* ImageBridgeChild::GetS
 bool ImageBridgeChild::IsCreated()
 {
   return GetSingleton() != nullptr;
 }
 
 void ImageBridgeChild::StartUp()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
-  ImageBridgeChild::StartUpOnThread(new Thread("ImageBridgeChild"));
+  ImageBridgeChild::StartUpOnThread(new ImageBridgeThread());
 }
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
 
 static void
 ConnectImageBridgeInChildProcess(Transport* aTransport,
@@ -704,17 +735,17 @@ static void CallSendImageBridgeThreadId(
 PImageBridgeChild*
 ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
                                         ProcessId aOtherPid)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   gfxPlatform::GetPlatform();
 
-  sImageBridgeChildThread = new Thread("ImageBridgeChild");
+  sImageBridgeChildThread = new ImageBridgeThread();
   if (!sImageBridgeChildThread->Start()) {
     return nullptr;
   }
 
   sImageBridgeChildSingleton = new ImageBridgeChild();
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
     NewRunnableFunction(ConnectImageBridgeInChildProcess,
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -585,21 +585,22 @@ private:
 hb_blob_t *
 gfxFontEntry::FontTableHashEntry::
 ShareTableAndGetBlob(nsTArray<uint8_t>&& aTable,
                      nsTHashtable<FontTableHashEntry> *aHashtable)
 {
     Clear();
     // adopts elements of aTable
     mSharedBlobData = new FontTableBlobData(Move(aTable));
+
     mBlob = hb_blob_create(mSharedBlobData->GetTable(),
                            mSharedBlobData->GetTableLength(),
                            HB_MEMORY_MODE_READONLY,
                            mSharedBlobData, DeleteFontTableBlobData);
-    if (!mSharedBlobData) {
+    if (mBlob == hb_blob_get_empty() ) {
         // The FontTableBlobData was destroyed during hb_blob_create().
         // The (empty) blob is still be held in the hashtable with a strong
         // reference.
         return hb_blob_reference(mBlob);
     }
 
     // Tell the FontTableBlobData to remove this hash entry when destroyed.
     // The hashtable does not keep a strong reference.
--- a/gfx/thebes/gfxFontconfigUtils.cpp
+++ b/gfx/thebes/gfxFontconfigUtils.cpp
@@ -612,23 +612,23 @@ gfxFontconfigUtils::UpdateFontListIntern
             for (int v = 0;
              FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch;
              ++v) {
                 FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family);
                 if (entry) {
                     bool added = entry->AddFont(font);
 
                     if (!entry->mKey) {
-                        // The reference to the font pattern keeps the pointer to
-                        // string for the key valid.  If adding the font failed
-                        // then the entry must be removed.
+                        // The reference to the font pattern keeps the pointer
+                        // to string for the key valid.  If adding the font
+                        // failed then the entry must be removed.
                         if (added) {
                             entry->mKey = family;
                         } else {
-                            mFontsByFamily.RawRemoveEntry(entry);
+                            mFontsByFamily.RemoveEntry(entry);
                         }
                     }
                 }
             }
         }
     }
 
     mLastConfig = currentConfig;
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -212,16 +212,25 @@ BackgroundParentImpl::DeallocPBackground
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   return
     mozilla::dom::indexedDB::DeallocPBackgroundIndexedDBUtilsParent(aActor);
 }
 
+bool
+BackgroundParentImpl::RecvFlushPendingFileDeletions()
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+
+  return mozilla::dom::indexedDB::RecvFlushPendingFileDeletions();
+}
+
 auto
 BackgroundParentImpl::AllocPBlobParent(const BlobConstructorParams& aParams)
   -> PBlobParent*
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
 
   if (NS_WARN_IF(aParams.type() !=
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -53,16 +53,19 @@ protected:
   virtual PBackgroundIndexedDBUtilsParent*
   AllocPBackgroundIndexedDBUtilsParent() override;
 
   virtual bool
   DeallocPBackgroundIndexedDBUtilsParent(
                                         PBackgroundIndexedDBUtilsParent* aActor)
                                         override;
 
+  virtual bool
+  RecvFlushPendingFileDeletions() override;
+
   virtual PBlobParent*
   AllocPBlobParent(const BlobConstructorParams& aParams) override;
 
   virtual bool
   DeallocPBlobParent(PBlobParent* aActor) override;
 
   virtual bool
   RecvPBlobConstructor(PBlobParent* aActor,
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -152,16 +152,17 @@ public:
         MOZ_RELEASE_ASSERT(mMessageName);
     }
 
     InterruptFrame(InterruptFrame&& aOther)
     {
         MOZ_RELEASE_ASSERT(aOther.mMessageName);
         mMessageName = aOther.mMessageName;
         aOther.mMessageName = nullptr;
+        mMoved = aOther.mMoved;
         aOther.mMoved = true;
 
         mMessageRoutingId = aOther.mMessageRoutingId;
         mMesageSemantics = aOther.mMesageSemantics;
         mDirection = aOther.mDirection;
     }
 
     ~InterruptFrame()
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -61,16 +61,19 @@ sync protocol PBackground
 parent:
   // Only called at startup during mochitests to check the basic infrastructure.
   async PBackgroundTest(nsCString testArg);
 
   async PBackgroundIDBFactory(LoggingInfo loggingInfo);
 
   async PBackgroundIndexedDBUtils();
 
+  // Use only for testing!
+  async FlushPendingFileDeletions();
+
   async PVsync();
 
   async PCameras();
 
   async PUDPSocket(OptionalPrincipalInfo pInfo, nsCString filter);
   async PBroadcastChannel(PrincipalInfo pInfo, nsCString origin, nsString channel,
                           bool privateBrowsing);
 
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -463,17 +463,16 @@ struct NotableScriptSourceInfo : public 
  * compartments within it.
  */
 struct RuntimeSizes
 {
 #define FOR_EACH_SIZE(macro) \
     macro(_, MallocHeap, object) \
     macro(_, MallocHeap, atomsTable) \
     macro(_, MallocHeap, contexts) \
-    macro(_, MallocHeap, dtoa) \
     macro(_, MallocHeap, temporary) \
     macro(_, MallocHeap, interpreterStack) \
     macro(_, MallocHeap, mathCache) \
     macro(_, MallocHeap, uncompressedSourceCache) \
     macro(_, MallocHeap, compressedSourceSet) \
     macro(_, MallocHeap, scriptData)
 
     RuntimeSizes()
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -929,17 +929,17 @@ MutableHandle<T>::MutableHandle(Persiste
 
 /**
  * A copyable, assignable global GC root type with arbitrary lifetime, an
  * infallible constructor, and automatic unrooting on destruction.
  *
  * These roots can be used in heap-allocated data structures, so they are not
  * associated with any particular JSContext or stack. They are registered with
  * the JSRuntime itself, without locking, so they require a full JSContext to be
- * initialized, not one of its more restricted superclasses.  Initialization may
+ * initialized, not one of its more restricted superclasses. Initialization may
  * take place on construction, or in two phases if the no-argument constructor
  * is called followed by init().
  *
  * Note that you must not use an PersistentRooted in an object owned by a JS
  * object:
  *
  * Whenever one object whose lifetime is decided by the GC refers to another
  * such object, that edge must be traced only if the owning JS object is traced.
@@ -1043,19 +1043,20 @@ class PersistentRooted : public js::Pers
         return &ptr;
     }
     T& get() {
         MOZ_ASSERT(initialized());
         return ptr;
     }
 
   private:
-    void set(T value) {
+    template <typename U>
+    void set(U&& value) {
         MOZ_ASSERT(initialized());
-        ptr = value;
+        ptr = mozilla::Forward<U>(value);
     }
 
     // See the comment above Rooted::ptr.
     using MaybeWrapped = typename mozilla::Conditional<
         MapTypeToRootKind<T>::kind == JS::RootKind::Traceable,
         js::DispatchWrapper<T>,
         T>::Type;
 
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -25,16 +25,18 @@
 #include "vm/ArrayBufferObject.h"
 
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::wasm;
 
+using mozilla::IsNaN;
+
 typedef Handle<WasmModuleObject*> HandleWasmModule;
 typedef MutableHandle<WasmModuleObject*> MutableHandleWasmModule;
 
 /*****************************************************************************/
 // reporting
 
 static bool
 Fail(JSContext* cx, const char* str)
@@ -947,16 +949,19 @@ DecodeCodeSection(JSContext* cx, Decoder
 }
 
 static bool
 DecodeDataSection(JSContext* cx, Decoder& d, Handle<ArrayBufferObject*> heap)
 {
     if (!d.readCStringIf(DataSection))
         return true;
 
+    if (!heap)
+        return Fail(cx, d, "data section requires a memory section");
+
     uint32_t sectionStart;
     if (!d.startSection(&sectionStart))
         return Fail(cx, d, "expected data section byte size");
 
     uint32_t numSegments;
     if (!d.readVarU32(&numSegments))
         return Fail(cx, d, "expected number of data segments");
 
--- a/js/src/asmjs/WasmFrameIterator.cpp
+++ b/js/src/asmjs/WasmFrameIterator.cpp
@@ -91,16 +91,17 @@ FrameIterator::settle()
         break;
       case CodeRange::Entry:
         fp_ = nullptr;
         MOZ_ASSERT(done());
         break;
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
       case CodeRange::Inline:
+      case CodeRange::CallThunk:
         MOZ_CRASH("Should not encounter an exit during iteration");
     }
 }
 
 JSAtom*
 FrameIterator::functionDisplayAtom() const
 {
     MOZ_ASSERT(!done());
@@ -486,16 +487,17 @@ ProfilingFrameIterator::initFromFP(const
         fp = CallerFPFromFP(fp);
         callerPC_ = ReturnAddressFromFP(fp);
         callerFP_ = CallerFPFromFP(fp);
         AssertMatchesCallSite(*module_, callerPC_, callerFP_, fp);
         break;
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
       case CodeRange::Inline:
+      case CodeRange::CallThunk:
         MOZ_CRASH("Unexpected CodeRange kind");
     }
 
     // The iterator inserts a pretend innermost frame for non-None ExitReasons.
     // This allows the variety of exit reasons to show up in the callstack.
     exitReason_ = activation.exitReason();
 
     // In the case of calls to builtins or asynchronous interrupts, no exit path
@@ -536,47 +538,50 @@ ProfilingFrameIterator::ProfilingFrameIt
     }
 
     // Note: fp may be null while entering and leaving the activation.
     uint8_t* fp = activation.fp();
 
     const CodeRange* codeRange = module_->lookupCodeRange(state.pc);
     switch (codeRange->kind()) {
       case CodeRange::Function:
+      case CodeRange::CallThunk:
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit: {
         // When the pc is inside the prologue/epilogue, the innermost
         // call's AsmJSFrame is not complete and thus fp points to the the
         // second-to-innermost call's AsmJSFrame. Since fp can only tell you
         // about its caller (via ReturnAddressFromFP(fp)), naively unwinding
         // while pc is in the prologue/epilogue would skip the second-to-
         // innermost call. To avoid this problem, we use the static structure of
         // the code in the prologue and epilogue to do the Right Thing.
         MOZ_ASSERT(module_->containsCodePC(state.pc));
         uint32_t offsetInModule = (uint8_t*)state.pc - module_->code();
         MOZ_ASSERT(offsetInModule >= codeRange->begin());
         MOZ_ASSERT(offsetInModule < codeRange->end());
         uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
         void** sp = (void**)state.sp;
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-        if (offsetInCodeRange < PushedRetAddr) {
+        if (offsetInCodeRange < PushedRetAddr || codeRange->kind() == CodeRange::CallThunk) {
             // First instruction of the ARM/MIPS function; the return address is
             // still in lr and fp still holds the caller's fp.
             callerPC_ = state.lr;
             callerFP_ = fp;
             AssertMatchesCallSite(*module_, callerPC_, callerFP_, sp - 2);
         } else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) {
             // Second-to-last instruction of the ARM/MIPS function; fp points to
             // the caller's fp; have not yet popped AsmJSFrame.
             callerPC_ = ReturnAddressFromFP(sp);
             callerFP_ = CallerFPFromFP(sp);
             AssertMatchesCallSite(*module_, callerPC_, callerFP_, sp);
         } else
 #endif
-        if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn()) {
+        if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn() ||
+            codeRange->kind() == CodeRange::CallThunk)
+        {
             // The return address has been pushed on the stack but not fp; fp
             // still points to the caller's fp.
             callerPC_ = *sp;
             callerFP_ = fp;
             AssertMatchesCallSite(*module_, callerPC_, callerFP_, sp - 1);
         } else if (offsetInCodeRange < StoredFP) {
             // The full AsmJSFrame has been pushed; fp still points to the
             // caller's frame.
@@ -650,16 +655,17 @@ ProfilingFrameIterator::operator++()
       case CodeRange::Entry:
         MOZ_ASSERT(callerFP_ == nullptr);
         callerPC_ = nullptr;
         break;
       case CodeRange::Function:
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
       case CodeRange::Inline:
+      case CodeRange::CallThunk:
         stackAddress_ = callerFP_;
         callerPC_ = ReturnAddressFromFP(callerFP_);
         AssertMatchesCallSite(*module_, callerPC_, CallerFPFromFP(callerFP_), callerFP_);
         callerFP_ = CallerFPFromFP(callerFP_);
         break;
     }
 
     MOZ_ASSERT(!done());
@@ -691,16 +697,17 @@ ProfilingFrameIterator::label() const
     }
 
     switch (codeRange_->kind()) {
       case CodeRange::Function:         return module_->profilingLabel(codeRange_->funcIndex());
       case CodeRange::Entry:            return "entry trampoline (in asm.js)";
       case CodeRange::ImportJitExit:    return importJitDescription;
       case CodeRange::ImportInterpExit: return importInterpDescription;
       case CodeRange::Inline:           return "inline stub (in asm.js)";
+      case CodeRange::CallThunk:        return "call thunk (in asm.js)";
     }
 
     MOZ_CRASH("bad code range kind");
 }
 
 /*****************************************************************************/
 // Runtime patching to enable/disable profiling
 
@@ -766,16 +773,24 @@ wasm::EnableProfilingPrologue(const Modu
     instr[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr);
 #elif defined(JS_CODEGEN_NONE)
     MOZ_CRASH();
 #else
 # error "Missing architecture"
 #endif
 }
 
+void
+wasm::EnableProfilingThunk(const Module& module, const CallThunk& callThunk, bool enabled)
+{
+    const CodeRange& cr = module.codeRanges()[callThunk.u.codeRangeIndex];
+    uint32_t calleeOffset = enabled ? cr.funcProfilingEntry() : cr.funcNonProfilingEntry();
+    MacroAssembler::repatchThunk(module.code(), callThunk.offset, calleeOffset);
+}
+
 // Replace all the nops in all the epilogues of asm.js functions with jumps
 // to the profiling epilogues.
 void
 wasm::EnableProfilingEpilogue(const Module& module, const CodeRange& codeRange, bool enabled)
 {
     if (!codeRange.isFunction())
         return;
 
--- a/js/src/asmjs/WasmFrameIterator.h
+++ b/js/src/asmjs/WasmFrameIterator.h
@@ -28,16 +28,17 @@ namespace js {
 class WasmActivation;
 namespace jit { class MacroAssembler; class Label; }
 
 namespace wasm {
 
 class CallSite;
 class CodeRange;
 class Module;
+struct CallThunk;
 struct FuncOffsets;
 struct ProfilingOffsets;
 
 // Iterates over the frames of a single WasmActivation, called synchronously
 // from C++ in the thread of the asm.js. The one exception is that this iterator
 // may be called from the interrupt callback which may be called asynchronously
 // from asm.js code; in this case, the backtrace may not be correct.
 class FrameIterator
@@ -108,14 +109,17 @@ void
 GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);
 
 // Runtime patching to enable/disable profiling
 
 void
 EnableProfilingPrologue(const Module& module, const CallSite& callSite, bool enabled);
 
 void
+EnableProfilingThunk(const Module& module, const CallThunk& callThunk, bool enabled);
+
+void
 EnableProfilingEpilogue(const Module& module, const CodeRange& codeRange, bool enabled);
 
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_frame_iterator_h
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -13,39 +13,45 @@
  * 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.
  */
 
 #include "asmjs/WasmGenerator.h"
 
+#include "mozilla/EnumeratedRange.h"
+
 #include "asmjs/WasmStubs.h"
 
 #include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 using namespace js::wasm;
 
+using mozilla::MakeEnumeratedRange;
+
 // ****************************************************************************
 // ModuleGenerator
 
 static const unsigned GENERATOR_LIFO_DEFAULT_CHUNK_SIZE = 4 * 1024;
 static const unsigned COMPILATION_LIFO_DEFAULT_CHUNK_SIZE = 64 * 1024;
 
 ModuleGenerator::ModuleGenerator(ExclusiveContext* cx)
   : cx_(cx),
     jcx_(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread())),
     slowFuncs_(cx),
     numSigs_(0),
     lifo_(GENERATOR_LIFO_DEFAULT_CHUNK_SIZE),
     alloc_(&lifo_),
     masm_(MacroAssembler::AsmJSToken(), alloc_),
     funcIndexToExport_(cx),
+    lastPatchedCallsite_(0),
+    startOfUnpatchedBranches_(0),
     parallel_(false),
     outstanding_(0),
     tasks_(cx),
     freeTasks_(cx),
     activeFunc_(nullptr),
     finishedFuncs_(false)
 {
     MOZ_ASSERT(IsCompilingAsmJS());
@@ -168,67 +174,282 @@ ModuleGenerator::finishOutstandingTask()
 
             HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
         }
     }
 
     return finishTask(task);
 }
 
-static const uint32_t BadEntry = UINT32_MAX;
+static const uint32_t BadCodeRange = UINT32_MAX;
 
 bool
 ModuleGenerator::funcIsDefined(uint32_t funcIndex) const
 {
-    return funcIndex < funcEntryOffsets_.length() &&
-           funcEntryOffsets_[funcIndex] != BadEntry;
+    return funcIndex < funcIndexToCodeRange_.length() &&
+           funcIndexToCodeRange_[funcIndex] != BadCodeRange;
+}
+
+uint32_t
+ModuleGenerator::funcEntry(uint32_t funcIndex) const
+{
+    MOZ_ASSERT(funcIsDefined(funcIndex));
+    return module_->codeRanges[funcIndexToCodeRange_[funcIndex]].funcNonProfilingEntry();
+}
+
+static uint32_t
+JumpRange()
+{
+    return Min(JitOptions.jumpThreshold, JumpImmediateRange);
+}
+
+typedef HashMap<uint32_t, uint32_t> OffsetMap;
+
+bool
+ModuleGenerator::convertOutOfRangeBranchesToThunks()
+{
+    masm_.haltingAlign(CodeAlignment);
+
+    // Create thunks for callsites that have gone out of range. Use a map to
+    // create one thunk for each callee since there is often high reuse.
+
+    OffsetMap alreadyThunked(cx_);
+    if (!alreadyThunked.init())
+        return false;
+
+    for (; lastPatchedCallsite_ < masm_.callSites().length(); lastPatchedCallsite_++) {
+        const CallSiteAndTarget& cs = masm_.callSites()[lastPatchedCallsite_];
+        if (!cs.isInternal())
+            continue;
+
+        uint32_t callerOffset = cs.returnAddressOffset();
+        MOZ_RELEASE_ASSERT(callerOffset < INT32_MAX);
+
+        if (funcIsDefined(cs.targetIndex())) {
+            uint32_t calleeOffset = funcEntry(cs.targetIndex());
+            MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX);
+
+            if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) {
+                masm_.patchCall(callerOffset, calleeOffset);
+                continue;
+            }
+        }
+
+        OffsetMap::AddPtr p = alreadyThunked.lookupForAdd(cs.targetIndex());
+        if (!p) {
+            Offsets offsets;
+            offsets.begin = masm_.currentOffset();
+            uint32_t thunkOffset = masm_.thunkWithPatch().offset();
+            if (masm_.oom())
+                return false;
+            offsets.end = masm_.currentOffset();
+
+            if (!module_->codeRanges.emplaceBack(CodeRange::CallThunk, offsets))
+                return false;
+            if (!module_->callThunks.emplaceBack(thunkOffset, cs.targetIndex()))
+                return false;
+            if (!alreadyThunked.add(p, cs.targetIndex(), offsets.begin))
+                return false;
+        }
+
+        masm_.patchCall(callerOffset, p->value());
+    }
+
+    // Create thunks for jumps to stubs. Stubs are always generated at the end
+    // so unconditionally thunk all existing jump sites.
+
+    for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) {
+        if (masm_.jumpSites()[target].empty())
+            continue;
+
+        for (uint32_t jumpSite : masm_.jumpSites()[target]) {
+            RepatchLabel label;
+            label.use(jumpSite);
+            masm_.bind(&label);
+        }
+
+        Offsets offsets;
+        offsets.begin = masm_.currentOffset();
+        uint32_t thunkOffset = masm_.thunkWithPatch().offset();
+        if (masm_.oom())
+            return false;
+        offsets.end = masm_.currentOffset();
+
+        if (!module_->codeRanges.emplaceBack(CodeRange::Inline, offsets))
+            return false;
+        if (!jumpThunks_[target].append(thunkOffset))
+            return false;
+    }
+
+    // Unlike callsites, which need to be persisted in the Module, we can simply
+    // flush jump sites after each patching pass.
+    masm_.clearJumpSites();
+
+    return true;
 }
 
 bool
 ModuleGenerator::finishTask(IonCompileTask* task)
 {
     const FuncBytecode& func = task->func();
     FuncCompileResults& results = task->results();
 
+    // Before merging in the new function's code, if jumps/calls in a previous
+    // function's body might go out of range, patch these to thunks which have
+    // full range.
+    if ((masm_.size() - startOfUnpatchedBranches_) + results.masm().size() > JumpRange()) {
+        startOfUnpatchedBranches_ = masm_.size();
+        if (!convertOutOfRangeBranchesToThunks())
+            return false;
+    }
+
     // Offset the recorded FuncOffsets by the offset of the function in the
     // whole module's code segment.
     uint32_t offsetInWhole = masm_.size();
     results.offsets().offsetBy(offsetInWhole);
 
-    // Record the non-profiling entry for whole-module linking later.
-    // Cannot simply append because funcIndex order is nonlinear.
-    if (func.index() >= funcEntryOffsets_.length()) {
-        if (!funcEntryOffsets_.appendN(BadEntry, func.index() - funcEntryOffsets_.length() + 1))
+    // Add the CodeRange for this function.
+    uint32_t funcCodeRangeIndex = module_->codeRanges.length();
+    if (!module_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets()))
+        return false;
+
+    // Maintain a mapping from function index to CodeRange index.
+    if (func.index() >= funcIndexToCodeRange_.length()) {
+        uint32_t n = func.index() - funcIndexToCodeRange_.length() + 1;
+        if (!funcIndexToCodeRange_.appendN(BadCodeRange, n))
             return false;
     }
     MOZ_ASSERT(!funcIsDefined(func.index()));
-    funcEntryOffsets_[func.index()] = results.offsets().nonProfilingEntry;
+    funcIndexToCodeRange_[func.index()] = funcCodeRangeIndex;
 
     // Merge the compiled results into the whole-module masm.
     DebugOnly<size_t> sizeBefore = masm_.size();
     if (!masm_.asmMergeWith(results.masm()))
         return false;
     MOZ_ASSERT(masm_.size() == offsetInWhole + results.masm().size());
 
-    // Add the CodeRange for this function.
-    if (!module_->codeRanges.emplaceBack(func.index(), func.lineOrBytecode(), results.offsets()))
-        return false;
-
     // Keep a record of slow functions for printing in the final console message.
     unsigned totalTime = func.generateTime() + results.compileTime();
     if (totalTime >= SlowFunction::msThreshold) {
         if (!slowFuncs_.emplaceBack(func.index(), totalTime, func.lineOrBytecode()))
             return false;
     }
 
     freeTasks_.infallibleAppend(task);
     return true;
 }
 
 bool
+ModuleGenerator::finishCodegen()
+{
+    uint32_t offsetInWhole = masm_.size();
+
+    // Generate stubs in a separate MacroAssembler since, otherwise, for modules
+    // larger than the JumpImmediateRange, even local uses of Label will fail
+    // due to the large absolute offsets temporarily stored by Label::bind().
+
+    Vector<Offsets> entries(cx_);
+    Vector<ProfilingOffsets> interpExits(cx_);
+    Vector<ProfilingOffsets> jitExits(cx_);
+    EnumeratedArray<JumpTarget, JumpTarget::Limit, Offsets> jumpTargets;
+    Offsets interruptExit;
+
+    {
+        TempAllocator alloc(&lifo_);
+        MacroAssembler masm(MacroAssembler::AsmJSToken(), alloc);
+
+        if (!entries.resize(numExports()))
+            return false;
+        for (uint32_t i = 0; i < numExports(); i++) {
+            uint32_t target = exportMap_->exportFuncIndices[i];
+            const Sig& sig = module_->exports[i].sig();
+            entries[i] = GenerateEntry(masm, target, sig, usesHeap());
+        }
+
+        if (!interpExits.resize(numImports()))
+            return false;
+        if (!jitExits.resize(numImports()))
+            return false;
+        for (uint32_t i = 0; i < numImports(); i++) {
+            interpExits[i] = GenerateInterpExit(masm, module_->imports[i], i);
+            jitExits[i] = GenerateJitExit(masm, module_->imports[i], usesHeap());
+        }
+
+        for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit))
+            jumpTargets[target] = GenerateJumpTarget(masm, target);
+
+        interruptExit = GenerateInterruptStub(masm);
+
+        if (masm.oom() || !masm_.asmMergeWith(masm))
+            return false;
+    }
+
+    // Adjust each of the resulting Offsets (to account for being merged into
+    // masm_) and then create code ranges for all the stubs.
+
+    for (uint32_t i = 0; i < numExports(); i++) {
+        entries[i].offsetBy(offsetInWhole);
+        module_->exports[i].initStubOffset(entries[i].begin);
+        if (!module_->codeRanges.emplaceBack(CodeRange::Entry, entries[i]))
+            return false;
+    }
+
+    for (uint32_t i = 0; i < numImports(); i++) {
+        interpExits[i].offsetBy(offsetInWhole);
+        module_->imports[i].initInterpExitOffset(interpExits[i].begin);
+        if (!module_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExits[i]))
+            return false;
+
+        jitExits[i].offsetBy(offsetInWhole);
+        module_->imports[i].initJitExitOffset(jitExits[i].begin);
+        if (!module_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExits[i]))
+            return false;
+    }
+
+    for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) {
+        jumpTargets[target].offsetBy(offsetInWhole);
+        if (!module_->codeRanges.emplaceBack(CodeRange::Inline, jumpTargets[target]))
+            return false;
+    }
+
+    interruptExit.offsetBy(offsetInWhole);
+    if (!module_->codeRanges.emplaceBack(CodeRange::Inline, interruptExit))
+        return false;
+
+    // The signal handler redirects PC to the out-of-bounds and interrupt stubs.
+
+    link_->pod.outOfBoundsOffset = jumpTargets[JumpTarget::OutOfBounds].begin;
+    link_->pod.interruptOffset = interruptExit.begin;
+
+    // Only call convertOutOfRangeBranchesToThunks after all other codegen that may
+    // emit new jumps to JumpTargets has finished.
+
+    if (!convertOutOfRangeBranchesToThunks())
+        return false;
+
+    // Now that all thunks have been generated, patch all the thunks.
+
+    for (CallThunk& callThunk : module_->callThunks) {
+        uint32_t funcIndex = callThunk.u.funcIndex;
+        callThunk.u.codeRangeIndex = funcIndexToCodeRange_[funcIndex];
+        masm_.patchThunk(callThunk.offset, funcEntry(funcIndex));
+    }
+
+    for (JumpTarget target : MakeEnumeratedRange(JumpTarget::Limit)) {
+        for (uint32_t thunkOffset : jumpThunks_[target])
+            masm_.patchThunk(thunkOffset, jumpTargets[target].begin);
+    }
+
+    // Code-generation is complete!
+
+    masm_.finish();
+    return !masm_.oom();
+}
+
+bool
 ModuleGenerator::addImport(const Sig& sig, uint32_t globalDataOffset)
 {
     Sig copy;
     if (!copy.clone(sig))
         return false;
 
     return module_->imports.emplaceBack(Move(copy), globalDataOffset);
 }
@@ -330,21 +551,22 @@ ModuleGenerator::funcSig(uint32_t funcIn
 {
     MOZ_ASSERT(shared_->funcSigs[funcIndex]);
     return *shared_->funcSigs[funcIndex];
 }
 
 bool
 ModuleGenerator::initImport(uint32_t importIndex, uint32_t sigIndex)
 {
+    MOZ_ASSERT(isAsmJS());
+
     uint32_t globalDataOffset;
     if (!allocateGlobalBytes(Module::SizeOfImportExit, sizeof(void*), &globalDataOffset))
         return false;
 
-    MOZ_ASSERT(isAsmJS());
     MOZ_ASSERT(importIndex == module_->imports.length());
     if (!addImport(sig(sigIndex), globalDataOffset))
         return false;
 
     ModuleImportGeneratorData& import = shared_->imports[importIndex];
     MOZ_ASSERT(!import.sig);
     import.sig = &shared_->sigs[sigIndex];
     import.globalDataOffset = globalDataOffset;
@@ -360,26 +582,16 @@ ModuleGenerator::numImports() const
 const ModuleImportGeneratorData&
 ModuleGenerator::import(uint32_t index) const
 {
     MOZ_ASSERT(shared_->imports[index].sig);
     return shared_->imports[index];
 }
 
 bool
-ModuleGenerator::defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit)
-{
-    Import& import = module_->imports[index];
-    import.initInterpExitOffset(interpExit.begin);
-    import.initJitExitOffset(jitExit.begin);
-    return module_->codeRanges.emplaceBack(CodeRange::ImportInterpExit, interpExit) &&
-           module_->codeRanges.emplaceBack(CodeRange::ImportJitExit, jitExit);
-}
-
-bool
 ModuleGenerator::declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32_t* exportIndex)
 {
     if (!exportMap_->fieldNames.append(Move(fieldName)))
         return false;
 
     FuncIndexMap::AddPtr p = funcIndexToExport_.lookupForAdd(funcIndex);
     if (p) {
         if (exportIndex)
@@ -399,49 +611,22 @@ ModuleGenerator::declareExport(UniqueCha
 
     return module_->exports.append(Move(copy)) &&
            funcIndexToExport_.add(p, funcIndex, newExportIndex) &&
            exportMap_->fieldsToExports.append(newExportIndex) &&
            exportMap_->exportFuncIndices.append(funcIndex);
 }
 
 uint32_t
-ModuleGenerator::exportFuncIndex(uint32_t index) const
-{
-    return exportMap_->exportFuncIndices[index];
-}
-
-uint32_t
-ModuleGenerator::exportEntryOffset(uint32_t index) const
-{
-    uint32_t funcIndex = exportMap_->exportFuncIndices[index];
-    MOZ_ASSERT(funcIsDefined(funcIndex));
-    return funcEntryOffsets_[funcIndex];
-}
-
-const Sig&
-ModuleGenerator::exportSig(uint32_t index) const
-{
-    return module_->exports[index].sig();
-}
-
-uint32_t
 ModuleGenerator::numExports() const
 {
     return module_->exports.length();
 }
 
 bool
-ModuleGenerator::defineExport(uint32_t index, Offsets offsets)
-{
-    module_->exports[index].initStubOffset(offsets.begin);
-    return module_->codeRanges.emplaceBack(CodeRange::Entry, offsets);
-}
-
-bool
 ModuleGenerator::addMemoryExport(UniqueChars fieldName)
 {
     return exportMap_->fieldNames.append(Move(fieldName)) &&
            exportMap_->fieldsToExports.append(ExportMap::MemoryExport);
 }
 
 bool
 ModuleGenerator::startFuncDefs()
@@ -556,34 +741,19 @@ ModuleGenerator::finishFuncDefs()
     MOZ_ASSERT(!activeFunc_);
     MOZ_ASSERT(!finishedFuncs_);
 
     while (outstanding_ > 0) {
         if (!finishOutstandingTask())
             return false;
     }
 
-    for (uint32_t funcIndex = 0; funcIndex < funcEntryOffsets_.length(); funcIndex++)
+    for (uint32_t funcIndex = 0; funcIndex < funcIndexToCodeRange_.length(); funcIndex++)
         MOZ_ASSERT(funcIsDefined(funcIndex));
 
-    // During codegen, all wasm->wasm (internal) calls use AsmJSInternalCallee
-    // as the call target, which contains the function-index of the target.
-    // These get recorded in a CallSiteAndTargetVector in the MacroAssembler
-    // so that we can patch them now that all the function entry offsets are
-    // known.
-
-    for (CallSiteAndTarget& cs : masm_.callSites()) {
-        if (!cs.isInternal())
-            continue;
-        MOZ_ASSERT(cs.kind() == CallSiteDesc::Relative);
-        uint32_t callerOffset = cs.returnAddressOffset();
-        uint32_t calleeOffset = funcEntryOffsets_[cs.targetIndex()];
-        masm_.patchCall(callerOffset, calleeOffset);
-    }
-
     module_->functionBytes = masm_.size();
     finishedFuncs_ = true;
     return true;
 }
 
 bool
 ModuleGenerator::declareFuncPtrTable(uint32_t numElems, uint32_t* index)
 {
@@ -623,59 +793,34 @@ ModuleGenerator::defineFuncPtrTable(uint
     MOZ_ASSERT(finishedFuncs_);
 
     StaticLinkData::FuncPtrTable& table = link_->funcPtrTables[index];
     MOZ_ASSERT(table.elemOffsets.length() == elemFuncIndices.length());
 
     for (size_t i = 0; i < elemFuncIndices.length(); i++) {
         uint32_t funcIndex = elemFuncIndices[i];
         MOZ_ASSERT(funcIsDefined(funcIndex));
-        table.elemOffsets[i] = funcEntryOffsets_[funcIndex];
+        table.elemOffsets[i] = funcEntry(funcIndex);
     }
 }
 
 bool
-ModuleGenerator::defineInlineStub(Offsets offsets)
-{
-    MOZ_ASSERT(finishedFuncs_);
-    return module_->codeRanges.emplaceBack(CodeRange::Inline, offsets);
-}
-
-void
-ModuleGenerator::defineInterruptExit(uint32_t offset)
-{
-    MOZ_ASSERT(finishedFuncs_);
-    link_->pod.interruptOffset = offset;
-}
-
-void
-ModuleGenerator::defineOutOfBoundsExit(uint32_t offset)
-{
-    MOZ_ASSERT(finishedFuncs_);
-    link_->pod.outOfBoundsOffset = offset;
-}
-
-bool
 ModuleGenerator::finish(CacheableCharsVector&& prettyFuncNames,
                         UniqueModuleData* module,
                         UniqueStaticLinkData* linkData,
                         UniqueExportMap* exportMap,
                         SlowFunctionVector* slowFuncs)
 {
     MOZ_ASSERT(!activeFunc_);
     MOZ_ASSERT(finishedFuncs_);
 
-    module_->prettyFuncNames = Move(prettyFuncNames);
-
-    if (!GenerateStubs(*this))
+    if (!finishCodegen())
         return false;
 
-    masm_.finish();
-    if (masm_.oom())
-        return false;
+    module_->prettyFuncNames = Move(prettyFuncNames);
 
     // Start global data on a new page so JIT code may be given independent
     // protection flags. Note assumption that global data starts right after
     // code below.
     module_->codeBytes = AlignBytes(masm_.bytesNeeded(), gc::SystemPageSize());
 
     // Inflate the global bytes up to page size so that the total bytes are a
     // page size (as required by the allocator functions).
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -137,33 +137,39 @@ class MOZ_STACK_CLASS ModuleGenerator
     SlowFunctionVector              slowFuncs_;
 
     // Data scoped to the ModuleGenerator's lifetime
     UniqueModuleGeneratorData       shared_;
     uint32_t                        numSigs_;
     LifoAlloc                       lifo_;
     jit::TempAllocator              alloc_;
     jit::MacroAssembler             masm_;
-    Uint32Vector                    funcEntryOffsets_;
+    Uint32Vector                    funcIndexToCodeRange_;
     FuncIndexMap                    funcIndexToExport_;
+    uint32_t                        lastPatchedCallsite_;
+    uint32_t                        startOfUnpatchedBranches_;
+    JumpSiteArray                   jumpThunks_;
 
     // Parallel compilation
     bool                            parallel_;
     uint32_t                        outstanding_;
     UniqueModuleGeneratorThreadView threadView_;
     Vector<IonCompileTask>          tasks_;
     Vector<IonCompileTask*>         freeTasks_;
 
     // Assertions
     DebugOnly<FunctionGenerator*>   activeFunc_;
     DebugOnly<bool>                 finishedFuncs_;
 
     bool finishOutstandingTask();
     bool funcIsDefined(uint32_t funcIndex) const;
+    uint32_t funcEntry(uint32_t funcIndex) const;
+    bool convertOutOfRangeBranchesToThunks();
     bool finishTask(IonCompileTask* task);
+    bool finishCodegen();
     bool addImport(const Sig& sig, uint32_t globalDataOffset);
     bool startedFuncDefs() const { return !!threadView_; }
     bool allocateGlobalBytes(uint32_t bytes, uint32_t align, uint32_t* globalDataOffset);
 
   public:
     explicit ModuleGenerator(ExclusiveContext* cx);
     ~ModuleGenerator();
 
@@ -190,43 +196,33 @@ class MOZ_STACK_CLASS ModuleGenerator
     bool initFuncSig(uint32_t funcIndex, uint32_t sigIndex);
     uint32_t numFuncSigs() const { return module_->numFuncs; }
     const DeclaredSig& funcSig(uint32_t funcIndex) const;
 
     // Imports:
     bool initImport(uint32_t importIndex, uint32_t sigIndex);
     uint32_t numImports() const;
     const ModuleImportGeneratorData& import(uint32_t index) const;
-    bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
 
     // Exports:
     bool declareExport(UniqueChars fieldName, uint32_t funcIndex, uint32_t* exportIndex = nullptr);
     uint32_t numExports() const;
-    uint32_t exportFuncIndex(uint32_t index) const;
-    uint32_t exportEntryOffset(uint32_t index) const;
-    const Sig& exportSig(uint32_t index) const;
-    bool defineExport(uint32_t index, Offsets offsets);
     bool addMemoryExport(UniqueChars fieldName);
 
     // Function definitions:
     bool startFuncDefs();
     bool startFuncDef(uint32_t lineOrBytecode, FunctionGenerator* fg);
     bool finishFuncDef(uint32_t funcIndex, unsigned generateTime, FunctionGenerator* fg);
     bool finishFuncDefs();
 
     // Function-pointer tables:
     bool declareFuncPtrTable(uint32_t numElems, uint32_t* index);
     uint32_t funcPtrTableGlobalDataOffset(uint32_t index) const;
     void defineFuncPtrTable(uint32_t index, const Vector<uint32_t>& elemFuncIndices);
 
-    // Stubs:
-    bool defineInlineStub(Offsets offsets);
-    void defineInterruptExit(uint32_t offset);
-    void defineOutOfBoundsExit(uint32_t offset);
-
     // Return a ModuleData object which may be used to construct a Module, the
     // StaticLinkData required to call Module::staticallyLink, and the list of
     // functions that took a long time to compile.
     bool finish(CacheableCharsVector&& prettyFuncNames,
                 UniqueModuleData* module,
                 UniqueStaticLinkData* staticLinkData,
                 UniqueExportMap* exportMap,
                 SlowFunctionVector* slowFuncs);
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -355,17 +355,17 @@ CodeRange::CodeRange(Kind kind, Offsets 
     begin_(offsets.begin),
     profilingReturn_(0),
     end_(offsets.end)
 {
     PodZero(&u);  // zero padding for Valgrind
     u.kind_ = kind;
 
     MOZ_ASSERT(begin_ <= end_);
-    MOZ_ASSERT(u.kind_ == Entry || u.kind_ == Inline);
+    MOZ_ASSERT(u.kind_ == Entry || u.kind_ == Inline || u.kind_ == CallThunk);
 }
 
 CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets)
   : funcIndex_(0),
     funcLineOrBytecode_(0),
     begin_(offsets.begin),
     profilingReturn_(offsets.profilingReturn),
     end_(offsets.end)
@@ -503,30 +503,32 @@ ModuleData::serializedSize() const
 {
     return sizeof(pod()) +
            codeBytes +
            SerializedVectorSize(imports) +
            SerializedVectorSize(exports) +
            SerializedPodVectorSize(heapAccesses) +
            SerializedPodVectorSize(codeRanges) +
            SerializedPodVectorSize(callSites) +
+           SerializedPodVectorSize(callThunks) +
            SerializedVectorSize(prettyFuncNames) +
            filename.serializedSize();
 }
 
 uint8_t*
 ModuleData::serialize(uint8_t* cursor) const
 {
     cursor = WriteBytes(cursor, &pod(), sizeof(pod()));
     cursor = WriteBytes(cursor, code.get(), codeBytes);
     cursor = SerializeVector(cursor, imports);
     cursor = SerializeVector(cursor, exports);
     cursor = SerializePodVector(cursor, heapAccesses);
     cursor = SerializePodVector(cursor, codeRanges);
     cursor = SerializePodVector(cursor, callSites);
+    cursor = SerializePodVector(cursor, callThunks);
     cursor = SerializeVector(cursor, prettyFuncNames);
     cursor = filename.serialize(cursor);
     return cursor;
 }
 
 /* static */ const uint8_t*
 ModuleData::deserialize(ExclusiveContext* cx, const uint8_t* cursor)
 {
@@ -537,16 +539,17 @@ ModuleData::deserialize(ExclusiveContext
         return nullptr;
     cursor = ReadBytes(cursor, code.get(), codeBytes);
 
     (cursor = DeserializeVector(cx, cursor, &imports)) &&
     (cursor = DeserializeVector(cx, cursor, &exports)) &&
     (cursor = DeserializePodVector(cx, cursor, &heapAccesses)) &&
     (cursor = DeserializePodVector(cx, cursor, &codeRanges)) &&
     (cursor = DeserializePodVector(cx, cursor, &callSites)) &&
+    (cursor = DeserializePodVector(cx, cursor, &callThunks)) &&
     (cursor = DeserializeVector(cx, cursor, &prettyFuncNames)) &&
     (cursor = filename.deserialize(cx, cursor));
     return cursor;
 }
 
 bool
 ModuleData::clone(JSContext* cx, ModuleData* out) const
 {
@@ -557,29 +560,31 @@ ModuleData::clone(JSContext* cx, ModuleD
         return false;
     memcpy(out->code.get(), code.get(), codeBytes);
 
     return CloneVector(cx, imports, &out->imports) &&
            CloneVector(cx, exports, &out->exports) &&
            ClonePodVector(cx, heapAccesses, &out->heapAccesses) &&
            ClonePodVector(cx, codeRanges, &out->codeRanges) &&
            ClonePodVector(cx, callSites, &out->callSites) &&
+           ClonePodVector(cx, callThunks, &out->callThunks) &&
            CloneVector(cx, prettyFuncNames, &out->prettyFuncNames) &&
            filename.clone(cx, &out->filename);
 }
 
 size_t
 ModuleData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 {
     // Module::addSizeOfMisc takes care of code and global memory.
     return SizeOfVectorExcludingThis(imports, mallocSizeOf) +
            SizeOfVectorExcludingThis(exports, mallocSizeOf) +
            heapAccesses.sizeOfExcludingThis(mallocSizeOf) +
            codeRanges.sizeOfExcludingThis(mallocSizeOf) +
            callSites.sizeOfExcludingThis(mallocSizeOf) +
+           callThunks.sizeOfExcludingThis(mallocSizeOf) +
            prettyFuncNames.sizeOfExcludingThis(mallocSizeOf) +
            filename.sizeOfExcludingThis(mallocSizeOf);
 }
 
 uint8_t*
 Module::rawHeapPtr() const
 {
     return const_cast<Module*>(this)->rawHeapPtr();
@@ -787,16 +792,19 @@ Module::setProfilingEnabled(JSContext* c
     {
         AutoWritableJitCode awjc(cx->runtime(), code(), codeBytes());
         AutoFlushICache afc("Module::setProfilingEnabled");
         AutoFlushICache::setRange(uintptr_t(code()), codeBytes());
 
         for (const CallSite& callSite : module_->callSites)
             EnableProfilingPrologue(*this, callSite, enabled);
 
+        for (const CallThunk& callThunk : module_->callThunks)
+            EnableProfilingThunk(*this, callThunk, enabled);
+
         for (const CodeRange& codeRange : module_->codeRanges)
             EnableProfilingEpilogue(*this, codeRange, enabled);
     }
 
     // Update the function-pointer tables to point to profiling prologues.
     for (FuncPtrTable& funcPtrTable : funcPtrTables_) {
         auto array = reinterpret_cast<void**>(globalData() + funcPtrTable.globalDataOffset);
         for (size_t i = 0; i < funcPtrTable.numElems; i++) {
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -62,19 +62,17 @@ struct StaticLinkData
 
         InternalLink() = default;
         explicit InternalLink(Kind kind);
         bool isRawPointerPatch();
     };
     typedef Vector<InternalLink, 0, SystemAllocPolicy> InternalLinkVector;
 
     typedef Vector<uint32_t, 0, SystemAllocPolicy> OffsetVector;
-    struct SymbolicLinkArray : mozilla::EnumeratedArray<SymbolicAddress,
-                                                        SymbolicAddress::Limit,
-                                                        OffsetVector> {
+    struct SymbolicLinkArray : EnumeratedArray<SymbolicAddress, SymbolicAddress::Limit, OffsetVector> {
         WASM_DECLARE_SERIALIZABLE(SymbolicLinkArray)
     };
 
     struct FuncPtrTable {
         uint32_t globalDataOffset;
         OffsetVector elemOffsets;
         explicit FuncPtrTable(uint32_t globalDataOffset) : globalDataOffset(globalDataOffset) {}
         FuncPtrTable() = default;
@@ -208,17 +206,17 @@ class CodeRange
             uint8_t profilingEpilogueToProfilingReturn_;
         } func;
         uint8_t kind_;
     } u;
 
     void assertValid();
 
   public:
-    enum Kind { Function, Entry, ImportJitExit, ImportInterpExit, Inline };
+    enum Kind { Function, Entry, ImportJitExit, ImportInterpExit, Inline, CallThunk };
 
     CodeRange() = default;
     CodeRange(Kind kind, Offsets offsets);
     CodeRange(Kind kind, ProfilingOffsets offsets);
     CodeRange(uint32_t funcIndex, uint32_t lineOrBytecode, FuncOffsets offsets);
 
     // All CodeRanges have a begin and end.
 
@@ -232,26 +230,29 @@ class CodeRange
     // Other fields are only available for certain CodeRange::Kinds.
 
     Kind kind() const { return Kind(u.kind_); }
 
     // Every CodeRange except entry and inline stubs has a profiling return
     // which is used for asynchronous profiling to determine the frame pointer.
 
     uint32_t profilingReturn() const {
-        MOZ_ASSERT(kind() != Entry && kind() != Inline);
+        MOZ_ASSERT(isFunction() || isImportExit());
         return profilingReturn_;
     }
 
     // Functions have offsets which allow patching to selectively execute
     // profiling prologues/epilogues.
 
     bool isFunction() const {
         return kind() == Function;
     }
+    bool isImportExit() const {
+        return kind() == ImportJitExit || kind() == ImportInterpExit;
+    }
     uint32_t funcProfilingEntry() const {
         MOZ_ASSERT(isFunction());
         return begin();
     }
     uint32_t funcNonProfilingEntry() const {
         MOZ_ASSERT(isFunction());
         return begin_ + u.func.beginToEntry_;
     }
@@ -283,16 +284,35 @@ class CodeRange
         bool operator<(const CodeRange& rhs) const {
             return offset < rhs.begin();
         }
     };
 };
 
 typedef Vector<CodeRange, 0, SystemAllocPolicy> CodeRangeVector;
 
+// A CallThunk describes the offset and target of thunks so that they may be
+// patched at runtime when profiling is toggled. Thunks are emitted to connect
+// callsites that are too far away from callees to fit in a single call
+// instruction's relative offset.
+
+struct CallThunk
+{
+    uint32_t offset;
+    union {
+        uint32_t funcIndex;
+        uint32_t codeRangeIndex;
+    } u;
+
+    CallThunk(uint32_t offset, uint32_t funcIndex) : offset(offset) { u.funcIndex = funcIndex; }
+    CallThunk() = default;
+};
+
+typedef Vector<CallThunk, 0, SystemAllocPolicy> CallThunkVector;
+
 // CacheableChars is used to cacheably store UniqueChars.
 
 struct CacheableChars : UniqueChars
 {
     CacheableChars() = default;
     explicit CacheableChars(char* ptr) : UniqueChars(ptr) {}
     MOZ_IMPLICIT CacheableChars(UniqueChars&& rhs) : UniqueChars(Move(rhs)) {}
     CacheableChars(CacheableChars&& rhs) : UniqueChars(Move(rhs)) {}
@@ -384,16 +404,17 @@ struct ModuleData : ModuleCacheablePod
     const ModuleCacheablePod& pod() const { return *this; }
 
     UniqueCodePtr         code;
     ImportVector          imports;
     ExportVector          exports;
     HeapAccessVector      heapAccesses;
     CodeRangeVector       codeRanges;
     CallSiteVector        callSites;
+    CallThunkVector       callThunks;
     CacheableCharsVector  prettyFuncNames;
     CacheableChars        filename;
     bool                  loadedFromCache;
 
     WASM_DECLARE_SERIALIZABLE(ModuleData);
 };
 
 typedef UniquePtr<ModuleData> UniqueModuleData;
@@ -491,16 +512,17 @@ class Module
     uint8_t* globalData() const { return code() + module_->codeBytes; }
     uint32_t globalBytes() const { return module_->globalBytes; }
     HeapUsage heapUsage() const { return module_->heapUsage; }
     bool usesHeap() const { return UsesHeap(module_->heapUsage); }
     bool hasSharedHeap() const { return module_->heapUsage == HeapUsage::Shared; }
     CompileArgs compileArgs() const { return module_->compileArgs; }
     const ImportVector& imports() const { return module_->imports; }
     const ExportVector& exports() const { return module_->exports; }
+    const CodeRangeVector& codeRanges() const { return module_->codeRanges; }
     const char* filename() const { return module_->filename.get(); }
     bool loadedFromCache() const { return module_->loadedFromCache; }
     bool staticallyLinked() const { return staticallyLinked_; }
     bool dynamicallyLinked() const { return dynamicallyLinked_; }
 
     // Some wasm::Module's have the most-derived type AsmJSModule. The
     // AsmJSModule stores the extra metadata necessary to implement asm.js (JS)
     // semantics. The asAsmJS() member may be used as a checked downcast when
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -14,26 +14,24 @@
  * 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.
  */
 
 #include "asmjs/WasmStubs.h"
 
 #include "mozilla/ArrayUtils.h"
-#include "mozilla/EnumeratedRange.h"
 
 #include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 using namespace js::wasm;
 
 using mozilla::ArrayLength;
-using mozilla::MakeEnumeratedRange;
 
 static void
 AssertStackAlignment(MacroAssembler& masm, uint32_t alignment, uint32_t addBeforeAssert = 0)
 {
     MOZ_ASSERT((sizeof(AsmJSFrame) + masm.framePushed() + addBeforeAssert) % alignment == 0);
     masm.assertStackAlignment(alignment, addBeforeAssert);
 }
 
@@ -89,22 +87,19 @@ static const unsigned FramePushedAfterSa
                                            + NonVolatileRegs.fpus().getPushSizeInBytes();
 #endif
 static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void*);
 
 // Generate a stub that enters wasm from a C++ caller via the native ABI.
 // The signature of the entry point is Module::CodePtr. The exported wasm
 // function has an ABI derived from its specific signature, so this function
 // must map from the ABI of CodePtr to the export's signature's ABI.
-static bool
-GenerateEntry(ModuleGenerator& mg, unsigned exportIndex)
+Offsets
+wasm::GenerateEntry(MacroAssembler& masm, unsigned target, const Sig& sig, bool usesHeap)
 {
-    MacroAssembler& masm = mg.masm();
-    const Sig& sig = mg.exportSig(exportIndex);
-
     masm.haltingAlign(CodeAlignment);
 
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
     // Save the return address if it wasn't already saved by the call insn.
 #if defined(JS_CODEGEN_ARM)
     masm.push(lr);
@@ -126,17 +121,17 @@ GenerateEntry(ModuleGenerator& mg, unsig
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     masm.movePtr(IntArgReg1, GlobalReg);
     masm.addPtr(Imm32(AsmJSGlobalRegBias), GlobalReg);
 #endif
 
     // ARM, MIPS/MIPS64 and x64 have a globally-pinned HeapReg (x86 uses immediates in
     // effective addresses). Loading the heap register depends on the global
     // register already having been loaded.
-    if (mg.usesHeap())
+    if (usesHeap)
         masm.loadAsmJSHeapRegisterFromGlobalData();
 
     // Put the 'argv' argument into a non-argument/return register so that we
     // can use 'argv' while we fill in the arguments for the asm.js callee.
     // Also, save 'argv' on the stack so that we can recover it after the call.
     // Use a second non-argument/return register as temporary scratch.
     Register argv = ABIArgGenerator::NonArgReturnReg0;
     Register scratch = ABIArgGenerator::NonArgReturnReg1;
@@ -230,19 +225,17 @@ GenerateEntry(ModuleGenerator& mg, unsig
                 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected stack arg type");
             }
             break;
         }
     }
 
     // Call into the real function.
     masm.assertStackAlignment(AsmJSStackAlignment);
-    Label target;
-    target.bind(mg.exportEntryOffset(exportIndex));
-    masm.call(CallSiteDesc(CallSiteDesc::Relative), &target);
+    masm.call(CallSiteDesc(CallSiteDesc::Relative), AsmJSInternalCallee(target));
 
     // Recover the stack pointer value before dynamic alignment.
     masm.loadWasmActivation(scratch);
     masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
     masm.setFramePushed(FramePushedForEntrySP);
 
     // Recover the 'argv' pointer which was saved before aligning the stack.
     masm.Pop(argv);
@@ -278,21 +271,18 @@ GenerateEntry(ModuleGenerator& mg, unsig
 
     // Restore clobbered non-volatile registers of the caller.
     masm.PopRegsInMask(NonVolatileRegs);
     MOZ_ASSERT(masm.framePushed() == 0);
 
     masm.move32(Imm32(true), ReturnReg);
     masm.ret();
 
-    if (masm.oom())
-        return false;
-
     offsets.end = masm.currentOffset();
-    return mg.defineExport(exportIndex, offsets);
+    return offsets;
 }
 
 static void
 FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argOffset,
                   unsigned offsetToCallerStackArgs, Register scratch)
 {
     for (ABIArgValTypeIter i(args); !i.done(); i++) {
         Address dstAddr(masm.getStackPointer(), argOffset + i.index() * sizeof(Value));
@@ -328,21 +318,20 @@ FillArgumentArray(MacroAssembler& masm, 
             break;
         }
     }
 }
 
 // Generate a stub that is called via the internal ABI derived from the
 // signature of the import and calls into an appropriate InvokeImport C++
 // function, having boxed all the ABI arguments into a homogeneous Value array.
-static bool
-GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets* offsets)
+ProfilingOffsets
+wasm::GenerateInterpExit(MacroAssembler& masm, const Import& import, uint32_t importIndex)
 {
-    MacroAssembler& masm = mg.masm();
-    const Sig& sig = *mg.import(importIndex).sig;
+    const Sig& sig = import.sig();
 
     masm.setFramePushed(0);
 
     // Argument types for InvokeImport_*:
     static const MIRType typeArray[] = { MIRType_Pointer,   // ImportExit
                                          MIRType_Int32,     // argc
                                          MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes;
@@ -351,17 +340,18 @@ GenerateInterpExitStub(ModuleGenerator& 
     // At the point of the call, the stack layout shall be (sp grows to the left):
     //   | stack args | padding | Value argv[] | padding | retaddr | caller stack args |
     // The padding between stack args and argv ensures that argv is aligned. The
     // padding between argv and retaddr ensures that sp is aligned.
     unsigned argOffset = AlignBytes(StackArgBytes(invokeArgTypes), sizeof(double));
     unsigned argBytes = Max<size_t>(1, sig.args().length()) * sizeof(Value);
     unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, argOffset + argBytes);
 
-    GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, offsets);
+    ProfilingOffsets offsets;
+    GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = sizeof(AsmJSFrame) + masm.framePushed();
     Register scratch = ABIArgGenerator::NonArgReturnReg0;
     FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch);
 
     // Prepare the arguments for the call to InvokeImport_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
@@ -402,17 +392,16 @@ GenerateInterpExitStub(ModuleGenerator& 
       case ExprType::I32:
         masm.call(SymbolicAddress::InvokeImport_I32);
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
         masm.unboxInt32(argv, ReturnReg);
         break;
       case ExprType::I64:
         MOZ_CRASH("no int64 in asm.js");
       case ExprType::F32:
-        MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js");
         masm.call(SymbolicAddress::InvokeImport_F64);
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
         masm.loadDouble(argv, ReturnDoubleReg);
         masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg);
         break;
       case ExprType::F64:
         masm.call(SymbolicAddress::InvokeImport_F64);
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
@@ -421,70 +410,67 @@ GenerateInterpExitStub(ModuleGenerator& 
       case ExprType::I32x4:
       case ExprType::F32x4:
       case ExprType::B32x4:
         MOZ_CRASH("SIMD types shouldn't be returned from a FFI");
       case ExprType::Limit:
         MOZ_CRASH("Limit");
     }
 
-    GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, offsets);
+    GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, &offsets);
 
-    if (masm.oom())
-        return false;
-
-    offsets->end = masm.currentOffset();
-    return true;
+    offsets.end = masm.currentOffset();
+    return offsets;
 }
 
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
 static const unsigned MaybeSavedGlobalReg = sizeof(void*);
 #else
 static const unsigned MaybeSavedGlobalReg = 0;
 #endif
 
 // Generate a stub that is called via the internal ABI derived from the
 // signature of the import and calls into a compatible JIT function,
 // having boxed all the ABI arguments into the JIT stack frame layout.
-static bool
-GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets* offsets)
+ProfilingOffsets
+wasm::GenerateJitExit(MacroAssembler& masm, const Import& import, bool usesHeap)
 {
-    MacroAssembler& masm = mg.masm();
-    const Sig& sig = *mg.import(importIndex).sig;
+    const Sig& sig = import.sig();
 
     masm.setFramePushed(0);
 
     // JIT calls use the following stack layout (sp grows to the left):
     //   | retaddr | descriptor | callee | argc | this | arg1..N |
     // After the JIT frame, the global register (if present) is saved since the
     // JIT's ABI does not preserve non-volatile regs. Also, unlike most ABIs,
     // the JIT ABI requires that sp be JitStackAlignment-aligned *after* pushing
     // the return address.
     static_assert(AsmJSStackAlignment >= JitStackAlignment, "subsumes");
     unsigned sizeOfRetAddr = sizeof(void*);
     unsigned jitFrameBytes = 3 * sizeof(void*) + (1 + sig.args().length()) * sizeof(Value);
     unsigned totalJitFrameBytes = sizeOfRetAddr + jitFrameBytes + MaybeSavedGlobalReg;
     unsigned jitFramePushed = StackDecrementForCall(masm, JitStackAlignment, totalJitFrameBytes) -
                               sizeOfRetAddr;
 
-    GenerateExitPrologue(masm, jitFramePushed, ExitReason::ImportJit, offsets);
+    ProfilingOffsets offsets;
+    GenerateExitPrologue(masm, jitFramePushed, ExitReason::ImportJit, &offsets);
 
     // 1. Descriptor
     size_t argOffset = 0;
     uint32_t descriptor = MakeFrameDescriptor(jitFramePushed, JitFrame_Entry,
                                               JitFrameLayout::Size());
     masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(masm.getStackPointer(), argOffset));
     argOffset += sizeof(size_t);
 
     // 2. Callee
     Register callee = ABIArgGenerator::NonArgReturnReg0;   // live until call
     Register scratch = ABIArgGenerator::NonArgReturnReg1;  // repeatedly clobbered
 
     // 2.1. Get ExitDatum
-    unsigned globalDataOffset = mg.import(importIndex).globalDataOffset;
+    uint32_t globalDataOffset = import.exitGlobalDataOffset();
 #if defined(JS_CODEGEN_X64)
     masm.append(AsmJSGlobalAccess(masm.leaRipRelative(callee), globalDataOffset));
 #elif defined(JS_CODEGEN_X86)
     masm.append(AsmJSGlobalAccess(masm.movlWithPatch(Imm32(0), callee), globalDataOffset));
 #elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
       defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     masm.computeEffectiveAddress(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), callee);
 #endif
@@ -658,17 +644,16 @@ GenerateJitExitStub(ModuleGenerator& mg,
         break;
       case ExprType::I32:
         masm.convertValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert,
                                  /* -0 check */ false);
         break;
       case ExprType::I64:
         MOZ_CRASH("no int64 in asm.js");
       case ExprType::F32:
-        MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js");
         masm.convertValueToFloat(JSReturnOperand, ReturnFloat32Reg, &oolConvert);
         break;
       case ExprType::F64:
         masm.convertValueToDouble(JSReturnOperand, ReturnDoubleReg, &oolConvert);
         break;
       case ExprType::I32x4:
       case ExprType::F32x4:
       case ExprType::B32x4:
@@ -677,20 +662,20 @@ GenerateJitExitStub(ModuleGenerator& mg,
         MOZ_CRASH("Limit");
     }
 
     Label done;
     masm.bind(&done);
 
     // Ion code does not respect system callee-saved register conventions so
     // reload the heap register.
-    if (mg.usesHeap())
+    if (usesHeap)
         masm.loadAsmJSHeapRegisterFromGlobalData();
 
-    GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, offsets);
+    GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, &offsets);
 
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
         masm.setFramePushed(nativeFramePushed);
 
         // Coercion calls use the following stack layout (sp grows to the left):
         //   | args | padding | Value argv[1] | padding | exit AsmJSFrame |
         MIRTypeVector coerceArgTypes;
@@ -723,63 +708,43 @@ GenerateJitExitStub(ModuleGenerator& mg,
             masm.unboxInt32(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnReg);
             break;
           case ExprType::F64:
             masm.call(SymbolicAddress::CoerceInPlace_ToNumber);
             masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
             masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg);
             break;
           case ExprType::F32:
-            MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js");
             masm.call(SymbolicAddress::CoerceInPlace_ToNumber);
             masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
             masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg);
             masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg);
             break;
           default:
             MOZ_CRASH("Unsupported convert type");
         }
 
         masm.jump(&done);
         masm.setFramePushed(0);
     }
 
     MOZ_ASSERT(masm.framePushed() == 0);
 
-    if (masm.oom())
-        return false;
-
-    offsets->end = masm.currentOffset();
-    return true;
-}
-
-static void
-BindJumps(MacroAssembler& masm, JumpTarget target)
-{
-    for (uint32_t offset : masm.jumpSites()[target]) {
-        RepatchLabel label;
-        label.use(offset);
-        masm.bind(&label);
-    }
+    offsets.end = masm.currentOffset();
+    return offsets;
 }
 
 // Generate a stub that is called immediately after the prologue when there is a
 // stack overflow. This stub calls a C++ function to report the error and then
 // jumps to the throw stub to pop the activation.
-static bool
-GenerateStackOverflowStub(ModuleGenerator& mg)
+static Offsets
+GenerateStackOverflow(MacroAssembler& masm)
 {
-    MacroAssembler& masm = mg.masm();
     masm.haltingAlign(CodeAlignment);
 
-    if (masm.jumpSites()[JumpTarget::StackOverflow].empty())
-        return true;
-
-    BindJumps(masm, JumpTarget::StackOverflow);
-
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
     // If we reach here via the non-profiling prologue, WasmActivation::fp has
     // not been updated. To enable stack unwinding from C++, store to it now. If
     // we reached here via the profiling prologue, we'll just store the same
     // value again. Do not update AsmJSFrame::callerFP as it is not necessary in
     // the non-profiling case (there is no return path from this point) and, in
@@ -792,113 +757,132 @@ GenerateStackOverflowStub(ModuleGenerato
     if (uint32_t d = StackDecrementForCall(ABIStackAlignment, sizeof(AsmJSFrame), ShadowStackSpace))
         masm.subFromStackPtr(Imm32(d));
 
     // No need to restore the stack; the throw stub pops everything.
     masm.assertStackAlignment(ABIStackAlignment);
     masm.call(SymbolicAddress::ReportOverRecursed);
     masm.jump(JumpTarget::Throw);
 
-    if (masm.oom())
-        return false;
-
     offsets.end = masm.currentOffset();
-    return mg.defineInlineStub(offsets);
+    return offsets;
 }
 
 // Generate a stub that is jumped to from an out-of-bounds heap access when
 // there are throwing semantics. This stub calls a C++ function to report an
 // error and then jumps to the throw stub to pop the activation.
-static bool
-GenerateConversionErrorStub(ModuleGenerator& mg)
+static Offsets
+GenerateConversionError(MacroAssembler& masm)
 {
-    MacroAssembler& masm = mg.masm();
     masm.haltingAlign(CodeAlignment);
 
-    if (masm.jumpSites()[JumpTarget::ConversionError].empty())
-        return true;
-
-    BindJumps(masm, JumpTarget::ConversionError);
-
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
     // sp can be anything at this point, so ensure it is aligned when calling
     // into C++.  We unconditionally jump to throw so don't worry about restoring sp.
     masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
 
     // OnImpreciseConversion always throws.
     masm.assertStackAlignment(ABIStackAlignment);
     masm.call(SymbolicAddress::OnImpreciseConversion);
     masm.jump(JumpTarget::Throw);
 
-    if (masm.oom())
-        return false;
-
     offsets.end = masm.currentOffset();
-    return mg.defineInlineStub(offsets);
+    return offsets;
 }
 
 // Generate a stub that is jumped to from an out-of-bounds heap access when
 // there are throwing semantics. This stub calls a C++ function to report an
 // error and then jumps to the throw stub to pop the activation.
-static bool
-GenerateOutOfBoundsStub(ModuleGenerator& mg)
+static Offsets
+GenerateOutOfBounds(MacroAssembler& masm)
 {
-    MacroAssembler& masm = mg.masm();
     masm.haltingAlign(CodeAlignment);
 
-    // Generate the out-of-bounds stub unconditionally since it may always be
-    // used by the signal handler.
-    mg.defineOutOfBoundsExit(masm.currentOffset());
-
-    BindJumps(masm, JumpTarget::OutOfBounds);
-
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
     // sp can be anything at this point, so ensure it is aligned when calling
     // into C++.  We unconditionally jump to throw so don't worry about restoring sp.
     masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
 
     // OnOutOfBounds always throws.
     masm.assertStackAlignment(ABIStackAlignment);
     masm.call(SymbolicAddress::OnOutOfBounds);
     masm.jump(JumpTarget::Throw);
 
-    if (masm.oom())
-        return false;
+    offsets.end = masm.currentOffset();
+    return offsets;
+}
+
+// If an exception is thrown, simply pop all frames (since asm.js does not
+// contain try/catch). To do this:
+//  1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry.
+//  2. PopRegsInMask to restore the caller's non-volatile registers.
+//  3. Return (to CallAsmJS).
+static Offsets
+GenerateThrow(MacroAssembler& masm)
+{
+    masm.haltingAlign(CodeAlignment);
+
+    Offsets offsets;
+    offsets.begin = masm.currentOffset();
+
+    // We are about to pop all frames in this WasmActivation. Set fp to null to
+    // maintain the invariant that fp is either null or pointing to a valid
+    // frame.
+    Register scratch = ABIArgGenerator::NonArgReturnReg0;
+    masm.loadWasmActivation(scratch);
+    masm.storePtr(ImmWord(0), Address(scratch, WasmActivation::offsetOfFP()));
+
+    masm.setFramePushed(FramePushedForEntrySP);
+    masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
+    masm.Pop(scratch);
+    masm.PopRegsInMask(NonVolatileRegs);
+    MOZ_ASSERT(masm.framePushed() == 0);
+
+    masm.mov(ImmWord(0), ReturnReg);
+    masm.ret();
 
     offsets.end = masm.currentOffset();
-    return mg.defineInlineStub(offsets);
+    return offsets;
+}
+
+Offsets
+wasm::GenerateJumpTarget(MacroAssembler& masm, JumpTarget target)
+{
+    switch (target) {
+      case JumpTarget::StackOverflow: return GenerateStackOverflow(masm);
+      case JumpTarget::ConversionError: return GenerateConversionError(masm);
+      case JumpTarget::OutOfBounds: return GenerateOutOfBounds(masm);
+      case JumpTarget::Throw: return GenerateThrow(masm);
+      case JumpTarget::Limit: break;
+    }
+    MOZ_CRASH("bad JumpTarget");
 }
 
 static const LiveRegisterSet AllRegsExceptSP(
     GeneralRegisterSet(Registers::AllMask&
                        ~(uint32_t(1) << Registers::StackPointer)),
     FloatRegisterSet(FloatRegisters::AllMask));
 
 // The async interrupt-callback exit is called from arbitrarily-interrupted asm.js
 // code. That means we must first save *all* registers and restore *all*
 // registers (except the stack pointer) when we resume. The address to resume to
 // (assuming that js::HandleExecutionInterrupt doesn't indicate that the
 // execution should be aborted) is stored in WasmActivation::resumePC_.
 // Unfortunately, loading this requires a scratch register which we don't have
 // after restoring all registers. To hack around this, push the resumePC on the
 // stack so that it can be popped directly into PC.
-static bool
-GenerateInterruptStub(ModuleGenerator& mg)
+Offsets
+wasm::GenerateInterruptStub(MacroAssembler& masm)
 {
-    MacroAssembler& masm = mg.masm();
     masm.haltingAlign(CodeAlignment);
 
-    // Generate the interrupt stub unconditionally since it may always be used
-    // by the signal handler.
-    mg.defineInterruptExit(masm.currentOffset());
-
     Offsets offsets;
     offsets.begin = masm.currentOffset();
 
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     // Be very careful here not to perturb the machine state before saving it
     // to the stack. In particular, add/sub instructions may set conditions in
     // the flags register.
     masm.push(Imm32(0));            // space for resumePC
@@ -1035,94 +1019,11 @@ GenerateInterruptStub(ModuleGenerator& m
 #elif defined(JS_CODEGEN_ARM64)
     MOZ_CRASH();
 #elif defined (JS_CODEGEN_NONE)
     MOZ_CRASH();
 #else
 # error "Unknown architecture!"
 #endif
 
-    if (masm.oom())
-        return false;
-
     offsets.end = masm.currentOffset();
-    return mg.defineInlineStub(offsets);
+    return offsets;
 }
-
-// If an exception is thrown, simply pop all frames (since asm.js does not
-// contain try/catch). To do this:
-//  1. Restore 'sp' to it's value right after the PushRegsInMask in GenerateEntry.
-//  2. PopRegsInMask to restore the caller's non-volatile registers.
-//  3. Return (to CallAsmJS).
-static bool
-GenerateThrowStub(ModuleGenerator& mg)
-{
-    MacroAssembler& masm = mg.masm();
-    masm.haltingAlign(CodeAlignment);
-
-    if (masm.jumpSites()[JumpTarget::Throw].empty())
-        return true;
-
-    BindJumps(masm, JumpTarget::Throw);
-
-    Offsets offsets;
-    offsets.begin = masm.currentOffset();
-
-    // We are about to pop all frames in this WasmActivation. Set fp to null to
-    // maintain the invariant that fp is either null or pointing to a valid
-    // frame.
-    Register scratch = ABIArgGenerator::NonArgReturnReg0;
-    masm.loadWasmActivation(scratch);
-    masm.storePtr(ImmWord(0), Address(scratch, WasmActivation::offsetOfFP()));
-
-    masm.setFramePushed(FramePushedForEntrySP);
-    masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
-    masm.Pop(scratch);
-    masm.PopRegsInMask(NonVolatileRegs);
-    MOZ_ASSERT(masm.framePushed() == 0);
-
-    masm.mov(ImmWord(0), ReturnReg);
-    masm.ret();
-
-    if (masm.oom())
-        return false;
-
-    offsets.end = masm.currentOffset();
-    return mg.defineInlineStub(offsets);
-}
-
-bool
-wasm::GenerateStubs(ModuleGenerator& mg)
-{
-    for (unsigned i = 0; i < mg.numExports(); i++) {
-        if (!GenerateEntry(mg, i))
-            return false;
-    }
-
-    for (size_t i = 0; i < mg.numImports(); i++) {
-        ProfilingOffsets interp;
-        if (!GenerateInterpExitStub(mg, i, &interp))
-            return false;
-
-        ProfilingOffsets jit;
-        if (!GenerateJitExitStub(mg, i, &jit))
-            return false;
-
-        if (!mg.defineImport(i, interp, jit))
-            return false;
-    }
-
-    if (!GenerateStackOverflowStub(mg))
-        return false;
-
-    if (!GenerateConversionErrorStub(mg))
-        return false;
-
-    if (!GenerateOutOfBoundsStub(mg))
-        return false;
-
-    if (!GenerateInterruptStub(mg))
-        return false;
-
-    // The throw stub must go last since the other stubs use it.
-    return GenerateThrowStub(mg);
-}
-
--- a/js/src/asmjs/WasmStubs.h
+++ b/js/src/asmjs/WasmStubs.h
@@ -19,15 +19,27 @@
 #ifndef wasm_stubs_h
 #define wasm_stubs_h
 
 #include "asmjs/WasmGenerator.h"
 
 namespace js {
 namespace wasm {
 
-bool
-GenerateStubs(ModuleGenerator& mg);
+extern Offsets
+GenerateEntry(jit::MacroAssembler& masm, uint32_t target, const Sig& sig, bool usesHeap);
+
+extern ProfilingOffsets
+GenerateInterpExit(jit::MacroAssembler& masm, const Import& import, uint32_t importIndex);
+
+extern ProfilingOffsets
+GenerateJitExit(jit::MacroAssembler& masm, const Import& import, bool usesHeap);
+
+extern Offsets
+GenerateJumpTarget(jit::MacroAssembler& masm, JumpTarget target);
+
+extern Offsets
+GenerateInterruptStub(jit::MacroAssembler& masm);
 
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_stubs_h
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -33,16 +33,17 @@
 #include "js/Vector.h"
 
 namespace js {
 
 class PropertyName;
 
 namespace wasm {
 
+using mozilla::EnumeratedArray;
 using mozilla::Move;
 using mozilla::DebugOnly;
 using mozilla::MallocSizeOf;
 
 typedef Vector<uint32_t, 0, SystemAllocPolicy> Uint32Vector;
 
 // The ValType enum represents the WebAssembly "value type", which are used to
 // specify the type of locals and parameters.
@@ -261,17 +262,17 @@ struct DeclaredSig : Sig
 typedef Vector<DeclaredSig, 0, SystemAllocPolicy> DeclaredSigVector;
 typedef Vector<const DeclaredSig*, 0, SystemAllocPolicy> DeclaredSigPtrVector;
 
 // The (,Profiling,Func)Offsets classes are used to record the offsets of
 // different key points in a CodeRange during compilation.
 
 struct Offsets
 {
-    MOZ_IMPLICIT Offsets(uint32_t begin = 0, uint32_t end = 0)
+    explicit Offsets(uint32_t begin = 0, uint32_t end = 0)
       : begin(begin), end(end)
     {}
 
     // These define a [begin, end) contiguous range of instructions compiled
     // into a CodeRange.
     uint32_t begin;
     uint32_t end;
 
@@ -566,17 +567,17 @@ enum class JumpTarget
 {
     StackOverflow,
     OutOfBounds,
     ConversionError,
     Throw,
     Limit
 };
 
-typedef mozilla::EnumeratedArray<JumpTarget, JumpTarget::Limit, Uint32Vector> JumpSiteArray;
+typedef EnumeratedArray<JumpTarget, JumpTarget::Limit, Uint32Vector> JumpSiteArray;
 
 // The CompileArgs struct captures global parameters that affect all wasm code
 // generation. It also currently is the single source of truth for whether or
 // not to use signal handlers for different purposes.
 
 struct CompileArgs
 {
     bool useSignalHandlersForOOB;
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -923,17 +923,17 @@ js::RegExpMatcher(JSContext* cx, unsigne
     return RegExpMatcherImpl(cx, regexp, string, lastIndex, sticky,
                              UpdateRegExpStatics, args.rval());
 }
 
 /* Separate interface for use by IonMonkey.
  * This code cannot re-enter Ion code. */
 bool
 js::RegExpMatcherRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                     int32_t lastIndex, bool sticky,
+                     uint32_t lastIndex, bool sticky,
                      MatchPairs* maybeMatches, MutableHandleValue output)
 {
     MOZ_ASSERT(lastIndex <= INT32_MAX);
 
     // The MatchPairs will always be passed in, but RegExp execution was
     // successful only if the pairs have actually been filled in.
     if (maybeMatches && maybeMatches->pairsRaw()[0] >= 0)
         return CreateRegExpMatchResult(cx, input, *maybeMatches, output);
@@ -993,17 +993,17 @@ js::RegExpTester(JSContext* cx, unsigned
     }
     return true;
 }
 
 /* Separate interface for use by IonMonkey.
  * This code cannot re-enter Ion code. */
 bool
 js::RegExpTesterRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                    int32_t lastIndex, bool sticky, int32_t* endIndex)
+                    uint32_t lastIndex, bool sticky, int32_t* endIndex)
 {
     MOZ_ASSERT(lastIndex <= INT32_MAX);
 
     size_t endIndexTmp = 0;
     RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, lastIndex, sticky,
                                            nullptr, &endIndexTmp, UpdateRegExpStatics);
 
     if (status == RegExpRunStatus_Success) {
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -43,25 +43,25 @@ bool
 CreateRegExpMatchResult(JSContext* cx, HandleString input, const MatchPairs& matches,
                         MutableHandleValue rval);
 
 extern bool
 RegExpMatcher(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 RegExpMatcherRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                 int32_t lastIndex, bool sticky,
+                 uint32_t lastIndex, bool sticky,
                  MatchPairs* maybeMatches, MutableHandleValue output);
 
 extern bool
 RegExpTester(JSContext* cx, unsigned argc, Value* vp);
 
 extern bool
 RegExpTesterRaw(JSContext* cx, HandleObject regexp, HandleString input,
-                int32_t lastIndex, bool sticky, int32_t* endIndex);
+                uint32_t lastIndex, bool sticky, int32_t* endIndex);
 
 /*
  * The following functions are for use by self-hosted code.
  */
 
 /*
  * Behaves like regexp.exec(string), but doesn't set RegExp statics.
  *
--- a/js/src/builtin/Sorting.js
+++ b/js/src/builtin/Sorting.js
@@ -60,108 +60,110 @@ function InsertionSort(array, from, to, 
 
 function SwapArrayElements(array, i, j) {
     var swap = array[i];
     array[i] = array[j];
     array[j] = swap;
 }
 
 // A helper function for MergeSort.
-function Merge(array, start, mid, end, lBuffer, rBuffer, comparefn) {
+function Merge(list, start, mid, end, lBuffer, rBuffer, comparefn) {
     var i, j, k;
 
     var sizeLeft = mid - start + 1;
     var sizeRight =  end - mid;
 
-    // Copy our virtual arrays into separate buffers.
+    // Copy our virtual lists into separate buffers.
     for (i = 0; i < sizeLeft; i++)
-        lBuffer[i] = array[start + i];
+        lBuffer[i] = list[start + i];
 
     for (j = 0; j < sizeRight; j++)
-        rBuffer[j] = array[mid + 1 + j];
+        rBuffer[j] = list[mid + 1 + j];
 
 
     i = 0;
     j = 0;
     k = start;
     while (i < sizeLeft && j < sizeRight) {
         if (comparefn(lBuffer[i], rBuffer[j]) <= 0) {
-            _DefineDataProperty(array, k, lBuffer[i]);
+            list[k] = lBuffer[i];
             i++;
         } else {
-            _DefineDataProperty(array, k, rBuffer[j]);
+            list[k] = rBuffer[j];
             j++;
         }
         k++;
     }
 
     // Empty out any remaining elements in the buffer.
     while (i < sizeLeft) {
-        _DefineDataProperty(array, k, lBuffer[i]);
+        list[k] =lBuffer[i];
         i++;
         k++;
     }
 
     while (j < sizeRight) {
-        _DefineDataProperty(array, k, rBuffer[j]);
+        list[k] =rBuffer[j];
         j++;
         k++;
     }
 }
 
 // Helper function for overwriting a sparse array with a
 // dense array, filling remaining slots with holes.
 function MoveHoles(sparse, sparseLen, dense, denseLen) {
-    for (var i in dense)
+    for (var i = 0; i < denseLen; i++)
         _DefineDataProperty(sparse, i, dense[i]);
     for (var j = denseLen; j < sparseLen; j++)
         delete sparse[j];
 }
 
 // Iterative, bottom up, mergesort.
 function MergeSort(array, len, comparefn) {
-    // To save effort we will do all of our work on a dense array,
+    // To save effort we will do all of our work on a dense list,
     // then create holes at the end.
-    var denseArray = [];
+    var denseList = new List();
     var denseLen = 0;
+
     for (var i = 0; i < len; i++) {
         if (i in array)
-            _DefineDataProperty(denseArray, denseLen++, array[i]);
+            denseList[denseLen++] = array[i];
     }
+
     if (denseLen < 1)
         return array;
 
     // Insertion sort for small arrays, where "small" is defined by performance
     // testing.
     if (len < 24) {
-        InsertionSort(denseArray, 0, denseLen - 1, comparefn);
-        MoveHoles(array, len, denseArray, denseLen);
+        InsertionSort(denseList, 0, denseLen - 1, comparefn);
+        MoveHoles(array, len, denseList, denseLen);
         return array;
     }
 
     // We do all of our allocating up front
     var lBuffer = new List();
     var rBuffer = new List();
 
     var mid, end, endOne, endTwo;
     for (var windowSize = 1; windowSize < denseLen; windowSize = 2 * windowSize) {
-        for (var start = 0; start < denseLen - 1; start += 2*windowSize) {
+        for (var start = 0; start < denseLen - 1; start += 2 * windowSize) {
             assert(windowSize < denseLen, "The window size is larger than the array denseLength!");
             // The midpoint between the two subarrays.
             mid = start + windowSize - 1;
             // To keep from going over the edge.
             end = start + 2 * windowSize - 1;
             end = end < denseLen - 1 ? end : denseLen - 1;
             // Skip lopsided runs to avoid doing useless work
             if (mid > end)
                 continue;
-            Merge(denseArray, start, mid, end, lBuffer, rBuffer, comparefn);
+            Merge(denseList, start, mid, end, lBuffer, rBuffer, comparefn);
         }
     }
-    MoveHoles(array, len, denseArray, denseLen);
+    MoveHoles(array, len, denseList, denseLen);
     return array;
 }
 
 // Rearranges the elements in array[from:to + 1] and returns an index j such that:
 // - from < j < to
 // - each element in array[from:j] is less than or equal to array[j]
 // - each element in array[j + 1:to + 1] greater than or equal to array[j].
 function Partition(array, from, to, comparefn) {
--- a/js/src/devtools/rootAnalysis/build/gcc.manifest
+++ b/js/src/devtools/rootAnalysis/build/gcc.manifest
@@ -5,15 +5,16 @@
 {
 "size": 79831648,
 "digest": "958d0dfb531ac6911187cf57907317144a547b884c79dcb483668f0e468ab9f031492ab49177edebf6a6437680b69f54a346a37b4316da78c0ff87aa39c5f2c3",
 "algorithm": "sha512",
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
-"size": 12057960,
-"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
+"size": 12072532,
+"digest": "3915f8ec396c56a8a92e6f9695b70f09ce9d1582359d1258e37e3fd43a143bc974410e4cfc27f500e095f34a8956206e0ebf799b7287f0f38def0d5e34ed71c9",
 "algorithm": "sha512",
 "filename": "gtk3.tar.xz",
+"setup": "setup.sh",
 "unpack": true
 }
 ]
--- a/js/src/dtoa.c
+++ b/js/src/dtoa.c
@@ -521,16 +521,24 @@ destroydtoa
 			next = v->next;
 #ifndef Omit_Private_Memory
 			if ((double*)v < GET_STATE(private_mem) ||
 			    (double*)v >= GET_STATE(private_mem) + PRIVATE_mem)
 #endif
 				FREE((void*)v);
 			}
 		}
+#ifdef Omit_Private_Memory
+	Bigint* p5 = GET_STATE(p5s);
+	while (p5) {
+		Bigint* tmp = p5;
+		p5 = p5->next;
+		FREE(tmp);
+		}
+#endif
 	FREE((void *)state);
 }
 
 #else
 #define STATE_PARAM      /* nothing */
 #define STATE_PARAM_DECL /* nothing */
 #define PASS_STATE       /* nothing */
 #define GET_STATE(name) name
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -131,17 +131,20 @@ void
 js::RootLists::finishPersistentRoots()
 {
 #define FINISH_ROOT_LIST(name, type, _) \
     FinishPersistentRootedChain<type*>(heapRoots_[JS::RootKind::name]);
 JS_FOR_EACH_TRACEKIND(FINISH_ROOT_LIST)
 #undef FINISH_ROOT_LIST
     FinishPersistentRootedChain<jsid>(heapRoots_[JS::RootKind::Id]);
     FinishPersistentRootedChain<Value>(heapRoots_[JS::RootKind::Value]);
-    FinishPersistentRootedChain<ConcreteTraceable>(heapRoots_[JS::RootKind::Traceable]);
+
+    // Note that we do not finalize the Traceable list as we do not know how to
+    // safely clear memebers. We instead assert that none escape the RootLists.
+    // See the comment on RootLists::~RootLists for details.
 }
 
 inline void
 AutoGCRooter::trace(JSTracer* trc)
 {
     switch (tag_) {
       case PARSER:
         frontend::MarkParser(trc, this);
--- a/js/src/jit-test/tests/asm.js/testAtomics.js
+++ b/js/src/jit-test/tests/asm.js/testAtomics.js
@@ -1814,25 +1814,24 @@ var loadModule_misc_code =
         ilf9: ilf9 };
 `
 
 var loadModule_misc = asmCompile('stdlib', 'foreign', 'heap', loadModule_misc_code);
 
 function test_misc(heap) {
     var misc = loadModule_misc(this, {}, heap);
 
-    assertEq(misc.ilf1(), 1);
-    assertEq(misc.ilf2(), 1);
+    assertEq(misc.ilf1(), 1);   // Guaranteed by SpiderMonkey, not spec
+    assertEq(misc.ilf2(), 1);   // Guaranteed by SpiderMonkey, not spec
     assertEq(misc.ilf3(), 0);
-    assertEq(misc.ilf4(), 1);
+    assertEq(misc.ilf4(), 1);   // Guaranteed by SpiderMonkey, not spec
     assertEq(misc.ilf5(), 0);
     assertEq(misc.ilf6(), 0);
     assertEq(misc.ilf7(), 0);
-    var v = misc.ilf8();
-    assertEq(v === 0 || v === 1, true);
+    assertEq(misc.ilf8(), 0);   // Required by spec, for now
     assertEq(misc.ilf9(), 0);
 }
 
 // Shared-memory Uint8ClampedArray is not supported for asm.js.
 
 var heap = new SharedArrayBuffer(65536);
 
 test_int8(heap);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testJumpRange.js
@@ -0,0 +1,51 @@
+load(libdir + "asm.js");
+load(libdir + "asserts.js");
+
+var fatFunc = USE_ASM + '\n';
+for (var i = 0; i < 100; i++)
+    fatFunc += "function f" + i + "() { return ((f" + (i+1) + "()|0)+1)|0 }\n";
+fatFunc += "function f100() { return 42 }\n";
+fatFunc += "return f0";
+
+for (var signals = 0; signals <= 1; signals++) {
+    setJitCompilerOption("signals.enable", signals);
+
+    for (let threshold of [0, 50, 100, 5000, -1]) {
+        setJitCompilerOption("jump-threshold", threshold);
+
+        assertEq(asmCompile(
+            USE_ASM + `
+                function h() { return ((g()|0)+2)|0 }
+                function g() { return ((f()|0)+1)|0 }
+                function f() { return 42 }
+                return h
+            `)()(), 45);
+
+        if (isSimdAvailable() && this.SIMD) {
+            var buf = new ArrayBuffer(BUF_MIN);
+            new Int32Array(buf)[0] = 10;
+            new Float32Array(buf)[1] = 42;
+            assertEq(asmCompile('stdlib', 'ffis', 'buf',
+                USE_ASM + `
+                    var H = new stdlib.Uint8Array(buf);
+                    var i4 = stdlib.SIMD.Int32x4;
+                    var f4 = stdlib.SIMD.Float32x4;
+                    var i4load = i4.load;
+                    var f4load = f4.load;
+                    var toi4 = i4.fromFloat32x4;
+                    var i4ext = i4.extractLane;
+                    function f(i) { i=i|0; return i4ext(i4load(H, i), 0)|0 }
+                    function g(i) { i=i|0; return (i4ext(toi4(f4load(H, i)),1) + (f(i)|0))|0 }
+                    function h(i) { i=i|0; return g(i)|0 }
+                    return h
+                `)(this, null, buf)(0), 52);
+        }
+
+        enableSPSProfiling();
+        asmLink(asmCompile(USE_ASM + 'function f() {} function g() { f() } function h() { g() } return h'))();
+        disableSPSProfiling();
+
+        assertEq(asmCompile(fatFunc)()(), 142);
+    }
+}
+
--- a/js/src/jit-test/tests/asm.js/testProfiling.js
+++ b/js/src/jit-test/tests/asm.js/testProfiling.js
@@ -210,16 +210,25 @@ if (isSimdAvailable() && typeof SIMD !==
     assertThrowsInstanceOf(() => f(4), RangeError);
     var stacks = disableSingleStepProfiling();
     // TODO check that expected is actually the correctly expected string, when
     // SIMD is implemented on ARM.
     assertStackContainsSeq(stacks, ">,f,>,inline stub,f,>");
 }
 
 
+// Thunks
+setJitCompilerOption("jump-threshold", 0);
+var h = asmLink(asmCompile(USE_ASM + 'function f() {} function g() { f() } function h() { g() } return h'));
+enableSingleStepProfiling();
+h();
+var stacks = disableSingleStepProfiling();
+assertStackContainsSeq(stacks, ">,h,>,g,h,>,f,g,h,>,g,h,>,h,>,>");
+setJitCompilerOption("jump-threshold", -1);
+
 // This takes forever to run.
 // Stack-overflow exit test
 //var limit = -1;
 //var maxct = 0;
 //function ffi(ct) { if (ct == limit) { enableSingleStepProfiling(); print("enabled"); } maxct = ct; }
 //var f = asmLink(asmCompile('g', 'ffis',USE_ASM + "var ffi=ffis.ffi; var ct=0; function rec(){ ct=(ct+1)|0; ffi(ct|0); rec() } function f() { ct=0; rec() } return f"), null, {ffi});
 //// First find the stack limit:
 //var caught = false;
--- a/js/src/jit-test/tests/atomics/basic-tests.js
+++ b/js/src/jit-test/tests/atomics/basic-tests.js
@@ -370,44 +370,46 @@ function exchangeLoop(ta) {
 
 function adHocExchange() {
     var a = new Int8Array(new SharedArrayBuffer(16));
     for ( var i=0 ; i < a.length ; i++ )
 	a[i] = 255;
     assertEq(exchangeLoop(a), -100000);
 }
 
+// isLockFree(n) may return true only if there is an integer array
+// on which atomic operations is allowed whose byte size is n,
+// ie, it must return false for n=8.
+//
+// SpiderMonkey has isLockFree(1), isLockFree(2), isLockFree(4) on all
+// supported platforms, though this is not guaranteed by the spec.
+
 var sizes   = [    1,     2,     3,     4,     5,     6,     7,  8,
                    9,    10,    11,    12];
-var answers = [ true,  true, false,  true, false, false, false, {},
+var answers = [ true,  true, false,  true, false, false, false, false,
 	       false, false, false, false];
 
 function testIsLockFree() {
-    var saved8 = "Invalid";
-
     // This ought to defeat most compile-time resolution.
     for ( var i=0 ; i < sizes.length ; i++ ) {
 	var v = Atomics.isLockFree(sizes[i]);
 	var a = answers[i];
 	assertEq(typeof v, 'boolean');
-	if (typeof a == 'boolean')
-	    assertEq(v, a);
-	else
-	    saved8 = v;
+	assertEq(v, a);
     }
 
     // This ought to be optimizable.
     assertEq(Atomics.isLockFree(1), true);
     assertEq(Atomics.isLockFree(2), true);
     assertEq(Atomics.isLockFree(3), false);
     assertEq(Atomics.isLockFree(4), true);
     assertEq(Atomics.isLockFree(5), false);
     assertEq(Atomics.isLockFree(6), false);
     assertEq(Atomics.isLockFree(7), false);
-    assertEq(Atomics.isLockFree(8), saved8);
+    assertEq(Atomics.isLockFree(8), false);
     assertEq(Atomics.isLockFree(9), false);
     assertEq(Atomics.isLockFree(10), false);
     assertEq(Atomics.isLockFree(11), false);
     assertEq(Atomics.isLockFree(12), false);
 }
 
 function testUint8Clamped(sab) {
     var ta = new Uint8ClampedArray(sab);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/self-hosting/method-called-on-incompatible.js
@@ -0,0 +1,9 @@
+load(libdir + "asserts.js");
+
+assertTypeErrorMessage(() => WeakSet.prototype.add.call({}), "add method called on incompatible Object");
+assertTypeErrorMessage(() => newGlobal().WeakSet.prototype.add.call({}), "add method called on incompatible Object");
+assertTypeErrorMessage(() => WeakSet.prototype.add.call(15), "add method called on incompatible number");
+
+assertTypeErrorMessage(() => Int8Array.prototype.find.call({}), "find method called on incompatible Object");
+assertTypeErrorMessage(() => newGlobal().Int8Array.prototype.find.call({}), "find method called on incompatible Object");
+assertTypeErrorMessage(() => Int8Array.prototype.find.call(15), "find method called on incompatible number");
--- a/js/src/jit-test/tests/wasm/binary.js
+++ b/js/src/jit-test/tests/wasm/binary.js
@@ -13,16 +13,17 @@ const ver2 = 0xff;
 const ver3 = 0xff;
 
 // Section names
 const sigSectionStr = "sig";
 const declSectionStr = "decl";
 const importSectionStr = "import";
 const exportSectionStr = "export";
 const codeSectionStr = "code";
+const dataSectionStr = "data";
 const funcSubsectionStr = "func";
 
 const magicError = /failed to match magic number/;
 const versionError = /failed to match binary version/;
 const extraError = /failed to consume all bytes of module/;
 const sectionError = /failed to read section name/;
 
 const I32Code = 0;
@@ -165,8 +166,10 @@ assertErrorMessage(() => wasmEval(toBuf(
 wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([])])));
 wasmEval(toBuf(moduleWithSections([trivialSigSection, importSection([{sigIndex:0, module:"a", func:""}])])), {a:()=>{}});
 
 wasmEval(toBuf(moduleWithSections([
     trivialSigSection,
     importSection([{sigIndex:0, module:"a", func:""}]),
     trivialDeclSection,
     trivialCodeSection])), {a:()=>{}});
+
+assertErrorMessage(() => wasmEval(toBuf(moduleWithSections([ {name: dataSectionStr, body: [], } ]))), Error, /data section requires a memory section/);
--- a/js/src/jit/AtomicOperations.h
+++ b/js/src/jit/AtomicOperations.h
@@ -142,23 +142,29 @@ class AtomicOperations
 
     // Replacement for memcpy().
     static inline void memcpySafeWhenRacy(void* dest, const void* src, size_t nbytes);
 
     // Replacement for memmove().
     static inline void memmoveSafeWhenRacy(void* dest, const void* src, size_t nbytes);
 
   public:
-    // Test lock-freedom for any integer value.
+    // Test lock-freedom for any int32 value.  This implements the
+    // Atomics::isLockFree() operation in the Shared Memory and
+    // Atomics specification, as follows:
     //
-    // This implements a platform-independent pattern, as follows:
+    // 1, 2, and 4 bytes are always lock free (in SpiderMonkey).
     //
-    // 1, 2, and 4 bytes are always lock free, lock-freedom for 8
-    // bytes is determined by the platform's isLockfree8(), and there
-    // is no lock-freedom for any other values on any platform.
+    // Lock-freedom for 8 bytes is determined by the platform's
+    // isLockfree8().  However, the spec stipulates that isLockFree(8)
+    // is true only if there is an integer array that admits atomic
+    // operations whose BYTES_PER_ELEMENT=8; at the moment (February
+    // 2016) there are no such arrays.
+    //
+    // There is no lock-freedom for any other values on any platform.
     static inline bool isLockfree(int32_t n);
 
     // If the return value is true then a call to the 64-bit (8-byte)
     // routines below will work, otherwise those functions will assert in
     // debug builds and may crash in release build.  (See the code in
     // ../arm for an example.)  The value of this call does not change
     // during execution.
     static inline bool isLockfree8();
@@ -292,17 +298,22 @@ AtomicOperations::isLockfree(int32_t siz
     // Keep this in sync with visitAtomicIsLockFree() in jit/CodeGenerator.cpp.
 
     switch (size) {
       case 1:
       case 2:
       case 4:
         return true;
       case 8:
-        return AtomicOperations::isLockfree8();
+        // The spec requires Atomics.isLockFree(n) to return false
+        // unless n is the BYTES_PER_ELEMENT value of some integer
+        // TypedArray that admits atomic operations.  At the time of
+        // writing (February 2016) there is no such array with n=8.
+        // return AtomicOperations::isLockfree8();
+        return false;
       default:
         return false;
     }
 }
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1746,17 +1746,17 @@ class OutOfLineRegExpMatcher : public Ou
     }
 
     LRegExpMatcher* lir() const {
         return lir_;
     }
 };
 
 typedef bool (*RegExpMatcherRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
-                                   int32_t lastIndex, bool sticky,
+                                   uint32_t lastIndex, bool sticky,
                                    MatchPairs* pairs, MutableHandleValue output);
 static const VMFunction RegExpMatcherRawInfo = FunctionInfo<RegExpMatcherRawFn>(RegExpMatcherRaw);
 
 void
 CodeGenerator::visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool)
 {
     LRegExpMatcher* lir = ool->lir();
     Register sticky = ToRegister(lir->sticky());
@@ -1911,17 +1911,17 @@ class OutOfLineRegExpTester : public Out
     }
 
     LRegExpTester* lir() const {
         return lir_;
     }
 };
 
 typedef bool (*RegExpTesterRawFn)(JSContext* cx, HandleObject regexp, HandleString input,
-                                  int32_t lastIndex, bool sticky, int32_t* result);
+                                  uint32_t lastIndex, bool sticky, int32_t* result);
 static const VMFunction RegExpTesterRawInfo = FunctionInfo<RegExpTesterRawFn>(RegExpTesterRaw);
 
 void
 CodeGenerator::visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool)
 {
     LRegExpTester* lir = ool->lir();
     Register sticky = ToRegister(lir->sticky());
     Register lastIndex = ToRegister(lir->lastIndex());
@@ -9812,29 +9812,24 @@ CodeGenerator::visitStoreTypedArrayEleme
 }
 
 void
 CodeGenerator::visitAtomicIsLockFree(LAtomicIsLockFree* lir)
 {
     Register value = ToRegister(lir->value());
     Register output = ToRegister(lir->output());
 
-    // Keep this in sync with isLockfree() in jit/AtomicOperations-inl.h.
+    // Keep this in sync with isLockfree() in jit/AtomicOperations.h.
+    MOZ_ASSERT(!AtomicOperations::isLockfree(8));
 
     Label Ldone, Lfailed;
     masm.move32(Imm32(1), output);
-    if (AtomicOperations::isLockfree8())
-        masm.branch32(Assembler::Equal, value, Imm32(8), &Ldone);
-    else
-        masm.branch32(Assembler::Equal, value, Imm32(8), &Lfailed);
     masm.branch32(Assembler::Equal, value, Imm32(4), &Ldone);
     masm.branch32(Assembler::Equal, value, Imm32(2), &Ldone);
     masm.branch32(Assembler::Equal, value, Imm32(1), &Ldone);
-    if (!AtomicOperations::isLockfree8())
-        masm.bind(&Lfailed);
     masm.move32(Imm32(0), output);
     masm.bind(&Ldone);
 }
 
 void
 CodeGenerator::visitGuardSharedTypedArray(LGuardSharedTypedArray* guard)
 {
     Register obj = ToRegister(guard->input());
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2453,17 +2453,17 @@ IonBuilder::finishLoop(CFGState& state, 
     if (!current)
         return ControlStatus_Ended;
 
     pc = current->pc();
     return ControlStatus_Joined;
 }
 
 IonBuilder::ControlStatus
-IonBuilder::restartLoop(CFGState state)
+IonBuilder::restartLoop(const CFGState& state)
 {
     spew("New types at loop header, restarting loop body");
 
     if (JitOptions.limitScriptSize) {
         if (++numLoopRestarts_ >= MAX_LOOP_RESTARTS)
             return ControlStatus_Abort;
     }
 
@@ -2481,29 +2481,35 @@ IonBuilder::restartLoop(CFGState state)
     header->discardAllInstructions();
     header->discardAllResumePoints(/* discardEntry = */ false);
     header->setStackDepth(header->getPredecessor(0)->stackDepth());
 
     popCfgStack();
 
     loopDepth_++;
 
+    // Keep a local copy for these pointers since state will be overwritten in
+    // pushLoop since state is a reference to cfgStack_.back()
+    jsbytecode* condpc = state.loop.condpc;
+    jsbytecode* updatepc = state.loop.updatepc;
+    jsbytecode* updateEnd = state.loop.updateEnd;
+
     if (!pushLoop(state.loop.initialState, state.loop.initialStopAt, header, state.loop.osr,
                   state.loop.loopHead, state.loop.initialPc,
                   state.loop.bodyStart, state.loop.bodyEnd,
                   state.loop.exitpc, state.loop.continuepc))
     {
         return ControlStatus_Error;
     }
 
     CFGState& nstate = cfgStack_.back();
 
-    nstate.loop.condpc = state.loop.condpc;
-    nstate.loop.updatepc = state.loop.updatepc;
-    nstate.loop.updateEnd = state.loop.updateEnd;
+    nstate.loop.condpc = condpc;
+    nstate.loop.updatepc = updatepc;
+    nstate.loop.updateEnd = updateEnd;
 
     // Don't specializePhis(), as the header has been visited before and the
     // phis have already had their type set.
     setCurrent(header);
 
     if (!jsop_loophead(nstate.loop.loopHead))
         return ControlStatus_Error;
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -312,17 +312,17 @@ class IonBuilder
     // Incorporates a type/typeSet into an OSR value for a loop, after the loop
     // body has been processed.
     bool addOsrValueTypeBarrier(uint32_t slot, MInstruction** def,
                                 MIRType type, TemporaryTypeSet* typeSet);
     bool maybeAddOsrTypeBarriers();
 
     // Restarts processing of a loop if the type information at its header was
     // incomplete.
-    ControlStatus restartLoop(CFGState state);
+    ControlStatus restartLoop(const CFGState& state);
 
     void assertValidLoopHeadOp(jsbytecode* pc);
 
     ControlStatus forLoop(JSOp op, jssrcnote* sn);
     ControlStatus whileOrForInLoop(jssrcnote* sn);
     ControlStatus doWhileLoop(JSOp op, jssrcnote* sn);
     ControlStatus tableSwitch(JSOp op, jssrcnote* sn);
     ControlStatus condSwitch(JSOp op, jssrcnote* sn);
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -156,16 +156,20 @@ DefaultJitOptions::DefaultJitOptions()
 
     // How many times we will try to enter a script via OSR before
     // invalidating the script.
     SET_DEFAULT(osrPcMismatchesBeforeRecompile, 6000);
 
     // The bytecode length limit for small function.
     SET_DEFAULT(smallFunctionMaxBytecodeLength_, 120);
 
+    // An artificial testing limit for the maximum supported offset of
+    // pc-relative jump and call instructions.
+    SET_DEFAULT(jumpThreshold, UINT32_MAX);
+
     // Force how many invocation or loop iterations are needed before compiling
     // a function with the highest ionmonkey optimization level.
     // (i.e. OptimizationLevel_Normal)
     const char* forcedDefaultIonWarmUpThresholdEnv = "JIT_OPTION_forcedDefaultIonWarmUpThreshold";
     if (const char* env = getenv(forcedDefaultIonWarmUpThresholdEnv)) {
         Maybe<int> value = ParseInt(env);
         if (value.isSome())
             forcedDefaultIonWarmUpThreshold.emplace(value.ref());
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -67,16 +67,17 @@ struct DefaultJitOptions
     bool limitScriptSize;
     bool osr;
     uint32_t baselineWarmUpThreshold;
     uint32_t exceptionBailoutThreshold;
     uint32_t frequentBailoutThreshold;
     uint32_t maxStackArgs;
     uint32_t osrPcMismatchesBeforeRecompile;
     uint32_t smallFunctionMaxBytecodeLength_;
+    uint32_t jumpThreshold;
     mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
     mozilla::Maybe<IonRegisterAllocator> forcedRegisterAllocator;
 
     // The options below affect the rest of the VM, and not just the JIT.
     bool disableUnboxedObjects;
 
     DefaultJitOptions();
     bool isSmallFunction(JSScript* script) const;
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2470,28 +2470,37 @@ LIRGenerator::visitMonitorTypes(MMonitor
     LDefinition tmp = needTemp ? temp() : tempToUnbox();
 
     LMonitorTypes* lir = new(alloc()) LMonitorTypes(tmp);
     useBox(lir, LMonitorTypes::Input, ins->input());
     assignSnapshot(lir, Bailout_MonitorTypes);
     add(lir, ins);
 }
 
+// Returns true iff |def| is a constant that's either not a GC thing or is not
+// allocated in the nursery.
+static bool
+IsNonNurseryConstant(MDefinition* def)
+{
+    if (!def->isConstant())
+        return false;
+    Value v = def->toConstant()->value();
+    return !v.isMarkable() || !IsInsideNursery(v.toGCThing());
+}
+
 void
 LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType_Object);
 
     // LPostWriteBarrier assumes that if it has a constant object then that
     // object is tenured, and does not need to be tested for being in the
     // nursery. Ensure that assumption holds by lowering constant nursery
     // objects to a register.
-    bool useConstantObject =
-        ins->object()->isConstant() &&
-        !IsInsideNursery(&ins->object()->toConstant()->value().toObject());
+    bool useConstantObject = IsNonNurseryConstant(ins->object());
 
     switch (ins->value()->type()) {
       case MIRType_Object:
       case MIRType_ObjectOrNull: {
         LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
         LPostWriteBarrierO* lir =
             new(alloc()) LPostWriteBarrierO(useConstantObject
                                             ? useOrConstant(ins->object())
@@ -3636,16 +3645,17 @@ LIRGenerator::visitSetPropertyCache(MSet
     MOZ_ASSERT(id->type() == MIRType_String ||
                id->type() == MIRType_Symbol ||
                id->type() == MIRType_Int32 ||
                id->type() == MIRType_Value);
 
     // If this is a SETPROP, the id is a constant string. Allow passing it as a
     // constant to reduce register allocation pressure.
     bool useConstId = id->type() == MIRType_String || id->type() == MIRType_Symbol;
+    bool useConstValue = IsNonNurseryConstant(ins->value());
 
     // Set the performs-call flag so that we don't omit the overrecursed check.
     // This is necessary because the cache can attach a scripted setter stub
     // that calls this script recursively.
     gen->setPerformsCall();
 
     // If the index might be an integer, we need some extra temp registers for
     // the dense and typed array element stubs.
@@ -3658,17 +3668,17 @@ LIRGenerator::visitSetPropertyCache(MSet
             tempToUnboxIndex = tempToUnbox();
         tempD = tempDouble();
         tempF32 = hasUnaliasedDouble() ? tempFloat32() : LDefinition::BogusTemp();
     }
 
     LInstruction* lir = new(alloc()) LSetPropertyCache(useRegister(ins->object()), temp(),
                                                        tempToUnboxIndex, tempD, tempF32);
     useBoxOrTypedOrConstant(lir, LSetPropertyCache::Id, id, useConstId);
-    useBoxOrTypedOrConstant(lir, LSetPropertyCache::Value, ins->value(), /* useConstant = */ true);
+    useBoxOrTypedOrConstant(lir, LSetPropertyCache::Value, ins->value(), useConstValue);
 
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitCallSetElement(MCallSetElement* ins)
 {
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -81,23 +81,16 @@ MacroAssembler::PushWithPatch(ImmPtr imm
 void
 MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg)
 {
     CodeOffset l = call(reg);
     append(desc, l, framePushed());
 }
 
 void
-MacroAssembler::call(const wasm::CallSiteDesc& desc, Label* label)
-{
-    CodeOffset l = call(label);
-    append(desc, l, framePushed());
-}
-
-void
 MacroAssembler::call(const wasm::CallSiteDesc& desc, AsmJSInternalCallee callee)
 {
     CodeOffset l = callWithPatch();
     append(desc, l, framePushed(), callee.index);
 }
 
 // ===============================================================
 // ABI function calls.
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -493,27 +493,27 @@ class MacroAssembler : public MacroAssem
     void call(ImmWord imm) PER_SHARED_ARCH;
     // Call a target native function, which is neither traceable nor movable.
     void call(ImmPtr imm) PER_SHARED_ARCH;
     void call(wasm::SymbolicAddress imm) PER_SHARED_ARCH;
     // Call a target JitCode, which must be traceable, and may be movable.
     void call(JitCode* c) PER_SHARED_ARCH;
 
     inline void call(const wasm::CallSiteDesc& desc, const Register reg);
-    inline void call(const wasm::CallSiteDesc& desc, Label* label);
     inline void call(const wasm::CallSiteDesc& desc, AsmJSInternalCallee callee);
 
     CodeOffset callWithPatch() PER_SHARED_ARCH;
     void patchCall(uint32_t callerOffset, uint32_t calleeOffset) PER_SHARED_ARCH;
 
     // Thunks provide the ability to jump to any uint32_t offset from any other
     // uint32_t offset without using a constant pool (thus returning a simple
     // CodeOffset instead of a CodeOffsetJump).
     CodeOffset thunkWithPatch() PER_SHARED_ARCH;
     void patchThunk(uint32_t thunkOffset, uint32_t targetOffset) PER_SHARED_ARCH;
+    static void repatchThunk(uint8_t* code, uint32_t thunkOffset, uint32_t targetOffset) PER_SHARED_ARCH;
 
     // Push the return address and make a call. On platforms where this function
     // is not defined, push the link register (pushReturnAddress) at the entry
     // point of the callee.
     void callAndPushReturnAddress(Register reg) DEFINED_ON(mips_shared, x86_shared);
     void callAndPushReturnAddress(Label* label) DEFINED_ON(mips_shared, x86_shared);
 
     void pushReturnAddress() DEFINED_ON(arm, arm64);
--- a/js/src/jit/arm/Architecture-arm.h
+++ b/js/src/jit/arm/Architecture-arm.h
@@ -31,16 +31,20 @@ namespace jit {
 static const uint32_t ION_FRAME_SLACK_SIZE   = 20;
 
 // These offsets are specific to nunboxing, and capture offsets into the
 // components of a js::Value.
 static const int32_t NUNBOX32_TYPE_OFFSET    = 4;
 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
 
 static const uint32_t ShadowStackSpace = 0;
+
+// How far forward/back can a jump go? Provide a generous buffer for thunks.
+static const uint32_t JumpImmediateRange = 25 * 1024 * 1024;
+
 ////
 // These offsets are related to bailouts.
 ////
 
 // Size of each bailout table entry. On arm, this is presently a single call
 // (which is wrong!). The call clobbers lr.
 // For now, I've dealt with this by ensuring that we never allocate to lr. It
 // should probably be 8 bytes, a mov of an immediate into r12 (not allocated
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/arm/MacroAssembler-arm.h"
 
 #include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MathAlgorithms.h"
 
+#include "asmjs/WasmBinary.h"
 #include "jit/arm/Simulator-arm.h"
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/JitFrames.h"
 #include "jit/MacroAssembler.h"
 #include "jit/MoveEmitter.h"
 
 #include "jit/MacroAssembler-inl.h"
@@ -4952,16 +4953,19 @@ MacroAssembler::patchCall(uint32_t calle
 {
     BufferOffset inst(callerOffset - 4);
     as_bl(BufferOffset(calleeOffset).diffB<BOffImm>(inst), Always, inst);
 }
 
 CodeOffset
 MacroAssembler::thunkWithPatch()
 {
+    static_assert(32 * 1024 * 1024 - JumpImmediateRange > wasm::MaxFuncs * 3 * sizeof(Instruction),
+                  "always enough space for thunks");
+
     // The goal of the thunk is to be able to jump to any address without the
     // usual 32MiB branch range limitation. Additionally, to make the thunk
     // simple to use, the thunk does not use the constant pool or require
     // patching an absolute address. Instead, a relative offset is used which
     // can be patched during compilation.
 
     // Inhibit pools since these three words must be contiguous so that the offset
     // calculations below are valid.
@@ -4992,16 +4996,27 @@ MacroAssembler::patchThunk(uint32_t u32O
     MOZ_ASSERT(editSrc(BufferOffset(addOffset))->is<InstALU>());
 
     // When pc is read as the operand of the add, its value is the address of
     // the add instruction + 8.
     *u32 = (targetOffset - addOffset) - 8;
 }
 
 void
+MacroAssembler::repatchThunk(uint8_t* code, uint32_t u32Offset, uint32_t targetOffset)
+{
+    uint32_t* u32 = reinterpret_cast<uint32_t*>(code + u32Offset);
+
+    uint32_t addOffset = u32Offset - 4;
+    MOZ_ASSERT(reinterpret_cast<Instruction*>(code + addOffset)->is<InstALU>());
+
+    *u32 = (targetOffset - addOffset) - 8;
+}
+
+void
 MacroAssembler::pushReturnAddress()
 {
     push(lr);
 }
 
 // ===============================================================
 // ABI function calls.
 
--- a/js/src/jit/arm64/Architecture-arm64.h
+++ b/js/src/jit/arm64/Architecture-arm64.h
@@ -293,16 +293,21 @@ class FloatRegisters
 // In bytes: slots needed for potential memory->memory move spills.
 //   +8 for cycles
 //   +8 for gpr spills
 //   +8 for double spills
 static const uint32_t ION_FRAME_SLACK_SIZE = 24;
 
 static const uint32_t ShadowStackSpace = 0;
 
+// TODO:
+// This constant needs to be updated to account for whatever near/far branching
+// strategy is used by ARM64.
+static const uint32_t JumpImmediateRange = UINT32_MAX;
+
 static const uint32_t ABIStackAlignment = 16;
 static const uint32_t CodeAlignment = 16;
 static const bool StackKeptAligned = false;
 
 // Although sp is only usable if 16-byte alignment is kept,
 // the Pseudo-StackPointer enables use of 8-byte alignment.
 static const uint32_t StackAlignment = 8;
 static const uint32_t NativeFrameSize = 8;
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -574,16 +574,22 @@ MacroAssembler::thunkWithPatch()
 
 void
 MacroAssembler::patchThunk(uint32_t thunkOffset, uint32_t targetOffset)
 {
     MOZ_CRASH("NYI");
 }
 
 void
+MacroAssembler::repatchThunk(uint8_t* code, uint32_t thunkOffset, uint32_t targetOffset)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
 MacroAssembler::pushReturnAddress()
 {
     push(lr);
 }
 
 // ===============================================================
 // ABI function calls.
 
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -2469,24 +2469,16 @@ class MacroAssemblerCompat : public vixl
         MOZ_ASSERT(scratch != dest.base);
         load32(src, scratch);
         storeValue(JSVAL_TYPE_INT32, scratch, dest);
     }
 
     void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label);
     void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label);
 
-    void appendCallSite(const wasm::CallSiteDesc& desc) {
-        MOZ_CRASH("appendCallSite");
-    }
-
-    void callExit(wasm::SymbolicAddress imm, uint32_t stackArgBytes) {
-        MOZ_CRASH("callExit");
-    }
-
     void profilerEnterFrame(Register framePtr, Register scratch) {
         AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
         loadPtr(activation, scratch);
         storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
         storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
     }
     void profilerExitFrame() {
         branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
--- a/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
+++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared.cpp
@@ -1164,16 +1164,22 @@ MacroAssembler::thunkWithPatch()
 
 void
 MacroAssembler::patchThunk(uint32_t callerOffset, uint32_t calleeOffset)
 {
     MOZ_CRASH("NYI");
 }
 
 void
+MacroAssembler::repatchThunk(uint8_t* code, uint32_t callerOffset, uint32_t calleeOffset)
+{
+    MOZ_CRASH("NYI");
+}
+
+void
 MacroAssembler::call(wasm::SymbolicAddress target)
 {
     movePtr(target, CallReg);
     call(CallReg);
 }
 
 void
 MacroAssembler::call(ImmWord target)
--- a/js/src/jit/none/Architecture-none.h
+++ b/js/src/jit/none/Architecture-none.h
@@ -136,16 +136,17 @@ struct FloatRegister
     // This is used in static initializers, so produce a bogus value instead of crashing.
     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>&) { return 0; }
 };
 
 inline bool hasUnaliasedDouble() { MOZ_CRASH(); }
 inline bool hasMultiAlias() { MOZ_CRASH(); }
 
 static const uint32_t ShadowStackSpace = 0;
+static const uint32_t JumpImmediateRange = INT32_MAX;
 
 #ifdef JS_NUNBOX32
 static const int32_t NUNBOX32_TYPE_OFFSET = 4;
 static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
 #endif
 
 static const size_t WasmCheckedImmediateRange = 0;
 static const size_t WasmImmediateRange = 0;
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -749,17 +749,18 @@ class AssemblerShared
         wasm::CallSite callsite(desc, retAddr.offset(), framePushed + sizeof(AsmJSFrame));
         enoughMemory_ &= callsites_.append(wasm::CallSiteAndTarget(callsite, targetIndex));
     }
     wasm::CallSiteAndTargetVector& callSites() { return callsites_; }
 
     void append(wasm::JumpTarget target, uint32_t offset) {
         enoughMemory_ &= jumpsites_[target].append(offset);
     }
-    const wasm::JumpSiteArray& jumpSites() const { return jumpsites_; }
+    const wasm::JumpSiteArray& jumpSites() { return jumpsites_; }
+    void clearJumpSites() { for (auto& v : jumpsites_) v.clear(); }
 
     void append(wasm::HeapAccess access) { enoughMemory_ &= heapAccesses_.append(access); }
     wasm::HeapAccessVector&& extractHeapAccesses() { return Move(heapAccesses_); }
 
     void append(AsmJSGlobalAccess access) { enoughMemory_ &= asmJSGlobalAccesses_.append(access); }
     size_t numAsmJSGlobalAccesses() const { return asmJSGlobalAccesses_.length(); }
     AsmJSGlobalAccess asmJSGlobalAccess(size_t i) const { return asmJSGlobalAccesses_[i]; }
 
--- a/js/src/jit/x86-shared/Architecture-x86-shared.h
+++ b/js/src/jit/x86-shared/Architecture-x86-shared.h
@@ -52,16 +52,18 @@ static const uint32_t BAILOUT_TABLE_ENTR
 #endif
 
 #if defined(JS_CODEGEN_X64) && defined(_WIN64)
 static const uint32_t ShadowStackSpace = 32;
 #else
 static const uint32_t ShadowStackSpace = 0;
 #endif
 
+static const uint32_t JumpImmediateRange = INT32_MAX;
+
 class Registers {
   public:
     typedef uint8_t Code;
     typedef X86Encoding::RegisterID Encoding;
 
     // Content spilled during bailouts.
     union RegisterContent {
         uintptr_t r;
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -1023,19 +1023,22 @@ class AssemblerX86Shared : public Assemb
     }
     void patchCall(uint32_t callerOffset, uint32_t calleeOffset) {
         unsigned char* code = masm.data();
         X86Encoding::SetRel32(code + callerOffset, code + calleeOffset);
     }
     CodeOffset thunkWithPatch() {
         return CodeOffset(masm.jmp().offset());
     }
-    void patchThunk(uint32_t jumpOffset, uint32_t targetOffset) {
+    void patchThunk(uint32_t thunkOffset, uint32_t targetOffset) {
         unsigned char* code = masm.data();
-        X86Encoding::SetRel32(code + jumpOffset, code + targetOffset);
+        X86Encoding::SetRel32(code + thunkOffset, code + targetOffset);
+    }
+    static void repatchThunk(uint8_t* code, uint32_t thunkOffset, uint32_t targetOffset) {
+        X86Encoding::SetRel32(code + thunkOffset, code + targetOffset);
     }
 
     void breakpoint() {
         masm.int3();
     }
 
     static bool HasSSE2() { return CPUInfo::IsSSE2Present(); }
     static bool HasSSE3() { return CPUInfo::IsSSE3Present(); }
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -546,19 +546,25 @@ MacroAssembler::patchCall(uint32_t calle
 
 CodeOffset
 MacroAssembler::thunkWithPatch()
 {
     return Assembler::thunkWithPatch();
 }
 
 void
-MacroAssembler::patchThunk(uint32_t jumpOffset, uint32_t targetOffset)
+MacroAssembler::patchThunk(uint32_t thunkOffset, uint32_t targetOffset)
 {
-    Assembler::patchThunk(jumpOffset, targetOffset);
+    Assembler::patchThunk(thunkOffset, targetOffset);
+}
+
+void
+MacroAssembler::repatchThunk(uint8_t* code, uint32_t thunkOffset, uint32_t targetOffset)
+{
+    Assembler::repatchThunk(code, thunkOffset, targetOffset);
 }
 
 void
 MacroAssembler::callAndPushReturnAddress(Register reg)
 {
     call(reg);
 }
 
--- a/js/src/jsapi-tests/testGCExactRooting.cpp
+++ b/js/src/jsapi-tests/testGCExactRooting.cpp
@@ -90,17 +90,17 @@ BEGIN_TEST(testGCRootedStaticStructInter
     obj = nullptr;
     val = UndefinedValue();
 
     {
         JS::RootedString actual(cx);
         bool same;
 
         // Automatic move from stack to heap.
-        JS::PersistentRooted<MyContainer> heap(cx, container);
+        JS::PersistentRooted<MyContainer> heap(rt, container);
 
         // clear prior rooting.
         container.obj() = nullptr;
         container.str() = nullptr;
 
         obj = heap.obj();
         CHECK(JS_GetProperty(cx, obj, "foo", &val));
         actual = val.toString();
@@ -120,16 +120,52 @@ BEGIN_TEST(testGCRootedStaticStructInter
         obj = nullptr;
         actual = nullptr;
     }
 
     return true;
 }
 END_TEST(testGCRootedStaticStructInternalStackStorageAugmented)
 
+static JS::PersistentRooted<JSObject*> sLongLived;
+BEGIN_TEST(testGCPersistentRootedOutlivesRuntime)
+{
+    JSContext* cx2 = JS_NewContext(rt, 8192);
+    CHECK(cx2);
+
+    sLongLived.init(cx2, JS_NewObject(cx, nullptr));
+    CHECK(sLongLived);
+
+    JS_DestroyContext(cx2);
+    CHECK(!sLongLived);
+
+    return true;
+}
+END_TEST(testGCPersistentRootedOutlivesRuntime)
+
+// Unlike the above, the following test is an example of an invalid usage: for
+// performance and simplicity reasons, PersistentRooted<Traceable> is not
+// allowed to outlive the container it belongs to. The following commented out
+// test can be used to verify that the relevant assertion fires as expected.
+static JS::PersistentRooted<MyContainer> sContainer;
+BEGIN_TEST(testGCPersistentRootedTraceableCannotOutliveRuntime)
+{
+    JS::Rooted<MyContainer> container(cx);
+    container.obj() = JS_NewObject(cx, nullptr);
+    container.str() = JS_NewStringCopyZ(cx, "Hello");
+    sContainer.init(rt, container);
+
+    // Commenting the following line will trigger an assertion that the
+    // PersistentRooted outlives the runtime it is attached to.
+    sContainer.reset();
+
+    return true;
+}
+END_TEST(testGCPersistentRootedTraceableCannotOutliveRuntime)
+
 using MyHashMap = js::GCHashMap<js::Shape*, JSObject*>;
 
 BEGIN_TEST(testGCRootedHashMap)
 {
     JS::Rooted<MyHashMap> map(cx, MyHashMap(cx));
     CHECK(map.init(15));
     CHECK(map.initialized());
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5188,24 +5188,47 @@ JS_Stringify(JSContext* cx, MutableHandl
              HandleValue space, JSONWriteCallback callback, void* data)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, replacer, space);
     StringBuffer sb(cx);
     if (!sb.ensureTwoByteChars())
         return false;
-    if (!Stringify(cx, vp, replacer, space, sb))
+    if (!Stringify(cx, vp, replacer, space, sb, StringifyBehavior::Normal))
         return false;
     if (sb.empty() && !sb.append(cx->names().null))
         return false;
     return callback(sb.rawTwoByteBegin(), sb.length(), data);
 }
 
 JS_PUBLIC_API(bool)
+JS::ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input,
+                      JSONWriteCallback callback, void* data)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, input);
+
+    StringBuffer sb(cx);
+    if (!sb.ensureTwoByteChars())
+        return false;
+
+    RootedValue inputValue(cx, ObjectValue(*input));
+    if (!Stringify(cx, &inputValue, nullptr, NullHandleValue, sb,
+                   StringifyBehavior::RestrictedSafe))
+        return false;
+
+    if (sb.empty() && !sb.append(cx->names().null))
+        return false;
+
+    return callback(sb.rawTwoByteBegin(), sb.length(), data);
+}
+
+JS_PUBLIC_API(bool)
 JS_ParseJSON(JSContext* cx, const char16_t* chars, uint32_t len, MutableHandleValue vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len), NullHandleValue, vp);
 }
 
 JS_PUBLIC_API(bool)
@@ -5861,16 +5884,23 @@ JS_SetGlobalJitCompilerOption(JSRuntime*
         if (value == 1) {
             rt->setCanUseSignalHandlers(true);
             JitSpew(js::jit::JitSpew_IonScripts, "Enable signals");
         } else if (value == 0) {
             rt->setCanUseSignalHandlers(false);
             JitSpew(js::jit::JitSpew_IonScripts, "Disable signals");
         }
         break;
+      case JSJITCOMPILER_JUMP_THRESHOLD:
+        if (value == uint32_t(-1)) {
+            jit::DefaultJitOptions defaultValues;
+            value = defaultValues.jumpThreshold;
+        }
+        jit::JitOptions.jumpThreshold = value;
+        break;
       default:
         break;
     }
 }
 
 JS_PUBLIC_API(int)
 JS_GetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4749,16 +4749,41 @@ typedef bool (* JSONWriteCallback)(const
 
 /**
  * JSON.stringify as specified by ES5.
  */
 JS_PUBLIC_API(bool)
 JS_Stringify(JSContext* cx, JS::MutableHandleValue value, JS::HandleObject replacer,
              JS::HandleValue space, JSONWriteCallback callback, void* data);
 
+namespace JS {
+
+/**
+ * An API akin to JS_Stringify but with the goal of not having observable
+ * side-effects when the stringification is performed.  This means it does not
+ * allow a replacer or a custom space, and has the following constraints on its
+ * input:
+ *
+ * 1) The input must be a plain object or array, not an abitrary value.
+ * 2) Every value in the graph reached by the algorithm starting with this
+ *    object must be one of the following: null, undefined, a string (NOT a
+ *    string object!), a boolean, a finite number (i.e. no NaN or Infinity or
+ *    -Infinity), a plain object with no accessor properties, or an Array with
+ *    no holes.
+ *
+ * The actual behavior differs from JS_Stringify only in asserting the above and
+ * NOT attempting to get the "toJSON" property from things, since that could
+ * clearly have side-effects.
+ */
+JS_PUBLIC_API(bool)
+ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input,
+                  JSONWriteCallback callback, void* data);
+
+} /* namespace JS */
+
 /**
  * JSON.parse as specified by ES5.
  */
 JS_PUBLIC_API(bool)
 JS_ParseJSON(JSContext* cx, const char16_t* chars, uint32_t len, JS::MutableHandleValue vp);
 
 JS_PUBLIC_API(bool)
 JS_ParseJSON(JSContext* cx, JS::HandleString str, JS::MutableHandleValue vp);
@@ -5277,17 +5302,18 @@ JS_SetOffthreadIonCompilationEnabled(JSR
 #define JIT_COMPILER_OPTIONS(Register)                                     \
     Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger")           \
     Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger")                     \
     Register(ION_GVN_ENABLE, "ion.gvn.enable")                             \
     Register(ION_FORCE_IC, "ion.forceinlineCaches")                        \
     Register(ION_ENABLE, "ion.enable")                                     \
     Register(BASELINE_ENABLE, "baseline.enable")                           \
     Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
-    Register(SIGNALS_ENABLE, "signals.enable")
+    Register(SIGNALS_ENABLE, "signals.enable")                             \
+    Register(JUMP_THRESHOLD, "jump-threshold")
 
 typedef enum JSJitCompilerOption {
 #define JIT_COMPILER_DECLARE(key, str) \
     JSJITCOMPILER_ ## key,
 
     JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE)
 #undef JIT_COMPILER_DECLARE
 
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -695,46 +695,67 @@ ParseDigitsN(size_t n, size_t* result, c
 
     if (ParseDigits(result, s, i, Min(limit, init + n)))
         return (*i - init) == n;
 
     *i = init;
     return false;
 }
 
+/*
+ * Read and convert n or less decimal digits from s[*i]
+ * to s[min(*i+n,limit)] into *result.
+ *
+ * Succeed only if greater than zero but less than or equal to n digits are
+ * converted. Advance *i only on success.
+ */
+template <typename CharT>
+static bool
+ParseDigitsNOrLess(size_t n, size_t* result, const CharT* s, size_t* i, size_t limit)
+{
+    size_t init = *i;
+
+    if (ParseDigits(result, s, i, Min(limit, init + n)))
+        return ((*i - init) > 0) && ((*i - init) <= n);
+
+    *i = init;
+    return false;
+}
+
 static int
 DaysInMonth(int year, int month)
 {
     bool leap = IsLeapYear(year);
     int result = int(DayFromMonth(month, leap) - DayFromMonth(month - 1, leap));
     return result;
 }
 
 /*
  * Parse a string in one of the date-time formats given by the W3C
  * "NOTE-datetime" specification. These formats make up a restricted
  * profile of the ISO 8601 format. Quoted here:
  *
- *   The formats are as follows. Exactly the components shown here
- *   must be present, with exactly this punctuation. Note that the "T"
- *   appears literally in the string, to indicate the beginning of the
- *   time element, as specified in ISO 8601.
- *
  *   Any combination of the date formats with the time formats is
  *   allowed, and also either the date or the time can be missing.
  *
  *   The specification is silent on the meaning when fields are
  *   ommitted so the interpretations are a guess, but hopefully a
  *   reasonable one. We default the month to January, the day to the
  *   1st, and hours minutes and seconds all to 0. If the date is
  *   missing entirely then we assume 1970-01-01 so that the time can
  *   be aded to a date later. If the time is missing then we assume
  *   00:00 UTC.  If the time is present but the time zone field is
  *   missing then we use local time.
  *
+ * For the sake of cross compatibility with other implementations we
+ * make a few exceptions to the standard: months, days, hours, minutes
+ * and seconds may be either one or two digits long, and the 'T' from
+ * the time part may be replaced with a space. Given that, a date time
+ * like "1999-1-1 1:1:1" will parse successfully.
+ *
  * Date part:
  *
  *  Year:
  *     YYYY (eg 1997)
  *
  *  Year and month:
  *     YYYY-MM (eg 1997-07)
  *
@@ -750,27 +771,27 @@ DaysInMonth(int year, int month)
  *     Thh:mm:ssTZD (eg T19:20:30+01:00)
  *
  *  Hours, minutes, seconds and a decimal fraction of a second:
  *     Thh:mm:ss.sTZD (eg T19:20:30.45+01:00)
  *
  * where:
  *
  *   YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
- *   MM   = two-digit month (01=January, etc.)
- *   DD   = two-digit day of month (01 through 31)
- *   hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
- *   mm   = two digits of minute (00 through 59)
- *   ss   = two digits of second (00 through 59)
+ *   MM   = one or two-digit month (01=January, etc.)
+ *   DD   = one or two-digit day of month (01 through 31)
+ *   hh   = one or two digits of hour (00 through 23) (am/pm NOT allowed)
+ *   mm   = one or two digits of minute (00 through 59)
+ *   ss   = one or two digits of second (00 through 59)
  *   s    = one or more digits representing a decimal fraction of a second
  *   TZD  = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
  */
 template <typename CharT>
 static bool
-ParseISODate(const CharT* s, size_t length, ClippedTime* result)
+ParseISOStyleDate(const CharT* s, size_t length, ClippedTime* result)
 {
     size_t i = 0;
     int tzMul = 1;
     int dateMul = 1;
     size_t year = 1970;
     size_t month = 1;
     size_t day = 1;
     size_t hour = 0;
@@ -790,38 +811,45 @@ ParseISODate(const CharT* s, size_t leng
     if (i >= length || s[i] != ch) { goto done_date; } else { ++i; }
 
 #define DONE_UNLESS(ch)                                                        \
     if (i >= length || s[i] != ch) { goto done; } else { ++i; }
 
 #define NEED_NDIGITS(n, field)                                                 \
     if (!ParseDigitsN(n, &field, s, &i, length)) { return false; }
 
+#define NEED_NDIGITS_OR_LESS(n, field)                                         \
+    if (!ParseDigitsNOrLess(n, &field, s, &i, length)) { return false; }
+
     if (PEEK('+') || PEEK('-')) {
         if (PEEK('-'))
             dateMul = -1;
         ++i;
         NEED_NDIGITS(6, year);
     } else if (!PEEK('T')) {
         NEED_NDIGITS(4, year);
     }
     DONE_DATE_UNLESS('-');
-    NEED_NDIGITS(2, month);
+    NEED_NDIGITS_OR_LESS(2, month);
     DONE_DATE_UNLESS('-');
-    NEED_NDIGITS(2, day);
+    NEED_NDIGITS_OR_LESS(2, day);
 
  done_date:
-    DONE_UNLESS('T');
-    NEED_NDIGITS(2, hour);
+    if (PEEK('T') || PEEK(' '))
+        i++;
+    else
+        goto done;
+
+    NEED_NDIGITS_OR_LESS(2, hour);
     NEED(':');
-    NEED_NDIGITS(2, min);
+    NEED_NDIGITS_OR_LESS(2, min);
 
     if (PEEK(':')) {
         ++i;
-        NEED_NDIGITS(2, sec);
+        NEED_NDIGITS_OR_LESS(2, sec);
         if (PEEK('.')) {
             ++i;
             if (!ParseFractional(&frac, s, &i, length))
                 return false;
         }
     }
 
     if (PEEK('Z')) {
@@ -877,17 +905,17 @@ ParseISODate(const CharT* s, size_t leng
 #undef DONE_UNLESS
 #undef NEED_NDIGITS
 }
 
 template <typename CharT>
 static bool
 ParseDate(const CharT* s, size_t length, ClippedTime* result)
 {
-    if (ParseISODate(s, length, result))
+    if (ParseISOStyleDate(s, length, result))
         return true;
 
     if (length == 0)
         return false;
 
     int year = -1;
     int mon = -1;
     int mday = -1;
--- a/js/src/jsdtoa.cpp
+++ b/js/src/jsdtoa.cpp
@@ -44,16 +44,17 @@ using namespace js;
  * MALLOC gets declared external, and that doesn't work for class members, so
  * wrap.
  */
 static inline void* dtoa_malloc(size_t size) { return js_malloc(size); }
 static inline void dtoa_free(void* p) { return js_free(p); }
 
 #define NO_GLOBAL_STATE
 #define NO_ERRNO
+#define Omit_Private_Memory // This saves memory for the workloads we see.
 #define MALLOC dtoa_malloc
 #define FREE dtoa_free
 #include "dtoa.c"
 
 /* Mapping of JSDToStrMode -> js_dtoa mode */
 static const uint8_t dtoaModes[] = {
     0,   /* DTOSTR_STANDARD */
     0,   /* DTOSTR_STANDARD_EXPONENTIAL, */
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -127,35 +127,41 @@ Quote(JSContext* cx, StringBuffer& sb, J
 }
 
 namespace {
 
 class StringifyContext
 {
   public:
     StringifyContext(JSContext* cx, StringBuffer& sb, const StringBuffer& gap,
-                     HandleObject replacer, const AutoIdVector& propertyList)
+                     HandleObject replacer, const AutoIdVector& propertyList,
+                     bool maybeSafely)
       : sb(sb),
         gap(gap),
         replacer(cx, replacer),
         stack(cx, GCHashSet<JSObject*, MovableCellHasher<JSObject*>>(cx)),
         propertyList(propertyList),
-        depth(0)
-    {}
+        depth(0),
+        maybeSafely(maybeSafely)
+    {
+        MOZ_ASSERT_IF(maybeSafely, !replacer);
+        MOZ_ASSERT_IF(maybeSafely, gap.empty());
+    }
 
     bool init() {
         return stack.init(8);
     }
 
     StringBuffer& sb;
     const StringBuffer& gap;
     RootedObject replacer;
     Rooted<GCHashSet<JSObject*, MovableCellHasher<JSObject*>>> stack;
     const AutoIdVector& propertyList;
     uint32_t depth;
+    bool maybeSafely;
 };
 
 } /* anonymous namespace */
 
 static bool Str(JSContext* cx, const Value& v, StringifyContext* scx);
 
 static bool
 WriteIndent(JSContext* cx, StringifyContext* scx, uint32_t limit)
@@ -207,16 +213,21 @@ class KeyStringifier<HandleId> {
 /*
  * ES5 15.12.3 Str, steps 2-4, extracted to enable preprocessing of property
  * values when stringifying objects in JO.
  */
 template<typename KeyType>
 static bool
 PreprocessValue(JSContext* cx, HandleObject holder, KeyType key, MutableHandleValue vp, StringifyContext* scx)
 {
+    // We don't want to do any preprocessing here if scx->maybeSafely,
+    // since the stuff we do here can have side-effects.
+    if (scx->maybeSafely)
+        return true;
+
     RootedString keyStr(cx);
 
     /* Step 2. */
     if (vp.isObject()) {
         RootedValue toJSON(cx);
         RootedObject obj(cx, &vp.toObject());
         if (!GetProperty(cx, obj, obj, cx->names().toJSON, &toJSON))
             return false;
@@ -337,16 +348,18 @@ JO(JSContext* cx, HandleObject obj, Stri
      *
      *   * The algorithm is somewhat reformulated to allow the final string to
      *     be streamed into a single buffer, rather than be created and copied
      *     into place incrementally as the ES5 algorithm specifies it.  This
      *     requires moving portions of the Str call in 8a into this algorithm
      *     (and in JA as well).
      */
 
+    MOZ_ASSERT_IF(scx->maybeSafely, obj->is<PlainObject>());
+
     /* Steps 1-2, 11. */
     CycleDetector detect(scx, obj);
     if (!detect.foundCycle(cx))
         return false;
 
     if (!scx->sb.append('{'))
         return false;
 
@@ -379,16 +392,24 @@ JO(JSContext* cx, HandleObject obj, Stri
          * Steps 8a-8b.  Note that the call to Str is broken up into 1) getting
          * the property; 2) processing for toJSON, calling the replacer, and
          * handling boxed Number/String/Boolean objects; 3) filtering out
          * values which process to |undefined|, and 4) stringifying all values
          * which pass the filter.
          */
         id = propertyList[i];
         RootedValue outputValue(cx);
+#ifdef DEBUG
+        if (scx->maybeSafely) {
+            RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
+            RootedShape prop(cx);
+            NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop);
+            MOZ_ASSERT(prop && prop->isDataDescriptor());
+        }
+#endif // DEBUG
         if (!GetProperty(cx, obj, obj, id, &outputValue))
             return false;
         if (!PreprocessValue(cx, obj, HandleId(id), &outputValue, scx))
             return false;
         if (IsFilteredValue(outputValue))
             continue;
 
         /* Output a comma unless this is the first member to write. */
@@ -455,16 +476,37 @@ JA(JSContext* cx, HandleObject obj, Stri
         RootedValue outputValue(cx);
         for (uint32_t i = 0; i < length; i++) {
             /*
              * Steps 8a-8c.  Again note how the call to the spec's Str method
              * is broken up into getting the property, running it past toJSON
              * and the replacer and maybe unboxing, and interpreting some
              * values as |null| in separate steps.
              */
+#ifdef DEBUG
+            if (scx->maybeSafely) {
+                /*
+                 * Trying to do a JS_AlreadyHasOwnElement runs the risk of
+                 * hitting OOM on jsid creation.  Let's just assert sanity for
+                 * small enough indices.
+                 */
+                MOZ_ASSERT(obj->is<ArrayObject>());
+                MOZ_ASSERT(obj->is<NativeObject>());
+                RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
+                if (i <= JSID_INT_MAX) {
+                    MOZ_ASSERT(nativeObj->containsDenseElement(i) != nativeObj->isIndexed(),
+                               "the array must either be small enough to remain "
+                               "fully dense (and otherwise un-indexed), *or* "
+                               "all its initially-dense elements were sparsified "
+                               "and the object is indexed");
+                } else {
+                    MOZ_ASSERT(obj->isIndexed());
+                }
+            }
+#endif
             if (!GetElement(cx, obj, obj, i, &outputValue))
                 return false;
             if (!PreprocessValue(cx, obj, i, &outputValue, scx))
                 return false;
             if (IsFilteredValue(outputValue)) {
                 if (!scx->sb.append("null"))
                     return false;
             } else {
@@ -520,45 +562,63 @@ Str(JSContext* cx, const Value& v, Strin
 
     /* Steps 6-7. */
     if (v.isBoolean())
         return v.toBoolean() ? scx->sb.append("true") : scx->sb.append("false");
 
     /* Step 9. */
     if (v.isNumber()) {
         if (v.isDouble()) {
-            if (!IsFinite(v.toDouble()))
+            if (!IsFinite(v.toDouble())) {
+                MOZ_ASSERT(!scx->maybeSafely,
+                           "input JS::ToJSONMaybeSafely must not include "
+                           "reachable non-finite numbers");
                 return scx->sb.append("null");
+            }
         }
 
         return NumberValueToStringBuffer(cx, v, scx->sb);
     }
 
     /* Step 10. */
     MOZ_ASSERT(v.isObject());
     RootedObject obj(cx, &v.toObject());
 
+    MOZ_ASSERT(!scx->maybeSafely || obj->is<PlainObject>() || obj->is<ArrayObject>(),
+               "input to JS::ToJSONMaybeSafely must not include reachable "
+               "objects that are neither arrays nor plain objects");
+
     scx->depth++;
     auto dec = mozilla::MakeScopeExit([&] { scx->depth--; });
 
     bool isArray;
     if (!IsArray(cx, obj, &isArray))
         return false;
 
     return isArray ? JA(cx, obj, scx) : JO(cx, obj, scx);
 }
 
 /* ES6 24.3.2. */
 bool
 js::Stringify(JSContext* cx, MutableHandleValue vp, JSObject* replacer_, Value space_,
-              StringBuffer& sb)
+              StringBuffer& sb, StringifyBehavior stringifyBehavior)
 {
     RootedObject replacer(cx, replacer_);
     RootedValue space(cx, space_);
 
+    MOZ_ASSERT_IF(stringifyBehavior == StringifyBehavior::RestrictedSafe, space.isNull());
+    MOZ_ASSERT_IF(stringifyBehavior == StringifyBehavior::RestrictedSafe, vp.isObject());
+    /**
+     * This uses MOZ_ASSERT, since it's actually asserting something jsapi
+     * consumers could get wrong, so needs a better error message.
+     */
+    MOZ_ASSERT(stringifyBehavior == StringifyBehavior::Normal ||
+               vp.toObject().is<PlainObject>() || vp.toObject().is<ArrayObject>(),
+               "input to JS::ToJSONMaybeSafely must be a plain object or array");
+
     /* Step 4. */
     AutoIdVector propertyList(cx);
     if (replacer) {
         bool isArray;
         if (replacer->isCallable()) {
             /* Step 4a(i): use replacer to transform values.  */
         } else if (!IsArray(cx, replacer, &isArray)) {
             return false;
@@ -686,17 +746,18 @@ js::Stringify(JSContext* cx, MutableHand
         return false;
 
     /* Steps 10-11. */
     RootedId emptyId(cx, NameToId(cx->names().empty));
     if (!NativeDefineProperty(cx, wrapper, emptyId, vp, nullptr, nullptr, JSPROP_ENUMERATE))
         return false;
 
     /* Step 12. */
-    StringifyContext scx(cx, sb, gap, replacer, propertyList);
+    StringifyContext scx(cx, sb, gap, replacer, propertyList,
+                         stringifyBehavior == StringifyBehavior::RestrictedSafe);
     if (!scx.init())
         return false;
     if (!PreprocessValue(cx, wrapper, HandleId(emptyId), vp, &scx))
         return false;
     if (IsFilteredValue(vp))
         return true;
 
     return Str(cx, vp, &scx);
@@ -885,17 +946,17 @@ json_stringify(JSContext* cx, unsigned a
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject replacer(cx, args.get(1).isObject() ? &args[1].toObject() : nullptr);
     RootedValue value(cx, args.get(0));
     RootedValue space(cx, args.get(2));
 
     StringBuffer sb(cx);
-    if (!Stringify(cx, &value, replacer, space, sb))
+    if (!Stringify(cx, &value, replacer, space, sb, StringifyBehavior::Normal))
         return false;
 
     // XXX This can never happen to nsJSON.cpp, but the JSON object
     // needs to support returning undefined. So this is a little awkward
     // for the API, because we want to support streaming writers.
     if (!sb.empty()) {
         JSString* str = sb.finishString();
         if (!str)
--- a/js/src/json.h
+++ b/js/src/json.h
@@ -14,19 +14,29 @@
 #include "js/RootingAPI.h"
 
 namespace js {
 class StringBuffer;
 
 extern JSObject*
 InitJSONClass(JSContext* cx, HandleObject obj);
 
+enum class StringifyBehavior {
+    Normal,
+    RestrictedSafe
+};
+
+/**
+ * If maybeSafely is true, Stringify will attempt to assert the API requirements
+ * of JS::ToJSONMaybeSafely as it traverses the graph, and will not try to
+ * invoke .toJSON on things as it goes.
+ */
 extern bool
 Stringify(JSContext* cx, js::MutableHandleValue vp, JSObject* replacer,
-          Value space, StringBuffer& sb);
+          Value space, StringBuffer& sb, StringifyBehavior stringifyBehavior);
 
 template <typename CharT>
 extern bool
 ParseJSONWithReviver(JSContext* cx, const mozilla::Range<const CharT> chars,
                      HandleValue reviver, MutableHandleValue vp);
 
 } // namespace js
 
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -120,19 +120,16 @@ typedef JSConstScalarSpec<int32_t> JSCon
 /*
  * Generic trace operation that calls JS_CallTracer on each traceable thing
  * stored in data.
  */
 typedef void
 (* JSTraceDataOp)(JSTracer* trc, void* data);
 
 namespace js {
-
-void FinishGC(JSRuntime* rt);
-
 namespace gc {
 class AutoTraceSession;
 class StoreBuffer;
 } // namespace gc
 } // namespace js
 
 namespace JS {
 
@@ -287,16 +284,39 @@ class RootLists
 
   public:
     RootLists() : autoGCRooters_(nullptr) {
         for (auto& stackRootPtr : stackRoots_) {
             stackRootPtr = nullptr;
         }
     }
 
+    ~RootLists() {
+        // The semantics of PersistentRooted containing pointers and tagged
+        // pointers are somewhat different from those of PersistentRooted
+        // containing a structure with a trace method. PersistentRooted
+        // containing pointers are allowed to outlive the owning RootLists,
+        // whereas those containing a traceable structure are not.
+        //
+        // The purpose of this feature is to support lazy initialization of
+        // global references for the several places in Gecko that do not have
+        // access to a tighter context, but that still need to refer to GC
+        // pointers. For such pointers, FinishPersistentRootedChains ensures
+        // that the contained references are nulled out when the owning
+        // RootLists dies to prevent UAF errors.
+        //
+        // However, for RootKind::Traceable, we do not know the concrete type
+        // of the held thing, so we simply cannot do this without accruing
+        // extra overhead and complexity for all users for a case that is
+        // unlikely to ever be used in practice. For this reason, the following
+        // assertion disallows usage of PersistentRooted<Traceable> that
+        // outlives the RootLists.
+        MOZ_ASSERT(heapRoots_[JS::RootKind::Traceable].isEmpty());
+    }
+
     void traceStackRoots(JSTracer* trc);
     void checkNoGCRooters();
 
     void tracePersistentRoots(JSTracer* trc);
     void finishPersistentRoots();
 };
 
 struct ContextFriendFields
--- a/js/src/tests/ecma_6/Array/iterator_edge_cases.js
+++ b/js/src/tests/ecma_6/Array/iterator_edge_cases.js
@@ -2,17 +2,17 @@
 // ArrayIterator object.
 function TestArrayIteratorPrototypeConfusion() {
     var iter = [][Symbol.iterator]();
     try {
         iter.next.call(Object.getPrototypeOf(iter))
         throw new Error("Call did not throw");
     } catch (e) {
         assertEq(e instanceof TypeError, true);
-        assertEq(e.message, "CallArrayIteratorMethodIfWrapped method called on incompatible Array Iterator");
+        assertEq(e.message, "next method called on incompatible Array Iterator");
     }
 }
 TestArrayIteratorPrototypeConfusion();
 
 // Tests that we can use %ArrayIteratorPrototype%.next on a
 // cross-compartment iterator.
 function TestArrayIteratorWrappers() {
     var iter = [][Symbol.iterator]();
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Date/non-iso.js
@@ -0,0 +1,63 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommonn.org/licenses/publicdomain/
+ */
+
+/*
+ * For the sake of cross compatibility with other implementations we
+ * follow the W3C "NOTE-datetime" specification when parsing dates of
+ * the form YYYY-MM-DDTHH:MM:SS save for a few exceptions: months, days, hours
+ * minutes, and seconds may be either one _or_ two digits long, and the 'T'
+ * preceding the time part may be replaced with a space. So, a string like
+ * "1997-3-8 1:1:1" will parse successfully. See bug: 1203298
+ */
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+assertEq(new Date("1997-03-08 1:1:1.01").getTime(),
+         new Date("1997-03-08T01:01:01.01").getTime());
+assertEq(new Date("1997-03-08 11:19:20").getTime(),
+         new Date("1997-03-08T11:19:20").getTime());
+assertEq(new Date("1997-3-08 11:19:20").getTime(),
+         new Date("1997-03-08T11:19:20").getTime());
+assertEq(new Date("1997-3-8 11:19:20").getTime(),
+         new Date("1997-03-08T11:19:20").getTime());
+assertEq(new Date("1997-3-8T11:19:20").getTime(),
+         new Date("1997-03-08T11:19:20").getTime());
+assertEq(new Date("1997-03-8T11:19:20").getTime(),
+         new Date("1997-03-08T11:19:20").getTime());
+assertEq(new Date("1997-03-08 11:19").getTime(),
+         new Date("1997-03-08T11:19").getTime());
+assertEq(new Date("1997-03-08 1:19").getTime(),
+         new Date("1997-03-08T1:19").getTime());
+assertEq(new Date("1997-03-08 1:1").getTime(),
+         new Date("1997-03-08T1:1").getTime());
+assertEq(new Date("1997-03-08 1:1:01").getTime(),
+         new Date("1997-03-08T1:1:01").getTime());
+assertEq(new Date("1997-03-08 1:1:1").getTime(),
+         new Date("1997-03-08T1:1:1").getTime());
+assertEq(new Date("1997-03-08 11").getTime(),
+         new Date("1997-03-08T11").getTime());
+assertEq(new Date("1997-03-08").getTime(),
+         new Date("1997-03-08").getTime());
+assertEq(new Date("1997-03-8").getTime(),
+         new Date("1997-03-08").getTime());
+assertEq(new Date("1997-3-8").getTime(),
+         new Date("1997-03-08").getTime());
+assertEq(new Date("1997-3-8 ").getTime(),
+         new Date("1997-03-08T").getTime()); // Date(NaN)
+assertEq(new Date("1997-3-8 :00:01").getTime(),
+         new Date(NaN).getTime());
+assertEq(new Date("1997-3-8 :00:01").getTime(),
+         new Date(NaN).getTime());
+assertEq(new Date("1997-3-8 01::01").getTime(),
+         new Date(NaN).getTime());
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/tests/ecma_6/String/iterator_edge_cases.js
+++ b/js/src/tests/ecma_6/String/iterator_edge_cases.js
@@ -2,17 +2,17 @@
 // StringIterator object.
 function TestStringIteratorPrototypeConfusion() {
     var iter = ""[Symbol.iterator]();
     try {
         iter.next.call(Object.getPrototypeOf(iter))
         throw new Error("Call did not throw");
     } catch (e) {
         assertEq(e instanceof TypeError, true);
-        assertEq(e.message, "CallStringIteratorMethodIfWrapped method called on incompatible String Iterator");
+        assertEq(e.message, "next method called on incompatible String Iterator");
     }
 }
 TestStringIteratorPrototypeConfusion();
 
 // Tests that we can use %StringIteratorPrototype%.next on a
 // cross-compartment iterator.
 function TestStringIteratorWrappers() {
     var iter = ""[Symbol.iterator]();
--- a/js/src/vm/CallNonGenericMethod.cpp
+++ b/js/src/vm/CallNonGenericMethod.cpp
@@ -6,28 +6,32 @@
 
 #include "js/CallNonGenericMethod.h"
 
 #include "jsfun.h"
 #include "jsobj.h"
 
 #include "proxy/Proxy.h"
 #include "vm/ProxyObject.h"
+#include "vm/SelfHosting.h"
 
 using namespace js;
 
 bool
 JS::detail::CallMethodIfWrapped(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
                                 const CallArgs& args)
 {
     HandleValue thisv = args.thisv();
     MOZ_ASSERT(!test(thisv));
 
     if (thisv.isObject()) {
         JSObject& thisObj = args.thisv().toObject();
         if (thisObj.is<ProxyObject>())
             return Proxy::nativeCall(cx, test, impl, args);
     }
 
+    if (IsCallSelfHostedNonGenericMethod(impl))
+        return ReportIncompatibleSelfHostedMethod(cx, args);
+
     ReportIncompatible(cx, args);
     return false;
 }
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -525,18 +525,16 @@ JSRuntime::addSizeOfIncludingThis(mozill
         rtSizes->atomsTable += mallocSizeOf(staticStrings);
         rtSizes->atomsTable += mallocSizeOf(commonNames);
         rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
     }
 
     for (ContextIter acx(this); !acx.done(); acx.next())
         rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
 
-    rtSizes->dtoa += mallocSizeOf(mainThread.dtoaState);
-
     rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
 
     rtSizes->uncompressedSourceCache += uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
 
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1377,16 +1377,44 @@ Is(HandleValue v)
 template<IsAcceptableThis Test>
 static bool
 CallNonGenericSelfhostedMethod(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<Test, CallSelfHostedNonGenericMethod>(cx, args);
 }
 
+bool
+js::IsCallSelfHostedNonGenericMethod(NativeImpl impl)
+{
+    return impl == CallSelfHostedNonGenericMethod;
+}
+
+bool
+js::ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args)
+{
+    // The contract for this function is the same as CallSelfHostedNonGenericMethod.
+    // The normal ReportIncompatible function doesn't work for selfhosted functions,
+    // because they always call the different CallXXXMethodIfWrapped methods,
+    // which would be reported as the called function instead.
+
+    // Lookup the selfhosted method that was invoked.
+    ScriptFrameIter iter(cx);
+    MOZ_ASSERT(iter.isFunctionFrame());
+
+    JSAutoByteString funNameBytes;
+    if (const char* funName = GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes)) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD,
+                             funName, "method", InformalValueTypeName(args.thisv()));
+    }
+
+    return false;
+}
+
+
 /**
  * Returns the default locale as a well-formed, but not necessarily canonicalized,
  * BCP-47 language tag.
  */
 static bool
 intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
--- a/js/src/vm/SelfHosting.h
+++ b/js/src/vm/SelfHosting.h
@@ -3,26 +3,34 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef vm_SelfHosting_h_
 #define vm_SelfHosting_h_
 
 #include "jsapi.h"
+#include "NamespaceImports.h"
 
 class JSAtom;
 
 namespace js {
 
 /*
  * Check whether the given JSFunction is a self-hosted function whose
  * self-hosted name is the given name.
  */
-bool IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name);
+bool
+IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name);
+
+bool
+IsCallSelfHostedNonGenericMethod(NativeImpl impl);
+
+bool
+ReportIncompatibleSelfHostedMethod(JSContext* cx, const CallArgs& args);
 
 /* Get the compile options used when compiling self hosted code. */
 void
 FillSelfHostingCompileOptions(JS::CompileOptions& options);
 
 } /* namespace js */
 
 #endif /* vm_SelfHosting_h_ */
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -4303,16 +4303,22 @@ JSScript::maybeSweepTypes(AutoClearTypeI
 
     unsigned num = TypeScript::NumTypeSets(this);
     StackTypeSet* typeArray = types_->typeArray();
 
     // Remove constraints and references to dead objects from stack type sets.
     for (unsigned i = 0; i < num; i++)
         typeArray[i].sweep(zone(), *oom);
 
+    if (oom->hadOOM()) {
+        // It's possible we OOM'd while copying freeze constraints, so they
+        // need to be regenerated.
+        hasFreezeConstraints_ = false;
+    }
+
     // Update the recompile indexes in any IonScripts still on the script.
     if (hasIonScript())
         ionScript()->recompileInfoRef().shouldSweep(types);
 }
 
 void
 TypeScript::destroy()
 {
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -593,16 +593,19 @@ class AutoClearTypeInferenceStateOnOOM
       : zone(zone), oom(false)
     {}
 
     ~AutoClearTypeInferenceStateOnOOM();
 
     void setOOM() {
         oom = true;
     }
+    bool hadOOM() const {
+        return oom;
+    }
 };
 
 /* Superclass common to stack and heap type sets. */
 class ConstraintTypeSet : public TypeSet
 {
   public:
     /* Chain of constraints which propagate changes out from this type set. */
     TypeConstraint* constraintList;
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2480,21 +2480,16 @@ ReportJSRuntimeExplicitTreeStats(const J
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/atoms-table"),
         KIND_HEAP, rtStats.runtime.atomsTable,
         "The atoms table.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/contexts"),
         KIND_HEAP, rtStats.runtime.contexts,
         "JSContext objects and structures that belong to them.");
 
-    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/dtoa"),
-        KIND_HEAP, rtStats.runtime.dtoa,
-        "The DtoaState object, which is used for converting strings to "
-        "numbers and vice versa.");
-
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/temporary"),
         KIND_HEAP, rtStats.runtime.temporary,
         "Transient data (mostly parse nodes) held by the JSRuntime during "
         "compilation.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/interpreter-stack"),
         KIND_HEAP, rtStats.runtime.interpreterStack,
         "JS interpreter frames.");
--- a/layout/base/FramePropertyTable.cpp
+++ b/layout/base/FramePropertyTable.cpp
@@ -118,17 +118,20 @@ FramePropertyTable::RemoveInternal(
   }
   Entry* entry = mLastEntry;
   if (!entry)
     return nullptr;
 
   if (entry->mProp.mProperty == aProperty) {
     // There's only one entry and it's the one we want
     void* value = entry->mProp.mValue;
-    mEntries.RawRemoveEntry(entry);
+
+    // Here it's ok to use RemoveEntry() -- which may resize mEntries --
+    // because we null mLastEntry at the same time.
+    mEntries.RemoveEntry(entry);
     mLastEntry = nullptr;
     if (aFoundResult) {
       *aFoundResult = true;
     }
     return value;
   }
   if (!entry->mProp.IsArray()) {
     // There's just one property and it's not the one we want, bail
@@ -204,16 +207,19 @@ FramePropertyTable::DeleteAllFor(const n
   if (mLastFrame == aFrame) {
     // Flush cache. We assume DeleteAllForEntry will be called before
     // a frame is destroyed.
     mLastFrame = nullptr;
     mLastEntry = nullptr;
   }
 
   DeleteAllForEntry(entry);
+
+  // mLastEntry points into mEntries, so we use RawRemoveEntry() which will not
+  // resize mEntries.
   mEntries.RawRemoveEntry(entry);
 }
 
 void
 FramePropertyTable::DeleteAll()
 {
   mLastFrame = nullptr;
   mLastEntry = nullptr;
--- a/layout/base/FramePropertyTable.h
+++ b/layout/base/FramePropertyTable.h
@@ -331,16 +331,19 @@ protected:
       return mProp.SizeOfExcludingThis(aMallocSizeOf);
     }
 
     PropertyValue mProp;
   };
 
   static void DeleteAllForEntry(Entry* aEntry);
 
+  // Note that mLastEntry points into mEntries, so we need to be careful about
+  // not triggering a resize of mEntries, e.g. use RawRemoveEntry() instead of
+  // RemoveEntry() in some places.
   nsTHashtable<Entry> mEntries;
   const nsIFrame* mLastFrame;
   Entry* mLastEntry;
 };
 
 /**
  * This class encapsulates the properties of a frame.
  */
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -5636,17 +5636,17 @@ nsCSSFrameConstructor::AddFrameConstruct
       }
       return;
     }
   }
 
   // When constructing a child of a non-open <details>, create only the frame
   // for the main <summary> element, and skip other elements.
   auto* details = HTMLDetailsElement::FromContentOrNull(parent);
-  if (details && !details->Open()) {
+  if (details && details->IsDetailsEnabled() && !details->Open()) {
     auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
     if (!summary || !summary->IsMainSummary()) {
       SetAsUndisplayedContent(aState, aItems, aContent, styleContext,
                               isGeneratedContent);
       return;
     }
   }
 
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -344,17 +344,17 @@ static void AddTransformFunctions(nsCSSV
       }
       default:
         NS_ERROR("Function not handled yet!");
     }
   }
 }
 
 static TimingFunction
-ToTimingFunction(Maybe<ComputedTimingFunction> aCTF)
+ToTimingFunction(const Maybe<ComputedTimingFunction>& aCTF)
 {
   if (aCTF.isNothing()) {
     return TimingFunction(null_t());
   }
 
   if (aCTF->HasSpline()) {
     const nsSMILKeySpline* spline = aCTF->GetFunction();
     return TimingFunction(CubicBezierFunction(spline->X1(), spline->Y1(),
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -8576,16 +8576,24 @@ nsLayoutUtils::SetScrollPositionClamping
   // layout depends on the size of the screen.  Since when the size
   // of the screen changes, the scroll position clamping scroll port
   // size also changes, we hook in the needed updates here rather
   // than adding a separate notification just for this change.
   nsPresContext* presContext = aPresShell->GetPresContext();
   MaybeReflowForInflationScreenSizeChange(presContext);
 }
 
+/* static */ bool
+nsLayoutUtils::CanScrollOriginClobberApz(nsIAtom* aScrollOrigin)
+{
+  return aScrollOrigin != nullptr
+      && aScrollOrigin != nsGkAtoms::apz
+      && aScrollOrigin != nsGkAtoms::restore;
+}
+
 /* static */ FrameMetrics
 nsLayoutUtils::ComputeFrameMetrics(nsIFrame* aForFrame,
                                    nsIFrame* aScrollFrame,
                                    nsIContent* aContent,
                                    const nsIFrame* aReferenceFrame,
                                    Layer* aLayer,
                                    ViewID aScrollParentId,
                                    const nsRect& aViewport,
@@ -8632,21 +8640,20 @@ nsLayoutUtils::ComputeFrameMetrics(nsIFr
 
   if (scrollableFrame) {
     nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
     metrics.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition));
 
     nsPoint smoothScrollPosition = scrollableFrame->LastScrollDestination();
     metrics.SetSmoothScrollOffset(CSSPoint::FromAppUnits(smoothScrollPosition));
 
-    // If the frame was scrolled since the last layers update, and by
-    // something other than the APZ code, we want to tell the APZ to update
+    // If the frame was scrolled since the last layers update, and by something
+    // that is higher priority than APZ, we want to tell the APZ to update
     // its scroll offset.
-    nsIAtom* lastScrollOrigin = scrollableFrame->LastScrollOrigin();
-    if (lastScrollOrigin && lastScrollOrigin != nsGkAtoms::apz) {
+    if (CanScrollOriginClobberApz(scrollableFrame->LastScrollOrigin())) {
       metrics.SetScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
     }
     nsIAtom* lastSmoothScrollOrigin = scrollableFrame->LastSmoothScrollOrigin();
     if (lastSmoothScrollOrigin) {
       metrics.SetSmoothScrollOffsetUpdated(scrollableFrame->CurrentScrollGeneration());
     }
 
     nsSize lineScrollAmount = scrollableFrame->GetLineScrollAmount();
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2717,16 +2717,25 @@ public:
   /**
    * Set the scroll port size for the purpose of clamping the scroll position
    * for the root scroll frame of this document
    * (see nsIDOMWindowUtils.setScrollPositionClampingScrollPortSize).
    */
   static void SetScrollPositionClampingScrollPortSize(nsIPresShell* aPresShell,
                                                       CSSSize aSize);
 
+  /**
+   * Returns true if the given scroll origin is "higher priority" than APZ.
+   * In general any content programmatic scrolls (e.g. scrollTo calls) are
+   * higher priority, and take precedence over APZ scrolling. This function
+   * returns true for those, and returns false for other origins like APZ
+   * itself, or scroll position updates from the history restore code.
+   */
+  static bool CanScrollOriginClobberApz(nsIAtom* aScrollOrigin);
+
   static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame,
                                           nsIFrame* aScrollFrame,
                                           nsIContent* aContent,
                                           const nsIFrame* aReferenceFrame,
                                           Layer* aLayer,
                                           ViewID aScrollParentId,
                                           const nsRect& aViewport,
                                           const mozilla::Maybe<nsRect>& aClipRect,
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1474,56 +1474,56 @@ nsRefreshDriver::DispatchPendingEvents()
   nsTArray<PendingEvent> pendingEvents(Move(mPendingEvents));
   for (PendingEvent& event : pendingEvents) {
     bool dummy;
     event.mTarget->DispatchEvent(event.mEvent, &dummy);
   }
 }
 
 static bool
-DispatchAnimationEventsOnSubDocuments(nsIDocument* aDocument,
-                                      void* aRefreshDriver)
+CollectDocuments(nsIDocument* aDocument, void* aDocArray)
 {
-  nsIPresShell* shell = aDocument->GetShell();
-  if (!shell) {
-    return true;
-  }
-
-  RefPtr<nsPresContext> context = shell->GetPresContext();
-  if (!context || context->RefreshDriver() != aRefreshDriver) {
-    return true;
-  }
-
-  nsCOMPtr<nsIDocument> kungFuDeathGrip(aDocument);
-
-  context->TransitionManager()->SortEvents();
-  context->AnimationManager()->SortEvents();
-
-  // Dispatch transition events first since transitions conceptually sit
-  // below animations in terms of compositing order.
-  context->TransitionManager()->DispatchEvents();
-  // Check that the presshell has not been destroyed
-  if (context->GetPresShell()) {
-    context->AnimationManager()->DispatchEvents();
-  }
-
-  aDocument->EnumerateSubDocuments(DispatchAnimationEventsOnSubDocuments,
-                                   aRefreshDriver);
-
+  static_cast<nsCOMArray<nsIDocument>*>(aDocArray)->AppendObject(aDocument);
+  aDocument->EnumerateSubDocuments(CollectDocuments, aDocArray);
   return true;
 }
 
 void
 nsRefreshDriver::DispatchAnimationEvents()
 {
   if (!mPresContext) {
     return;
   }
 
-  DispatchAnimationEventsOnSubDocuments(mPresContext->Document(), this);
+  nsCOMArray<nsIDocument> documents;
+  CollectDocuments(mPresContext->Document(), &documents);
+
+  for (int32_t i = 0; i < documents.Count(); ++i) {
+    nsIDocument* doc = documents[i];
+    nsIPresShell* shell = doc->GetShell();
+    if (!shell) {
+      continue;
+    }
+
+    RefPtr<nsPresContext> context = shell->GetPresContext();
+    if (!context || context->RefreshDriver() != this) {
+      continue;
+    }
+
+    context->TransitionManager()->SortEvents();
+    context->AnimationManager()->SortEvents();
+
+    // Dispatch transition events first since transitions conceptually sit
+    // below animations in terms of compositing order.
+    context->TransitionManager()->DispatchEvents();
+    // Check that the presshell has not been destroyed
+    if (context->GetPresShell()) {
+      context->AnimationManager()->DispatchEvents();
+    }
+  }
 }
 
 void
 nsRefreshDriver::RunFrameRequestCallbacks(TimeStamp aNowTime)
 {
   // Grab all of our frame request callbacks up front.
   nsTArray<DocumentFrameCallbacks>
     frameRequestCallbacks(mFrameRequestCallbackDocs.Length() +
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -317,17 +317,18 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(Exception
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMSessionStorageManager)
 NS_GENERIC_FACTORY_CONSTRUCTOR(DOMLocalStorageManager)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(DOMRequestService,
                                          DOMRequestService::FactoryCreate)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(QuotaManagerService,
                                          QuotaManagerService::FactoryCreate)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ServiceWorkerManager,
                                          ServiceWorkerManager::GetInstance)
-NS_GENERIC_FACTORY_CONSTRUCTOR(WorkerDebuggerManager)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WorkerDebuggerManager,
+                                         WorkerDebuggerManager::GetInstance)
 
 #ifdef MOZ_WIDGET_GONK
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemWorkerManager,
                                          SystemWorkerManager::FactoryCreate)
 #endif
 #ifdef MOZ_B2G_BT
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(BluetoothService,
                                          BluetoothService::FactoryCreate)
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1720,19 +1720,25 @@ private:
 
 /*
  * Calculate duration, possibly dynamically according to events rate and event origin.
  * (also maintain previous timestamps - which are only used here).
  */
 void
 ScrollFrameHelper::AsyncScroll::InitPreferences(TimeStamp aTime, nsIAtom *aOrigin)
 {
-  if (!aOrigin){
+  if (!aOrigin || aOrigin == nsGkAtoms::restore) {
+    // We don't have special prefs for "restore", just treat it as "other".
+    // "restore" scrolls are (for now) always instant anyway so unless something
+    // changes we should never have aOrigin == nsGkAtoms::restore here.
     aOrigin = nsGkAtoms::other;
   }
+  // Likewise we should never get APZ-triggered scrolls here, and if that changes
+  // something is likely broken somewhere.
+  MOZ_ASSERT(aOrigin != nsGkAtoms::apz);
 
   // Read preferences only on first iteration or for a different event origin.
   if (!mIsFirstIteration && aOrigin == mOrigin) {
     return;
   }
 
   mOrigin = aOrigin;
   mOriginMinMS = mOriginMaxMS = 0;
@@ -2342,17 +2348,17 @@ RemoveDisplayPortCallback(nsITimer* aTim
   ScrollFrameHelper* helper = static_cast<ScrollFrameHelper*>(aClosure);
 
   // This function only ever gets called from the expiry timer, so it must
   // be non-null here. Set it to null here so that we don't keep resetting
   // it unnecessarily in MarkRecentlyScrolled().
   MOZ_ASSERT(helper->mDisplayPortExpiryTimer);
   helper->mDisplayPortExpiryTimer = nullptr;
 
-  if (helper->IsAlwaysActive() || helper->mIsScrollParent) {
+  if (!helper->AllowDisplayPortExpiration() || helper->mIsScrollParent) {
     // If this is a scroll parent for some other scrollable frame, don't
     // expire the displayport because it would break scroll handoff. Once the
     // descendant scrollframes have their displayports expired, they will
     // trigger the displayport expiration on this scrollframe as well, and
     // mIsScrollParent will presumably be false when that kicks in.
     return;
   }
 
@@ -2406,19 +2412,30 @@ void ScrollFrameHelper::ResetDisplayPort
 {
   if (mDisplayPortExpiryTimer) {
     mDisplayPortExpiryTimer->InitWithFuncCallback(
       RemoveDisplayPortCallback, this,
       gfxPrefs::APZDisplayPortExpiryTime(), nsITimer::TYPE_ONE_SHOT);
   }
 }
 
-void ScrollFrameHelper::TriggerDisplayPortExpiration()
+bool ScrollFrameHelper::AllowDisplayPortExpiration()
 {
   if (IsAlwaysActive()) {
+    return false;
+  }
+  if (mIsRoot && mOuter->PresContext()->IsRoot()) {
+    return false;
+  }
+  return true;
+}
+
+void ScrollFrameHelper::TriggerDisplayPortExpiration()
+{
+  if (!AllowDisplayPortExpiration()) {
     return;
   }
 
   if (!gfxPrefs::APZDisplayPortExpiryTime()) {
     // a zero time disables the expiry
     return;
   }
 
@@ -3933,17 +3950,18 @@ ScrollFrameHelper::ScrollToRestoredPosit
     // and scroll many times.
     if (mRestorePos != mLastPos /* GetLogicalScrollPosition() */) {
       nsPoint scrollToPos = mRestorePos;
       if (!IsLTR())
         // convert from logical to physical scroll position
         scrollToPos.x = mScrollPort.x -
           (mScrollPort.XMost() - scrollToPos.x - mScrolledFrame->GetRect().width);
       nsWeakFrame weakFrame(mOuter);
-      ScrollTo(scrollToPos, nsIScrollableFrame::INSTANT);
+      ScrollToWithOrigin(scrollToPos, nsIScrollableFrame::INSTANT,
+                         nsGkAtoms::restore, nullptr);
       if (!weakFrame.IsAlive()) {
         return;
       }
       // Re-get the scroll position, it might not be exactly equal to
       // mRestorePos due to rounding and clamping.
       mLastPos = GetLogicalScrollPosition();
     } else {
       // if we reached the position then stop
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -365,16 +365,17 @@ public:
   bool UsesContainerScrolling() const;
 
   bool DecideScrollableLayer(nsDisplayListBuilder* aBuilder,
                              nsRect* aDirtyRect,
                              bool aAllowCreateDisplayPort);
   void NotifyImageVisibilityUpdate();
   bool GetDisplayPortAtLastImageVisibilityUpdate(nsRect* aDisplayPort);
 
+  bool AllowDisplayPortExpiration();
   void TriggerDisplayPortExpiration();
   void ResetDisplayPortExpiryTimer();
 
   void ScheduleSyntheticMouseMove();
   static void ScrollActivityCallback(nsITimer *aTimer, void* anInstance);
 
   void HandleScrollbarStyleSwitching();
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/disabled-no-summary-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <body>
+    <div>
+      <p>This is the details.</p>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/disabled-single-summary-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <body>
+    <div>
+      <div>Summary</div>
+      <p>This is the details.</p>
+    </div>
+  </body>
+</html>
--- a/layout/reftests/details-summary/reftest.list
+++ b/layout/reftests/details-summary/reftest.list
@@ -1,8 +1,13 @@
+# Disable <details> and <summary>
+pref(dom.details_element.enabled,false) == single-summary.html disabled-single-summary-ref.html
+pref(dom.details_element.enabled,false) == open-single-summary.html disabled-single-summary-ref.html
+pref(dom.details_element.enabled,false) == no-summary.html disabled-no-summary-ref.html
+
 # Basic <summary> handling
 pref(dom.details_element.enabled,true) == multiple-summary.html single-summary.html
 pref(dom.details_element.enabled,true) == open-multiple-summary.html open-multiple-summary-ref.html
 pref(dom.details_element.enabled,true) == summary-not-first-child.html single-summary.html
 pref(dom.details_element.enabled,true) == open-summary-not-first-child.html open-single-summary.html
 pref(dom.details_element.enabled,true) == open-summary-block-style.html open-single-summary.html
 pref(dom.details_element.enabled,true) == no-summary.html no-summary-ref.html
 pref(dom.details_element.enabled,true) == open-no-summary.html open-no-summary-ref.html
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -308,17 +308,21 @@ public:
 
   /**
    * Dispatch any pending events.  We accumulate animationend and
    * animationiteration events only during refresh driver notifications
    * (and dispatch them at the end of such notifications), but we
    * accumulate animationstart events at other points when style
    * contexts are created.
    */
-  void DispatchEvents()  { mEventDispatcher.DispatchEvents(mPresContext); }
+  void DispatchEvents()
+  {
+    RefPtr<nsAnimationManager> kungFuDeathGrip(this);
+    mEventDispatcher.DispatchEvents(mPresContext);
+  }
   void SortEvents()      { mEventDispatcher.SortEvents(); }
   void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
 
   // Stop animations on the element. This method takes the real element
   // rather than the element for the generated content for animations on
   // ::before and ::after.
   void StopAnimationsForElement(mozilla::dom::Element* aElement,
                                 nsCSSPseudoElements::Type aPseudoType);
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -301,17 +301,21 @@ public:
   }
 
   void QueueEvent(mozilla::TransitionEventInfo&& aEventInfo)
   {
     mEventDispatcher.QueueEvent(
       mozilla::Forward<mozilla::TransitionEventInfo>(aEventInfo));
   }
 
-  void DispatchEvents()  { mEventDispatcher.DispatchEvents(mPresContext); }
+  void DispatchEvents()
+  {
+    RefPtr<nsTransitionManager> kungFuDeathGrip(this);
+    mEventDispatcher.DispatchEvents(mPresContext);
+  }
   void SortEvents()      { mEventDispatcher.SortEvents(); }
   void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
 
 protected:
   virtual ~nsTransitionManager() {}
 
   virtual nsIAtom* GetAnimationsAtom() override {
     return nsGkAtoms::transitionsProperty;
--- a/layout/tools/reftest/Makefile.in
+++ b/layout/tools/reftest/Makefile.in
@@ -9,23 +9,16 @@
   $(srcdir)/runreftest.py \
   $(srcdir)/reftestcommandline.py \
   $(srcdir)/remotereftest.py \
   $(srcdir)/runreftestb2g.py \
   $(srcdir)/runreftestmulet.py \
   $(srcdir)/gaia_lock_screen.js \
   $(srcdir)/output.py \
   automation.py \
-  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \
-  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \
-  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py \
-  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/droid.py \
-  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/version_codes.py \
-  $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/Zeroconf.py \
-  $(topsrcdir)/testing/mozbase/moznetwork/moznetwork/moznetwork.py \
   $(topsrcdir)/build/mobile/b2gautomation.py \
   $(topsrcdir)/build/mobile/remoteautomation.py \
   $(topsrcdir)/testing/mochitest/server.js \
   $(topsrcdir)/build/pgo/server-locations.txt \
   $(NULL)
 
 _HARNESS_PP_FILES = \
   b2g_start_script.js \
--- a/layout/tools/reftest/mach_commands.py
+++ b/layout/tools/reftest/mach_commands.py
@@ -276,18 +276,16 @@ class ReftestRunner(MozbuildObject):
             warnings.simplefilter('ignore')
 
             import imp
             path = os.path.join(self.reftest_dir, 'remotereftest.py')
             with open(path, 'r') as fh:
                 imp.load_module('reftest', fh, path, ('.py', 'r', imp.PY_SOURCE))
             import reftest
 
-        # Remove the stdout handler from the internal logger and let mach deal with it
-        runreftest.log.removeHandler(runreftest.log.handlers[0])
         self.log_manager.enable_unstructured()
         try:
             rv = reftest.run(**kwargs)
         finally:
             self.log_manager.disable_unstructured()
 
         return rv
 
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -2,21 +2,20 @@
 # 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 os
 import time
 import tempfile
 import traceback
+import urllib2
 
-import devicemanager
-import droid
+import mozdevice
 import mozinfo
-import moznetwork
 from automation import Automation
 from remoteautomation import RemoteAutomation, fennecLogcatFilters
 
 from output import OutputHandler
 from runreftest import RefTest, ReftestResolver
 import reftestcommandline
 
 # We need to know our current directory so that we can serve our test files from it.
@@ -277,29 +276,29 @@ class RemoteReftest(RefTest):
             prefs["layers.single-tile.enabled"] = False
 
         # Set the extra prefs.
         profile.set_preferences(prefs)
 
         try:
             self._devicemanager.pushDir(profileDir, options.remoteProfile)
             self._devicemanager.chmodDir(options.remoteProfile)
-        except devicemanager.DMError:
+        except mozdevice.DMError:
             print "Automation Error: Failed to copy profiledir to device"
             raise
 
         return profile
 
     def copyExtraFilesToProfile(self, options, profile):
         profileDir = profile.profile
         RefTest.copyExtraFilesToProfile(self, options, profile)
         try:
             self._devicemanager.pushDir(profileDir, options.remoteProfile)
             self._devicemanager.chmodDir(options.remoteProfile)
-        except devicemanager.DMError:
+        except mozdevice.DMError:
             print "Automation Error: Failed to copy extra files to device"
             raise
 
     def printDeviceInfo(self, printLogcat=False):
         try:
             if printLogcat:
                 logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
                 print ''.join(logcat)
@@ -308,17 +307,17 @@ class RemoteReftest(RefTest):
             for category in devinfo:
                 if type(devinfo[category]) is list:
                     print "  %s:" % category
                     for item in devinfo[category]:
                         print "     %s" % item
                 else:
                     print "  %s: %s" % (category, devinfo[category])
             print "Test root: %s" % self._devicemanager.deviceRoot
-        except devicemanager.DMError:
+        except mozdevice.DMError:
             print "WARNING: Error getting device information"
 
     def environment(self, **kwargs):
         return self.automation.environment(**kwargs)
 
     def buildBrowserEnv(self, options, profileDir):
         browserEnv = RefTest.buildBrowserEnv(self, options, profileDir)
         # remove desktop environment not used on device
@@ -362,24 +361,24 @@ class RemoteReftest(RefTest):
 def runTests(options, parser):
     if (options.dm_trans == 'sut' and options.deviceIP == None):
         print "Error: If --dm_trans = sut, you must provide a device IP to connect to via the --deviceIP option"
         return 1
 
     try:
         if (options.dm_trans == "adb"):
             if (options.deviceIP):
-                dm = droid.DroidADB(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot)
+                dm = mozdevice.DroidADB(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot)
             elif (options.deviceSerial):
-                dm = droid.DroidADB(None, None, deviceSerial=options.deviceSerial, deviceRoot=options.remoteTestRoot)
+                dm = mozdevice.DroidADB(None, None, deviceSerial=options.deviceSerial, deviceRoot=options.remoteTestRoot)
             else:
-                dm = droid.DroidADB(None, None, deviceRoot=options.remoteTestRoot)
+                dm = mozdevice.DroidADB(None, None, deviceRoot=options.remoteTestRoot)
         else:
-            dm = droid.DroidSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot)
-    except devicemanager.DMError:
+            dm = mozdevice.DroidSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot)
+    except mozdevice.DMError:
         print "Automation Error: exception while initializing devicemanager.  Most likely the device is not in a testable state."
         return 1
 
     automation = RemoteAutomation(None)
     automation.setDeviceManager(dm)
 
     if (options.remoteProductName != None):
         automation.setProduct(options.remoteProductName)
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -247,18 +247,25 @@ static int nr_ice_component_initialize_u
             isock,sock,SERVER_REFLEXIVE,0,
             &ctx->stun_servers[j],component->component_id,&cand))
             ABORT(r);
           TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
           component->candidate_ct++;
           cand=0;
         }
       }
+      else{
+        r_log(LOG_ICE,LOG_WARNING,"ICE(%s): relay only option results in no host candidate for %s",ctx->label,addrs[i].addr.as_string);
+      }
 
 #ifdef USE_TURN
+      if ((ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) &&
+          (ctx->turn_server_ct == 0)) {
+        r_log(LOG_ICE,LOG_ERR,"ICE(%s): relay only option is set without any TURN server configured",ctx->label);
+      }
       /* And both a srvrflx and relayed candidate for each TURN server (unless
          we're in relay-only mode, in which case just the relayed one) */
       for(j=0;j<ctx->turn_server_ct;j++){
         nr_socket *turn_sock;
         nr_ice_candidate *srvflx_cand=0;
 
         /* Skip non-UDP */
         if (ctx->turn_servers[j].turn_server.transport != IPPROTO_UDP)
@@ -413,16 +420,17 @@ static int nr_ice_component_initialize_t
         ABORT(r);
     }
 
     if ((r=NR_reg_get_char(NR_ICE_REG_ICE_TCP_DISABLE, &ice_tcp_disabled))) {
       if (r != R_NOT_FOUND)
         ABORT(r);
     }
     if (ctx->flags & NR_ICE_CTX_FLAGS_RELAY_ONLY) {
+      r_log(LOG_ICE,LOG_WARNING,"ICE(%s): relay only option results in ICE TCP being disabled",ctx->label);
       ice_tcp_disabled = 1;
     }
 
     for(i=0;i<addr_ct;i++){
       char suppress;
       nr_ice_socket *isock_psv=0;
       nr_ice_socket *isock_so=0;
 
--- a/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp
+++ b/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp
@@ -205,8 +205,13 @@ void EnableWebRtcLog()
 
 #ifdef MOZILLA_INTERNAL_API
   GetWebRtcLogPrefs(&trace_mask, &log_file, &aec_log_dir, &multi_log);
 #endif
   CheckOverrides(&trace_mask, &log_file, &multi_log);
   ConfigWebRtcLog(trace_mask, log_file, aec_log_dir, multi_log);
   return;
 }
+
+void StopWebRtcLog()
+{
+  webrtc::Trace::SetTraceFile(nullptr);
+}
--- a/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.h
+++ b/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.h
@@ -4,10 +4,11 @@
 
 #ifndef WEBRTCLOG_H_
 #define WEBRTCLOG_H_
 
 #include "webrtc/common_types.h"
 
 void StartWebRtcLog(uint32_t log_level = webrtc::kTraceDefault);
 void EnableWebRtcLog();
+void StopWebRtcLog();
 
 #endif
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -22,17 +22,16 @@
 #include "Latency.h"
 #include "mozilla/Telemetry.h"
 #endif
 
 #include "webrtc/common.h"
 #include "webrtc/modules/audio_processing/include/audio_processing.h"
 #include "webrtc/voice_engine/include/voe_errors.h"
 #include "webrtc/system_wrappers/interface/clock.h"
-#include "browser_logging/WebRtcLog.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidJNIWrapper.h"
 #endif
 
 namespace mozilla {
 
 static const char* logTag ="WebrtcAudioSessionConduit";
@@ -252,18 +251,16 @@ MediaConduitErrorCode WebrtcAudioConduit
 
   // Per WebRTC APIs below function calls return nullptr on failure
   if(!(mVoiceEngine = webrtc::VoiceEngine::Create(config)))
   {
     CSFLogError(logTag, "%s Unable to create voice engine", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
-  EnableWebRtcLog();
-
   if(!(mPtrVoEBase = VoEBase::GetInterface(mVoiceEngine)))
   {
     CSFLogError(logTag, "%s Unable to initialize VoEBase", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
   if(!(mPtrVoENetwork = VoENetwork::GetInterface(mVoiceEngine)))
   {
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -16,17 +16,16 @@
 #include "nsIPrefBranch.h"
 #include "mozilla/media/MediaUtils.h"
 
 #include "webrtc/common_types.h"
 #include "webrtc/common_video/interface/native_handle.h"
 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
 #include "webrtc/video_engine/include/vie_errors.h"
 #include "webrtc/video_engine/vie_defines.h"
-#include "browser_logging/WebRtcLog.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidJNIWrapper.h"
 #endif
 
 // for ntohs
 #ifdef _MSC_VER
 #include "Winsock2.h"
@@ -303,17 +302,16 @@ WebrtcVideoConduit::InitMain()
       bool use_loadmanager = false;
       (void) NS_WARN_IF(NS_FAILED(branch->GetBoolPref("media.navigator.load_adapt", &use_loadmanager)));
       if (use_loadmanager) {
         mLoadManager = LoadManagerBuild();
       }
     }
   }
 
-  EnableWebRtcLog();
 #ifdef MOZ_WIDGET_ANDROID
   // get the JVM
   JavaVM *jvm = jsjni_GetVM();
 
   if (webrtc::VideoEngine::SetAndroidObjects(jvm) != 0) {
     CSFLogError(logTag,  "%s: could not set Android objects", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
@@ -6,16 +6,17 @@
 
 #include "base/histogram.h"
 #include "PeerConnectionImpl.h"
 #include "PeerConnectionCtx.h"
 #include "runnable_utils.h"
 #include "prcvar.h"
 
 #include "mozilla/Telemetry.h"
+#include "browser_logging/WebRtcLog.h"
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
 #include "mozilla/dom/RTCPeerConnectionBinding.h"
 #include "mozilla/Preferences.h"
 #include <mozilla/Types.h>
 #endif
 
 #include "nsNetCID.h" // NS_SOCKETTRANSPORTSERVICE_CONTRACTID
@@ -130,16 +131,17 @@ nsresult PeerConnectionCtx::InitializeGl
     gInstance = ctx;
 
     if (!PeerConnectionCtx::gPeerConnectionCtxShutdown) {
       PeerConnectionCtx::gPeerConnectionCtxShutdown = new PeerConnectionCtxShutdown();
       PeerConnectionCtx::gPeerConnectionCtxShutdown->Init();
     }
   }
 
+  EnableWebRtcLog();
   return NS_OK;
 }
 
 PeerConnectionCtx* PeerConnectionCtx::GetInstance() {
   MOZ_ASSERT(gInstance);
   return gInstance;
 }
 
@@ -150,16 +152,18 @@ bool PeerConnectionCtx::isActive() {
 void PeerConnectionCtx::Destroy() {
   CSFLogDebug(logTag, "%s", __FUNCTION__);
 
   if (gInstance) {
     gInstance->Cleanup();
     delete gInstance;
     gInstance = nullptr;
   }
+
+  StopWebRtcLog();
 }
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
 typedef Vector<nsAutoPtr<RTCStatsQuery>> RTCStatsQueries;
 
 // Telemetry reporting every second after start of first call.
 // The threading model around the media pipelines is weird:
 // - The pipelines are containers,
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -233,16 +233,22 @@ pref("extensions.compatability.locales.b
 /* blocklist preferences */
 pref("extensions.blocklist.enabled", true);
 // OneCRL freshness checking depends on this value, so if you change it,
 // please also update security.onecrl.maximum_staleness_in_seconds.
 pref("extensions.blocklist.interval", 86400);
 pref("extensions.blocklist.url", "https://blocklist.addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PING_COUNT%/%TOTAL_PING_COUNT%/%DAYS_SINCE_LAST_PING%/");
 pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
 
+// Kinto blocklist preferences
+pref("services.kinto.base", "https://firefox.settings.services.mozilla.com/v1");
+pref("services.kinto.bucket", "blocklists");
+pref("services.kinto.onecrl.collection", "certificates");
+pref("services.kinto.onecrl.checked", 0);
+
 /* Don't let XPIProvider install distribution add-ons; we do our own thing on mobile. */
 pref("extensions.installDistroAddons", false);
 
 /* block popups by default, and notify the user about blocked popups */
 pref("dom.disable_open_during_load", true);
 pref("privacy.popups.showBrowserMessage", true);
 
 /* disable opening windows with the dialog feature */
@@ -435,17 +441,17 @@ pref("ui.zoomedview.simplified", true); 
 
 pref("ui.touch.radius.enabled", false);
 pref("ui.touch.radius.leftmm", 3);
 pref("ui.touch.radius.topmm", 5);
 pref("ui.touch.radius.rightmm", 3);
 pref("ui.touch.radius.bottommm", 2);
 pref("ui.touch.radius.visitedWeight", 120);
 
-pref("ui.mouse.radius.enabled", true);
+pref("ui.mouse.radius.enabled", false);
 pref("ui.mouse.radius.leftmm", 3);
 pref("ui.mouse.radius.topmm", 5);
 pref("ui.mouse.radius.rightmm", 3);
 pref("ui.mouse.radius.bottommm", 2);
 pref("ui.mouse.radius.visitedWeight", 120);
 pref("ui.mouse.radius.reposition", true);
 
 // The percentage of the screen that needs to be scrolled before toolbar
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4433,17 +4433,17 @@ pref("gfx.content.use-native-pushlayer",
 
 #ifdef ANDROID
 pref("gfx.apitrace.enabled",false);
 #endif
 
 #ifdef MOZ_X11
 pref("gfx.content.use-native-pushlayer", true);
 #ifdef MOZ_WIDGET_GTK
-pref("gfx.xrender.enabled",true);
+pref("gfx.xrender.enabled",false);
 #endif
 #endif
 
 #ifdef XP_WIN
 pref("gfx.content.use-native-pushlayer", true);
 
 // Whether to disable the automatic detection and use of direct2d.
 pref("gfx.direct2d.disabled", false);
--- a/netwerk/base/nsURLHelper.cpp
+++ b/netwerk/base/nsURLHelper.cpp
@@ -243,61 +243,45 @@ net_CoalesceDirs(netCoalesceFlags flags,
     /* Stolen from the old netlib's mkparse.c.
      *
      * modifies a url of the form   /foo/../foo1  ->  /foo1
      *                       and    /foo/./foo1   ->  /foo/foo1
      *                       and    /foo/foo1/..  ->  /foo/
      */
     char *fwdPtr = path;
     char *urlPtr = path;
-    char *lastslash = path;
+    char *endPath = path;
     uint32_t traversal = 0;
     uint32_t special_ftp_len = 0;
 
     /* Remember if this url is a special ftp one: */
     if (flags & NET_COALESCE_DOUBLE_SLASH_IS_ROOT) 
     {
        /* some schemes (for example ftp) have the speciality that 
           the path can begin // or /%2F to mark the root of the 
           servers filesystem, a simple / only marks the root relative 
           to the user loging in. We remember the length of the marker */
         if (nsCRT::strncasecmp(path,"/%2F",4) == 0)
             special_ftp_len = 4;
         else if (nsCRT::strncmp(path,"//",2) == 0 )
             special_ftp_len = 2; 
     }
 
-    /* find the last slash before # or ? */
-    for(; (*fwdPtr != '\0') && 
-            (*fwdPtr != '?') && 
+    /* find the end of the path - places the cursor on \0, ? or # */
+    for(; (*fwdPtr != '\0') &&
+            (*fwdPtr != '?') &&
             (*fwdPtr != '#'); ++fwdPtr)
     {
     }
 
-    /* found nothing, but go back one only */
-    /* if there is something to go back to */
-    if (fwdPtr != path && *fwdPtr == '\0')
-    {
-        --fwdPtr;
-    }
-
-    /* search the slash */
-    for(; (fwdPtr != path) && 
-            (*fwdPtr != '/'); --fwdPtr)
-    {
-    }
-    lastslash = fwdPtr;
+    endPath = fwdPtr;
     fwdPtr = path;
 
     /* replace all %2E or %2e with . in the path */
-    /* but stop at lastchar if non null */
-    for(; (*fwdPtr != '\0') && 
-            (*fwdPtr != '?') && 
-            (*fwdPtr != '#') &&
-            (*lastslash == '\0' || fwdPtr != lastslash); ++fwdPtr)
+    for(; fwdPtr != endPath; ++fwdPtr)
     {
         if (*fwdPtr == '%' && *(fwdPtr+1) == '2' && 
             (*(fwdPtr+2) == 'E' || *(fwdPtr+2) == 'e'))
         {
             *urlPtr++ = '.';
             ++fwdPtr;
             ++fwdPtr;
         } 
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_bug464591.js
@@ -0,0 +1,81 @@
+
+const StandardURL = Components.Constructor("@mozilla.org/network/standard-url;1",
+                                           "nsIStandardURL",
+                                           "init");
+
+ // 1.percent-encoded IDN that contains blacklisted character should be converted
+ //   to punycode, not UTF-8 string
+ // 2.only hostname-valid percent encoded ASCII characters should be decoded
+ // 3.IDN convertion must not bypassed by %00
+let reference = [
+   ["www.example.com%e2%88%95www.mozill%d0%b0.com%e2%81%84www.mozilla.org",
+    "www.example.xn--comwww-re3c.xn--mozill-8nf.xn--comwww-rq0c.mozilla.org"],
+   ["www.mozill%61%2f.org", "www.mozilla%2f.org"], // a slash is not valid in the hostname
+   ["www.e%00xample.com%e2%88%95www.mozill%d0%b0.com%e2%81%84www.mozill%61.org",
+    "www.e%00xample.xn--comwww-re3c.xn--mozill-8nf.xn--comwww-rq0c.mozilla.org"],
+];
+
+let prefData =
+  [
+    {
+      name: "network.enableIDN",
+      newVal: true
+    },
+    {
+      name: "network.IDN_show_punycode",
+      newVal: false
+    },
+    {
+      name: "network.IDN.whitelist.org",
+      newVal: true
+    }
+  ];
+
+ let prefIdnBlackList = {
+      name: "network.IDN.blacklist_chars",
+      minimumList: "\u2215\u0430\u2044",
+  };
+
+function stringToURL(str) {
+  return (new StandardURL(Ci.nsIStandardURL.URLTYPE_AUTHORITY, 80,
+			 str, "UTF-8", null))
+         .QueryInterface(Ci.nsIURL);
+}
+
+function run_test() {
+  // Make sure our prefs are set such that this test actually means something
+  let prefs = Cc["@mozilla.org/preferences-service;1"].
+              getService(Ci.nsIPrefBranch);
+  for (let pref of prefData) {
+    prefs.setBoolPref(pref.name, pref.newVal);
+  }
+
+  prefIdnBlackList.set = false;
+  try {
+    prefIdnBlackList.oldVal = prefs.getComplexValue(prefIdnBlackList.name,
+                                                    Ci.nsIPrefLocalizedString).data;
+    prefs.getComplexValue(prefIdnBlackList.name,
+                          Ci.nsIPrefLocalizedString).data=prefIdnBlackList.minimumList;
+    prefIdnBlackList.set = true;
+  } catch (e) {
+  }
+
+  do_register_cleanup(function() {
+    for (let pref of prefData) {
+      prefs.clearUserPref(pref.name);
+    }
+    if (prefIdnBlackList.set) {
+      prefs.getComplexValue(prefIdnBlackList.name,
+                            Ci.nsIPrefLocalizedString).data = prefIdnBlackList.oldVal;
+    }
+  });
+
+  for (let i = 0; i < reference.length; ++i) {
+    try {
+      let result = stringToURL("http://" + reference[i][0]).host;
+      equal(result, reference[i][1]);
+    } catch (e) {
+      ok(false, "Error testing "+reference[i][0]);
+    }
+  }
+}
--- a/netwerk/test/unit/test_standardurl.js
+++ b/netwerk/test/unit/test_standardurl.js
@@ -296,14 +296,40 @@ add_test(function test_hugeStringThrows(
     Assert.throws(() => url[prop] = hugeString,
                   /NS_ERROR_MALFORMED_URI/,
                   `Passing a huge string to "${prop}" should throw`);
   }
 
   run_next_test();
 });
 
+add_test(function test_pathPercentEncodedDot()
+{
+  var url = stringToURL("http://example.com/%2eX/X%2e/%2eX");
+  do_check_eq(url.spec, "http://example.com/.X/X./.X");
+
+  url = stringToURL("http://example.com/hello/%2e%2E/%2e");
+  do_check_eq(url.spec, "http://example.com/");
+
+  url = stringToURL("http://example.com/hello/%2e%2E/%");
+  do_check_eq(url.spec, "http://example.com/%");
+
+  url = stringToURL("http://example.com/hello/%2e%2E/%2");
+  do_check_eq(url.spec, "http://example.com/%2");
+
+  url = stringToURL("http://example.com/hello/%2e%2E/%#");
+  do_check_eq(url.spec, "http://example.com/%#");
+
+  url = stringToURL("http://example.com/hello/%2e%2E/%2?");
+  do_check_eq(url.spec, "http://example.com/%2?");
+
+  url = stringToURL("http://example.com/hello/%2e/");
+  do_check_eq(url.spec, "http://example.com/hello/");
+
+  run_next_test();
+});
+
 add_test(function test_filterWhitespace()
 {
   var url = stringToURL(" \r\n\th\nt\rt\tp://ex\r\n\tample.com/path\r\n\t/\r\n\tto the/fil\r\n\te.e\r\n\txt?que\r\n\try#ha\r\n\tsh \r\n\t ");
   do_check_eq(url.spec, "http://example.com/path/to%20the/file.ext?query#hash");
   run_next_test();
 });
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -341,9 +341,10 @@ firefox-appdir = browser
 [test_dns_disable_ipv4.js]
 [test_dns_disable_ipv6.js]
 [test_packaged_app_service_paths.js]
 [test_bug1195415.js]
 [test_cookie_blacklist.js]
 [test_getHost.js]
 [test_packaged_app_bug1214079.js]
 [test_bug412457.js]
+[test_bug464591.js]
 
--- a/parser/html/javasrc/TreeBuilder.java
+++ b/parser/html/javasrc/TreeBuilder.java
@@ -4443,17 +4443,17 @@ public abstract class TreeBuilder<T> imp
         return TreeBuilder.NOT_FOUND_ON_STACK;
     }
 
     private void clearStackBackTo(int eltPos) throws SAXException {
         int eltGroup = stack[eltPos].getGroup();
         while (currentPtr > eltPos) { // > not >= intentional
             if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml"
                     && stack[currentPtr].getGroup() == TEMPLATE
-                    && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltGroup == HTML)) {
+                    && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltPos == 0)) {
                 return;
             }
             pop();
         }
     }
 
     private void resetTheInsertionMode() {
         StackNode<T> node;
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -3301,17 +3301,17 @@ nsHtml5TreeBuilder::findLastInTableScope
   return NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK;
 }
 
 void 
 nsHtml5TreeBuilder::clearStackBackTo(int32_t eltPos)
 {
   int32_t eltGroup = stack[eltPos]->getGroup();
   while (currentPtr > eltPos) {
-    if (stack[currentPtr]->ns == kNameSpaceID_XHTML && stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE && (eltGroup == NS_HTML5TREE_BUILDER_TABLE || eltGroup == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || eltGroup == NS_HTML5TREE_BUILDER_TR || eltGroup == NS_HTML5TREE_BUILDER_HTML)) {
+    if (stack[currentPtr]->ns == kNameSpaceID_XHTML && stack[currentPtr]->getGroup() == NS_HTML5TREE_BUILDER_TEMPLATE && (eltGroup == NS_HTML5TREE_BUILDER_TABLE || eltGroup == NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT || eltGroup == NS_HTML5TREE_BUILDER_TR || !eltPos)) {
       return;
     }
     pop();
   }
 }
 
 void 
 nsHtml5TreeBuilder::resetTheInsertionMode()
--- a/python/mach/mach/registrar.py
+++ b/python/mach/mach/registrar.py
@@ -86,16 +86,22 @@ class MachRegistrar(object):
         if debug_command:
             import pdb
             result = pdb.runcall(fn, **kwargs)
         else:
             result = fn(**kwargs)
 
         result = result or 0
         assert isinstance(result, (int, long))
+
+        if context:
+            postrun = getattr(context, 'post_dispatch_handler', None)
+            if postrun:
+                postrun(context, handler, args=kwargs)
+
         return result
 
     def dispatch(self, name, context=None, argv=None, **kwargs):
         """Dispatch/run a command.
 
         Commands can use this to call other commands.
         """
         # TODO handler.subcommand_handlers are ignored
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -488,16 +488,21 @@ class Build(MachCommandBase):
         if monitor.have_resource_usage:
             excessive, swap_in, swap_out = monitor.have_excessive_swapping()
             # if excessive:
             #    print(EXCESSIVE_SWAP_MESSAGE)
 
             print('To view resource usage of the build, run |mach '
                 'resource-usage|.')
 
+            telemetry_handler = getattr(self._mach_context,
+                                        'telemetry_handler', None)
+            usage = monitor.record_resource_usage()
+            telemetry_handler(self._mach_context, usage)
+
         # Only for full builds because incremental builders likely don't
         # need to be burdened with this.
         if not what:
             try:
                 # Fennec doesn't have useful output from just building. We should
                 # arguably make the build action useful for Fennec. Another day...
                 if self.substs['MOZ_BUILD_APP'] != 'mobile/android':
                     print('To take your build for a test drive, run: |mach run|')
new file mode 100644
--- /dev/null
+++ b/services/common/KintoCertificateBlocklist.js
@@ -0,0 +1,115 @@
+/* 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/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["OneCRLClient"];
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://services-common/moz-kinto-client.js");
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
+                                   "@mozilla.org/uuid-generator;1",
+                                   "nsIUUIDGenerator");
+
+const PREF_KINTO_BASE = "services.kinto.base";
+const PREF_KINTO_BUCKET = "services.kinto.bucket";
+const PREF_KINTO_ONECRL_COLLECTION = "services.kinto.onecrl.collection";
+const PREF_KINTO_ONECRL_CHECKED_SECONDS = "services.kinto.onecrl.checked";
+
+const RE_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
+
+// Kinto.js assumes version 4 UUIDs but allows you to specify custom
+// validators and generators. The tooling that generates records in the
+// certificates collection currently uses a version 1 UUID so we must
+// specify a validator that's less strict. We must also supply a generator
+// since Kinto.js does not allow one without the other.
+function makeIDSchema() {
+  return {
+    validate: RE_UUID.test.bind(RE_UUID),
+    generate: function() {
+      return uuidgen.generateUUID().toString();
+    }
+  };
+}
+
+// A Kinto based client to keep the OneCRL certificate blocklist up to date.
+function CertBlocklistClient() {
+  // maybe sync the collection of certificates with remote data.
+  // lastModified - the lastModified date (on the server, milliseconds since
+  // epoch) of data in the remote collection
+  // serverTime - the time on the server (milliseconds since epoch)
+  // returns a promise which rejects on sync failure
+  this.maybeSync = function(lastModified, serverTime) {
+    let base = Services.prefs.getCharPref(PREF_KINTO_BASE);
+    let bucket = Services.prefs.getCharPref(PREF_KINTO_BUCKET);
+
+    let Kinto = loadKinto();
+
+    let FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
+
+
+    let certList = Cc["@mozilla.org/security/certblocklist;1"]
+                     .getService(Ci.nsICertBlocklist);
+
+    // Future blocklist clients can extract the sync-if-stale logic. For
+    // now, since this is currently the only client, we'll do this here.
+    let config = {
+      remote: base,
+      bucket: bucket,
+      adapter: FirefoxAdapter,
+    };
+
+    let db = new Kinto(config);
+    let collectionName = Services.prefs.getCharPref(PREF_KINTO_ONECRL_COLLECTION,
+                                                    "certificates");
+    let blocklist = db.collection(collectionName,
+                                  { idSchema: makeIDSchema() });
+
+    let updateLastCheck = function() {
+      let checkedServerTimeInSeconds = Math.round(serverTime / 1000);
+      Services.prefs.setIntPref(PREF_KINTO_ONECRL_CHECKED_SECONDS,
+                                checkedServerTimeInSeconds);
+    }
+
+    return Task.spawn(function* () {
+      try {
+        yield blocklist.db.open();
+        let collectionLastModified = yield blocklist.db.getLastModified();
+        // if the data is up to date, there's no need to sync. We still need
+        // to record the fact that a check happened.
+        if (lastModified <= collectionLastModified) {
+          updateLastCheck();
+          return;
+        }
+        yield blocklist.sync();
+        let list = yield blocklist.list();
+        for (let item of list.data) {
+          if (item.issuerName && item.serialNumber) {
+            certList.revokeCertByIssuerAndSerial(item.issuerName,
+                                                 item.serialNumber);
+          } else if (item.subject && item.pubKeyHash) {
+            certList.revokeCertBySubjectAndPubKey(item.subject,
+                                                  item.pubKeyHash);
+          } else {
+            throw new Error("Cert blocklist record has incomplete data");
+          }
+        }
+        // We explicitly do not want to save entries or update the
+        // last-checked time if sync fails
+        certList.saveEntries();
+        updateLastCheck();
+      } finally {
+        blocklist.db.close()
+      }
+    });
+  }
+}
+
+this.OneCRLClient = new CertBlocklistClient();
--- a/services/common/moz.build
+++ b/services/common/moz.build
@@ -10,16 +10,17 @@ with Files('**'):
 TEST_DIRS += ['tests']
 
 EXTRA_COMPONENTS += [
     'servicesComponents.manifest',
 ]
 
 EXTRA_JS_MODULES['services-common'] += [
     'async.js',
+    'KintoCertificateBlocklist.js',
     'logmanager.js',
     'moz-kinto-client.js',
     'observers.js',
     'rest.js',
     'stringbundle.js',
     'utils.js',
 ]
 
new file mode 100644
--- /dev/null
+++ b/services/common/tests/unit/test_kintoCertBlocklist.js
@@ -0,0 +1,189 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { Constructor: CC } = Components;
+
+Cu.import("resource://services-common/KintoCertificateBlocklist.js");
+Cu.import("resource://services-common/moz-kinto-client.js")
+Cu.import("resource://testing-common/httpd.js");
+
+const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
+  "nsIBinaryInputStream", "setInputStream");
+
+var server;
+
+// set up what we need to make storage adapters
+const Kinto = loadKinto();
+const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
+const kintoFilename = "kinto.sqlite";
+
+let kintoClient;
+
+function do_get_kinto_collection(collectionName) {
+  if (!kintoClient) {
+    let config = {
+      // Set the remote to be some server that will cause test failure when
+      // hit since we should never hit the server directly, only via maybeSync()
+      remote: "https://firefox.settings.services.mozilla.com/v1/",
+      // Set up the adapter and bucket as normal
+      adapter: FirefoxAdapter,
+      bucket: "blocklists"
+    };
+    kintoClient = new Kinto(config);
+  }
+  return kintoClient.collection(collectionName);
+}
+
+// Some simple tests to demonstrate that the logic inside maybeSync works
+// correctly and that simple kinto operations are working as expected. There
+// are more tests for core Kinto.js (and its storage adapter) in the
+// xpcshell tests under /services/common
+add_task(function* test_something(){
+  const configPath = "/v1/";
+  const recordsPath = "/v1/buckets/blocklists/collections/certificates/records";
+
+  Services.prefs.setCharPref("services.kinto.base",
+                             `http://localhost:${server.identity.primaryPort}/v1`);
+
+  // register a handler
+  function handleResponse (request, response) {
+    try {
+      const sampled = getSampleResponse(request, server.identity.primaryPort);
+      if (!sampled) {
+        do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
+      }
+
+      response.setStatusLine(null, sampled.status.status,
+                             sampled.status.statusText);
+      // send the headers
+      for (let headerLine of sampled.sampleHeaders) {
+        let headerElements = headerLine.split(':');
+        response.setHeader(headerElements[0], headerElements[1].trimLeft());
+      }
+      response.setHeader("Date", (new Date()).toUTCString());
+
+      response.write(sampled.responseBody);
+    } catch (e) {
+      dump(`${e}\n`);
+    }
+  }
+  server.registerPathHandler(configPath, handleResponse);
+  server.registerPathHandler(recordsPath, handleResponse);
+
+  // Test an empty db populates
+  let result = yield OneCRLClient.maybeSync(2000, Date.now());
+
+  // Open the collection, verify it's been populated:
+  // Our test data has a single record; it should be in the local collection
+  let collection = do_get_kinto_collection("certificates");
+  yield collection.db.open();
+  let list = yield collection.list();
+  do_check_eq(list.data.length, 1);
+  yield collection.db.close();
+
+  // Test the db is updated when we call again with a later lastModified value
+  result = yield OneCRLClient.maybeSync(4000, Date.now());
+
+  // Open the collection, verify it's been updated:
+  // Our test data now has two records; both should be in the local collection
+  collection = do_get_kinto_collection("certificates");
+  yield collection.db.open();
+  list = yield collection.list();
+  do_check_eq(list.data.length, 3);
+  yield collection.db.close();
+
+  // Try to maybeSync with the current lastModified value - no connection
+  // should be attempted.
+  // Clear the kinto base pref so any connections will cause a test failure
+  Services.prefs.clearUserPref("services.kinto.base");
+  yield OneCRLClient.maybeSync(4000, Date.now());
+
+  // Try again with a lastModified value at some point in the past
+  yield OneCRLClient.maybeSync(3000, Date.now());
+
+  // Check the OneCRL check time pref is modified, even if the collection
+  // hasn't changed
+  Services.prefs.setIntPref("services.kinto.onecrl.checked", 0);
+  yield OneCRLClient.maybeSync(3000, Date.now());
+  let newValue = Services.prefs.getIntPref("services.kinto.onecrl.checked");
+  do_check_neq(newValue, 0);
+});
+
+function run_test() {
+  // Set up an HTTP Server
+  server = new HttpServer();
+  server.start(-1);
+
+  run_next_test();
+
+  do_register_cleanup(function() {
+    server.stop(function() { });
+  });
+}
+
+// get a response for a given request from sample data
+function getSampleResponse(req, port) {
+  const responses = {
+    "OPTIONS": {
+      "sampleHeaders": [
+        "Access-Control-Allow-Headers: Content-Length,Expires,Backoff,Retry-After,Last-Modified,Total-Records,ETag,Pragma,Cache-Control,authorization,content-type,if-none-match,Alert,Next-Page",
+        "Access-Control-Allow-Methods: GET,HEAD,OPTIONS,POST,DELETE,OPTIONS",
+        "Access-Control-Allow-Origin: *",
+        "Content-Type: application/json; charset=UTF-8",
+        "Server: waitress"
+      ],
+      "status": {status: 200, statusText: "OK"},
+      "responseBody": "null"
+    },
+    "GET:/v1/?": {
+      "sampleHeaders": [
+        "Access-Control-Allow-Origin: *",
+        "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
+        "Content-Type: application/json; charset=UTF-8",
+        "Server: waitress"
+      ],
+      "status": {status: 200, statusText: "OK"},
+      "responseBody": JSON.stringify({"settings":{"cliquet.batch_max_requests":25}, "url":`http://localhost:${port}/v1/`, "documentation":"https://kinto.readthedocs.org/", "version":"1.5.1", "commit":"cbc6f58", "hello":"kinto"})
+    },
+    "GET:/v1/buckets/blocklists/collections/certificates/records?": {
+      "sampleHeaders": [
+        "Access-Control-Allow-Origin: *",
+        "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
+        "Content-Type: application/json; charset=UTF-8",
+        "Server: waitress",
+        "Etag: \"3000\""
+      ],
+      "status": {status: 200, statusText: "OK"},
+      "responseBody": JSON.stringify({"data":[{
+        "issuerName": "MEQxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xHjAcBgNVBAMTFXRoYXd0ZSBFViBTU0wgQ0EgLSBHMw==",
+        "serialNumber":"CrTHPEE6AZSfI3jysin2bA==",
+        "id":"78cf8900-fdea-4ce5-f8fb-b78710617718",
+        "last_modified":3000
+      }]})
+    },
+    "GET:/v1/buckets/blocklists/collections/certificates/records?_since=3000": {
+      "sampleHeaders": [
+        "Access-Control-Allow-Origin: *",
+        "Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
+        "Content-Type: application/json; charset=UTF-8",
+        "Server: waitress",
+        "Etag: \"4000\""
+      ],
+      "status": {status: 200, statusText: "OK"},
+      "responseBody": JSON.stringify({"data":[{
+        "issuerName":"MFkxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKjAoBgNVBAMTIVN0YWF0IGRlciBOZWRlcmxhbmRlbiBPdmVyaGVpZCBDQQ",
+        "serialNumber":"ATFpsA==",
+        "id":"dabafde9-df4a-ddba-2548-748da04cc02c",
+        "last_modified":4000
+      },{
+        "subject":"MCIxIDAeBgNVBAMMF0Fub3RoZXIgVGVzdCBFbmQtZW50aXR5",
+        "pubKeyHash":"VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=",
+        "id":"dabafde9-df4a-ddba-2548-748da04cc02d",
+        "last_modified":4000
+      }]})
+    }
+  };
+  return responses[`${req.method}:${req.path}?${req.queryString}`] ||
+         responses[req.method];
+
+}
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -5,16 +5,17 @@ firefox-appdir = browser
 skip-if = toolkit == 'gonk'
 support-files =
   test_storage_adapter/**
 
 # Test load modules first so syntax failures are caught early.
 [test_load_modules.js]
 
 [test_kinto.js]
+[test_kintoCertBlocklist.js]
 [test_storage_adapter.js]
 
 [test_utils_atob.js]
 [test_utils_convert_string.js]
 [test_utils_dateprefs.js]
 [test_utils_deepCopy.js]
 [test_utils_encodeBase32.js]
 [test_utils_encodeBase64URL.js]
--- a/testing/crashtest/crashtests.list
+++ b/testing/crashtest/crashtests.list
@@ -15,16 +15,17 @@ include ../../dom/canvas/crashtests/cras
 include ../../dom/events/crashtests/crashtests.list
 include ../../dom/html/crashtests/crashtests.list
 include ../../dom/indexedDB/crashtests/crashtests.list
 include ../../dom/jsurl/crashtests/crashtests.list
 include ../../dom/mathml/crashtests/crashtests.list
 include ../../dom/media/mediasource/test/crashtests/crashtests.list
 include ../../dom/media/test/crashtests/crashtests.list
 skip-if(!webrtc) include ../../dom/media/tests/crashtests/crashtests.list
+include ../../dom/media/webspeech/synth/crashtests/crashtests.list
 include ../../dom/offline/crashtests/crashtests.list
 include ../../dom/plugins/test/crashtests/crashtests.list
 include ../../dom/smil/crashtests/crashtests.list
 include ../../dom/svg/crashtests/crashtests.list
 include ../../dom/workers/test/crashtests/crashtests.list
 include ../../dom/xbl/crashtests/crashtests.list
 include ../../dom/xml/crashtests/crashtests.list
 include ../../dom/xslt/crashtests/crashtests.list
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -510,17 +510,17 @@ GeckoDriver.prototype.listeningPromise =
       this.mm.removeMessageListener(li, cb);
       resolve();
     };
     this.mm.addMessageListener(li, cb);
   });
 };
 
 /** Create a new session. */
-GeckoDriver.prototype.newSession = function(cmd, resp) {
+GeckoDriver.prototype.newSession = function*(cmd, resp) {
   this.sessionId = cmd.parameters.sessionId ||
       cmd.parameters.session_id ||
       elements.generateUUID();
 
   this.newSessionCommandId = cmd.id;
   this.setSessionCapabilities(cmd.parameters.capabilities);
   this.scriptTimeout = 10000;
 
@@ -635,20 +635,20 @@ GeckoDriver.prototype.setSessionCapabili
     }
 
     for (let key in from) {
       switch (key) {
         case "desiredCapabilities":
           to = copy(from[key], to);
           break;
         case "requiredCapabilities":
-          if (from[key]["proxy"]) {
-              this.setUpProxy(from[key]["proxy"]);
-              to["proxy"] = from[key]["proxy"];
-              delete from[key]["proxy"];
+          if (from[key].proxy) {
+              this.setUpProxy(from[key].proxy);
+              to.proxy = from[key].proxy;
+              delete from[key].proxy;
           }
           for (let caps in from[key]) {
             if (from[key][caps] !== this.sessionCapabilities[caps]) {
               errors.push(from[key][caps] + " does not equal " +
                   this.sessionCapabilities[caps])   ;
             }
           }
           break;
@@ -711,16 +711,17 @@ GeckoDriver.prototype.setUpProxy = funct
 
       case "SYSTEM":
         Preferences.set("network.proxy.type", 5);
         break;
 
       case "NOPROXY":
       default:
         Preferences.set("network.proxy.type", 0);
+        break;
     }
   } else {
     throw new InvalidArgumentError("Value of 'proxy' should be an object");
   }
 };
 
 /**
  * Log message.  Accepts user defined log-level.
@@ -869,17 +870,17 @@ GeckoDriver.prototype.executeScriptInSan
 
 /**
  * Execute the given script either as a function body or directly (for
  * mochitest-like JS Marionette tests).
  *
  * If directInject is ture, it will run directly and not as a function
  * body.
  */
-GeckoDriver.prototype.execute = function(cmd, resp, directInject) {
+GeckoDriver.prototype.execute = function*(cmd, resp, directInject) {
   let {inactivityTimeout,
        scriptTimeout,
        script,
        newSandbox,
        args,
        filename,
        line} = cmd.parameters;
   let sandboxName = cmd.parameters.sandbox || 'default';
@@ -980,17 +981,17 @@ GeckoDriver.prototype.setScriptTimeout =
   }
   this.scriptTimeout = ms;
 };
 
 /**
  * Execute pure JavaScript.  Used to execute mochitest-like Marionette
  * tests.
  */
-GeckoDriver.prototype.executeJSScript = function(cmd, resp) {
+GeckoDriver.prototype.executeJSScript = function*(cmd, resp) {
   // TODO(ato): cmd.newSandbox doesn't ever exist?
   // All pure JS scripts will need to call
   // Marionette.finish() to complete the test
   if (typeof cmd.newSandbox == "undefined") {
     // If client does not send a value in newSandbox,
     // then they expect the same behaviour as WebDriver.
     cmd.newSandbox = true;
   }
@@ -1031,17 +1032,17 @@ GeckoDriver.prototype.executeJSScript = 
  * For executeAsync, it will return a response when
  * {@code marionetteScriptFinished} (equivalent to
  * {@code arguments[arguments.length-1]}) function is called,
  * or if it times out.
  *
  * If directInject is true, it will be run directly and not as a
  * function body.
  */
-GeckoDriver.prototype.executeWithCallback = function(cmd, resp, directInject) {
+GeckoDriver.prototype.executeWithCallback = function*(cmd, resp, directInject) {
   let {script,
       args,
       newSandbox,
       inactivityTimeout,
       scriptTimeout,
       filename,
       line} = cmd.parameters;
   let sandboxName = cmd.parameters.sandbox || "default";
@@ -1210,17 +1211,17 @@ GeckoDriver.prototype.executeWithCallbac
  *
  * In chrome context it will change the current window's location to
  * the supplied URL and wait until document.readyState equals "complete"
  * or the page timeout duration has elapsed.
  *
  * @param {string} url
  *     URL to navigate to.
  */
-GeckoDriver.prototype.get = function(cmd, resp) {
+GeckoDriver.prototype.get = function*(cmd, resp) {
   let url = cmd.parameters.url;
 
   switch (this.context) {
     case Context.CONTENT:
       let get = this.listener.get({url: url, pageTimeout: this.pageTimeout});
       // TODO(ato): Bug 1242595
       let id = this.listener.activeMessageId;
 
@@ -1287,27 +1288,25 @@ GeckoDriver.prototype.pageLoadPromise = 
  *
  * When in the context of the chrome, this returns the canonical URL
  * of the current resource.
  */
 GeckoDriver.prototype.getCurrentUrl = function(cmd) {
   switch (this.context) {
     case Context.CHROME:
       return this.getCurrentWindow().location.href;
-      break;
 
     case Context.CONTENT:
       let isB2G = this.appName == "B2G";
       return this.listener.getCurrentUrl(isB2G);
-      break;
   }
 };
 
 /** Gets the current title of the window. */
-GeckoDriver.prototype.getTitle = function(cmd, resp) {
+GeckoDriver.prototype.getTitle = function*(cmd, resp) {
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       resp.body.value = win.document.documentElement.getAttribute("title");
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getTitle();
@@ -1317,42 +1316,42 @@ GeckoDriver.prototype.getTitle = functio
 
 /** Gets the current type of the window. */
 GeckoDriver.prototype.getWindowType = function(cmd, resp) {
   let win = this.getCurrentWindow();
   resp.body.value = win.document.documentElement.getAttribute("windowtype");
 };
 
 /** Gets the page source of the content document. */
-GeckoDriver.prototype.getPageSource = function(cmd, resp) {
+GeckoDriver.prototype.getPageSource = function*(cmd, resp) {
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let s = new win.XMLSerializer();
       resp.body.value = s.serializeToString(win.document);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.getPageSource();
       break;
   }
 };
 
 /** Go back in history. */
-GeckoDriver.prototype.goBack = function(cmd, resp) {
+GeckoDriver.prototype.goBack = function*(cmd, resp) {
   yield this.listener.goBack();
 };
 
 /** Go forward in history. */
-GeckoDriver.prototype.goForward = function(cmd, resp) {
+GeckoDriver.prototype.goForward = function*(cmd, resp) {
   yield this.listener.goForward();
 };
 
 /** Refresh the page. */
-GeckoDriver.prototype.refresh = function(cmd, resp) {
+GeckoDriver.prototype.refresh = function*(cmd, resp) {
   yield this.listener.refresh();
 };
 
 /**
  * Get the current window's handle. On desktop this typically corresponds
  * to the currently selected tab.
  *
  * Return an opaque server-assigned identifier to this window that
@@ -1522,17 +1521,17 @@ GeckoDriver.prototype.setWindowPosition 
 
 /**
  * Switch current top-level browsing context by name or server-assigned ID.
  * Searches for windows by name, then ID.  Content windows take precedence.
  *
  * @param {string} name
  *     Target name or ID of the window to switch to.
  */
-GeckoDriver.prototype.switchToWindow = function(cmd, resp) {
+GeckoDriver.prototype.switchToWindow = function*(cmd, resp) {
   let switchTo = cmd.parameters.name;
   let isB2G = this.appName == "B2G";
   let found;
 
   let getOuterWindowId = function(win) {
     let rv = win.QueryInterface(Ci.nsIInterfaceRequestor)
         .getInterface(Ci.nsIDOMWindowUtils)
         .outerWindowID;
@@ -1615,33 +1614,30 @@ GeckoDriver.prototype.getActiveFrame = f
       break;
 
     case Context.CONTENT:
       resp.body.value = this.currentFrameElement;
       break;
   }
 };
 
-/**
- *
- */
-GeckoDriver.prototype.switchToParentFrame = function (cmd, resp) {
+GeckoDriver.prototype.switchToParentFrame = function*(cmd, resp) {
   let res = yield this.listener.switchToParentFrame();
 };
 
 /**
  * Switch to a given frame within the current window.
  *
  * @param {Object} element
  *     A web element reference to the element to switch to.
  * @param {(string|number)} id
  *     If element is not defined, then this holds either the id, name,
  *     or index of the frame to switch to.
  */
-GeckoDriver.prototype.switchToFrame = function(cmd, resp) {
+GeckoDriver.prototype.switchToFrame = function*(cmd, resp) {
   let {id, element, focus} = cmd.parameters;
 
   let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   let curWindow = this.getCurrentWindow();
 
   let checkLoad = function() {
     let errorRegex = /about:.+(error)|(blocked)\?/;
     let curWindow = this.getCurrentWindow();
@@ -1706,17 +1702,17 @@ GeckoDriver.prototype.switchToFrame = fu
             }
           }
         }
 
         // else, assume iframe
         let frames = curWindow.document.getElementsByTagName("iframe");
         let numFrames = frames.length;
         for (let i = 0; i < numFrames; i++) {
-          if (XPCNativeWrapper(frames[i]) == XPCNativeWrapper(wantedFrame)) {
+          if (new XPCNativeWrapper(frames[i]) == new XPCNativeWrapper(wantedFrame)) {
             curWindow = frames[i].contentWindow;
             this.curFrame = curWindow;
             if (focus) {
               this.curFrame.focus();
             }
             checkTimer.initWithCallback(checkLoad.bind(this), 100, Ci.nsITimer.TYPE_ONE_SHOT);
             return;
           }
@@ -1831,17 +1827,17 @@ GeckoDriver.prototype.timeouts = functio
 
     default:
       this.pageTimeout = ms;
       break;
   }
 };
 
 /** Single tap. */
-GeckoDriver.prototype.singleTap = function(cmd, resp) {
+GeckoDriver.prototype.singleTap = function*(cmd, resp) {
   let {id, x, y} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       throw new WebDriverError("Command 'singleTap' is not available in chrome context");
 
     case Context.CONTENT:
       this.addFrameCloseListener("tap");
@@ -1855,17 +1851,17 @@ GeckoDriver.prototype.singleTap = functi
  *
  * @param {Object} value
  *     A nested array where the inner array represents each event,
  *     and the outer array represents a collection of events.
  *
  * @return {number}
  *     Last touch ID.
  */
-GeckoDriver.prototype.actionChain = function(cmd, resp) {
+GeckoDriver.prototype.actionChain = function*(cmd, resp) {
   let {chain, nextId} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       if (this.appName != "Firefox") {
         // be conservative until this has a use case and is established
         // to work as expected on b2g/fennec
         throw new WebDriverError(
@@ -1891,17 +1887,17 @@ GeckoDriver.prototype.actionChain = func
 /**
  * A multi-action chain.
  *
  * @param {Object} value
  *     A nested array where the inner array represents eache vent,
  *     the middle array represents a collection of events for each
  *     finger, and the outer array represents all fingers.
  */
-GeckoDriver.prototype.multiAction = function(cmd, resp) {
+GeckoDriver.prototype.multiAction = function*(cmd, resp) {
   switch (this.context) {
     case Context.CHROME:
       throw new WebDriverError("Command 'multiAction' is not available in chrome context");
 
     case Context.CONTENT:
       this.addFrameCloseListener("multi action chain");
       yield this.listener.multiAction(cmd.parameters.value, cmd.parameters.max_length);
       break;
@@ -1911,17 +1907,17 @@ GeckoDriver.prototype.multiAction = func
 /**
  * Find an element using the indicated search strategy.
  *
  * @param {string} using
  *     Indicates which search method to use.
  * @param {string} value
  *     Value the client is looking for.
  */
-GeckoDriver.prototype.findElement = function(cmd, resp) {
+GeckoDriver.prototype.findElement = function*(cmd, resp) {
   switch (this.context) {
     case Context.CHROME:
       resp.body.value = yield new Promise((resolve, reject) => {
         let win = this.getCurrentWindow();
         this.curBrowser.elementManager.find(
             {frame: win},
             cmd.parameters,
             this.searchTimeout,
@@ -1944,17 +1940,17 @@ GeckoDriver.prototype.findElement = func
 /**
  * Find elements using the indicated search strategy.
  *
  * @param {string} using
  *     Indicates which search method to use.
  * @param {string} value
  *     Value the client is looking for.
  */
-GeckoDriver.prototype.findElements = function(cmd, resp) {
+GeckoDriver.prototype.findElements = function*(cmd, resp) {
   switch (this.context) {
     case Context.CHROME:
       resp.body = yield new Promise((resolve, reject) => {
         let win = this.getCurrentWindow();
         this.curBrowser.elementManager.find(
             {frame: win},
             cmd.parameters,
             this.searchTimeout,
@@ -1970,34 +1966,34 @@ GeckoDriver.prototype.findElements = fun
         using: cmd.parameters.using,
         element: cmd.parameters.element,
         searchTimeout: this.searchTimeout});
       break;
   }
 };
 
 /** Return the active element on the page. */
-GeckoDriver.prototype.getActiveElement = function(cmd, resp) {
+GeckoDriver.prototype.getActiveElement = function*(cmd, resp) {
   resp.body.value = yield this.listener.getActiveElement();
 };
 
 /**
  * Send click event to element.
  *
  * @param {string} id
  *     Reference ID to the element that will be clicked.
  */
-GeckoDriver.prototype.clickElement = function(cmd, resp) {
+GeckoDriver.prototype.clickElement = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       yield this.interactions.clickElement({ frame: win },
-        this.curBrowser.elementManager, id)
+        this.curBrowser.elementManager, id);
       break;
 
     case Context.CONTENT:
       // We need to protect against the click causing an OOP frame to close.
       // This fires the mozbrowserclose event when it closes so we need to
       // listen for it and then just send an error back. The person making the
       // call should be aware something isnt right and handle accordingly
       this.addFrameCloseListener("click");
@@ -2009,17 +2005,17 @@ GeckoDriver.prototype.clickElement = fun
 /**
  * Get a given attribute of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
  * @param {string} name
  *     Name of the attribute to retrieve.
  */
-GeckoDriver.prototype.getElementAttribute = function(cmd, resp) {
+GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
   let {id, name} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, {frame: win});
       resp.body.value = utils.getElementAttribute(el, name);
       break;
@@ -2032,17 +2028,17 @@ GeckoDriver.prototype.getElementAttribut
 
 /**
  * Get the text of an element, if any.  Includes the text of all child
  * elements.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
  */
-GeckoDriver.prototype.getElementText = function(cmd, resp) {
+GeckoDriver.prototype.getElementText = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // for chrome, we look at text nodes, and any node with a "label" field
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, { frame: win });
       let lines = [];
@@ -2057,17 +2053,17 @@ GeckoDriver.prototype.getElementText = f
 };
 
 /**
  * Get the tag name of the element.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
  */
-GeckoDriver.prototype.getElementTagName = function(cmd, resp) {
+GeckoDriver.prototype.getElementTagName = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, {frame: win});
       resp.body.value = el.tagName.toLowerCase();
       break;
@@ -2079,17 +2075,17 @@ GeckoDriver.prototype.getElementTagName 
 };
 
 /**
  * Check if element is displayed.
  *
  * @param {string} id
  *     Reference ID to the element that will be inspected.
  */
-GeckoDriver.prototype.isElementDisplayed = function(cmd, resp) {
+GeckoDriver.prototype.isElementDisplayed = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       resp.body.value = yield this.interactions.isElementDisplayed(
         {frame: win}, this.curBrowser.elementManager, id);
       break;
@@ -2103,17 +2099,17 @@ GeckoDriver.prototype.isElementDisplayed
 /**
  * Return the property of the computed style of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  * @param {string} propertyName
  *     CSS rule that is being requested.
  */
-GeckoDriver.prototype.getElementValueOfCssProperty = function(cmd, resp) {
+GeckoDriver.prototype.getElementValueOfCssProperty = function*(cmd, resp) {
   let {id, propertyName: prop} = cmd.parameters;
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, { frame: win });
       let sty = win.document.defaultView.getComputedStyle(el, null);
       resp.body.value = sty.getPropertyValue(prop);
@@ -2126,17 +2122,17 @@ GeckoDriver.prototype.getElementValueOfC
 };
 
 /**
  * Check if element is enabled.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  */
-GeckoDriver.prototype.isElementEnabled = function(cmd, resp) {
+GeckoDriver.prototype.isElementEnabled = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
       let win = this.getCurrentWindow();
       resp.body.value = yield this.interactions.isElementEnabled(
         {frame: win}, this.curBrowser.elementManager, id);
@@ -2149,34 +2145,34 @@ GeckoDriver.prototype.isElementEnabled =
 },
 
 /**
  * Check if element is selected.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  */
-GeckoDriver.prototype.isElementSelected = function(cmd, resp) {
+GeckoDriver.prototype.isElementSelected = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // Selenium atom doesn't quite work here
       let win = this.getCurrentWindow();
       resp.body.value = yield this.interactions.isElementSelected(
         { frame: win }, this.curBrowser.elementManager, id);
       break;
 
     case Context.CONTENT:
       resp.body.value = yield this.listener.isElementSelected(id);
       break;
   }
 };
 
-GeckoDriver.prototype.getElementRect = function(cmd, resp) {
+GeckoDriver.prototype.getElementRect = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, { frame: win });
       let rect = el.getBoundingClientRect();
       resp.body = {
@@ -2196,17 +2192,17 @@ GeckoDriver.prototype.getElementRect = f
 /**
  * Send key presses to element after focusing on it.
  *
  * @param {string} id
  *     Reference ID to the element that will be checked.
  * @param {string} value
  *     Value to send to the element.
  */
-GeckoDriver.prototype.sendKeysToElement = function(cmd, resp) {
+GeckoDriver.prototype.sendKeysToElement = function*(cmd, resp) {
   let {id, value} = cmd.parameters;
 
   if (!value) {
     throw new InvalidArgumentError(`Expected character sequence: ${value}`);
   }
 
   switch (this.context) {
     case Context.CHROME:
@@ -2246,29 +2242,29 @@ GeckoDriver.prototype.sendKeysToElement 
       if (err) {
         throw err;
       }
       break;
   }
 };
 
 /** Sets the test name.  The test name is used for logging purposes. */
-GeckoDriver.prototype.setTestName = function(cmd, resp) {
+GeckoDriver.prototype.setTestName = function*(cmd, resp) {
   let val = cmd.parameters.value;
   this.testName = val;
   yield this.listener.setTestName({value: val});
 };
 
 /**
  * Clear the text of an element.
  *
  * @param {string} id
  *     Reference ID to the element that will be cleared.
  */
-GeckoDriver.prototype.clearElement = function(cmd, resp) {
+GeckoDriver.prototype.clearElement = function*(cmd, resp) {
   let id = cmd.parameters.id;
 
   switch (this.context) {
     case Context.CHROME:
       // the selenium atom doesn't work here
       let win = this.getCurrentWindow();
       let el = this.curBrowser.elementManager.getKnownElement(id, { frame: win });
       if (el.nodeName == "textbox") {
@@ -2284,24 +2280,24 @@ GeckoDriver.prototype.clearElement = fun
   }
 };
 
 /**
  * Switch to shadow root of the given host element.
  *
  * @param {string} id element id.
  */
-GeckoDriver.prototype.switchToShadowRoot = function(cmd, resp) {
+GeckoDriver.prototype.switchToShadowRoot = function*(cmd, resp) {
   let id;
   if (cmd.parameters) { id = cmd.parameters.id; }
   yield this.listener.switchToShadowRoot(id);
 };
 
 /** Add a cookie to the document. */
-GeckoDriver.prototype.addCookie = function(cmd, resp) {
+GeckoDriver.prototype.addCookie = function*(cmd, resp) {
   let cb = msg => {
     this.mm.removeMessageListener("Marionette:addCookie", cb);
     let cookie = msg.json;
     Services.cookies.add(
         cookie.domain,
         cookie.path,
         cookie.name,
         cookie.value,
@@ -2316,38 +2312,38 @@ GeckoDriver.prototype.addCookie = functi
 };
 
 /**
  * Get all the cookies for the current domain.
  *
  * This is the equivalent of calling {@code document.cookie} and parsing
  * the result.
  */
-GeckoDriver.prototype.getCookies = function(cmd, resp) {
+GeckoDriver.prototype.getCookies = function*(cmd, resp) {
   resp.body = yield this.listener.getCookies();
 };
 
 /** Delete all cookies that are visible to a document. */
-GeckoDriver.prototype.deleteAllCookies = function(cmd, resp) {
+GeckoDriver.prototype.deleteAllCookies = function*(cmd, resp) {
   let cb = msg => {
     let cookie = msg.json;
     cookieManager.remove(
         cookie.host,
         cookie.name,
         cookie.path,
         false);
     return true;
   };
   this.mm.addMessageListener("Marionette:deleteCookie", cb);
   yield this.listener.deleteAllCookies();
   this.mm.removeMessageListener("Marionette:deleteCookie", cb);
 };
 
 /** Delete a cookie by name. */
-GeckoDriver.prototype.deleteCookie = function(cmd, resp) {
+GeckoDriver.prototype.deleteCookie = function*(cmd, resp) {
   let cb = msg => {
     this.mm.removeMessageListener("Marionette:deleteCookie", cb);
     let cookie = msg.json;
     cookieManager.remove(
         cookie.host,
         cookie.name,
         cookie.path,
         false);
@@ -2502,21 +2498,21 @@ GeckoDriver.prototype.sessionTearDown = 
  * Processes the "deleteSession" request from the client by tearing down
  * the session and responding "ok".
  */
 GeckoDriver.prototype.deleteSession = function(cmd, resp) {
   this.sessionTearDown();
 };
 
 /** Returns the current status of the Application Cache. */
-GeckoDriver.prototype.getAppCacheStatus = function(cmd, resp) {
+GeckoDriver.prototype.getAppCacheStatus = function*(cmd, resp) {
   resp.body.value = yield this.listener.getAppCacheStatus();
 };
 
-GeckoDriver.prototype.importScript = function(cmd, resp) {
+GeckoDriver.prototype.importScript = function*(cmd, resp) {
   let script = cmd.parameters.script;
 
   let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
       .createInstance(Ci.nsIScriptableUnicodeConverter);
   converter.charset = "UTF-8";
   let result = {};
   let data = converter.convertToByteArray(cmd.parameters.script, result);
   let ch = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
@@ -2629,17 +2625,16 @@ GeckoDriver.prototype.takeScreenshot = f
       context.drawWindow(win, 0, 0, width, height, "rgb(255,255,255)", flags);
       let dataUrl = canvas.toDataURL("image/png", "");
       let data = dataUrl.substring(dataUrl.indexOf(",") + 1);
       resp.body.value = data;
       break;
 
     case Context.CONTENT:
       return this.listener.takeScreenshot(id, full, highlights);
-      break;
   }
 };
 
 /**
  * Get the current browser orientation.
  *
  * Will return one of the valid primary orientation values
  * portrait-primary, landscape-primary, portrait-secondary, or
--- a/testing/marionette/driver/marionette_driver/geckoinstance.py
+++ b/testing/marionette/driver/marionette_driver/geckoinstance.py
@@ -30,16 +30,21 @@ class GeckoInstance(object):
         "browser.warnOnQuit": False,
         "datareporting.healthreport.logging.consoleEnabled": False,
         "datareporting.healthreport.service.enabled": False,
         "datareporting.healthreport.service.firstRun": False,
         "datareporting.healthreport.uploadEnabled": False,
         "datareporting.policy.dataSubmissionEnabled": False,
         "datareporting.policy.dataSubmissionPolicyAccepted": False,
         "dom.ipc.reportProcessHangs": False,
+        # Only install add-ons from the profile and the application scope
+        # Also ensure that those are not getting disabled.
+        # see: https://developer.mozilla.org/en/Installing_extensions
+        "extensions.enabledScopes": 5,
+        "extensions.autoDisableScopes": 10,
         "focusmanager.testmode": True,
         "marionette.defaultPrefs.enabled": True,
         "startup.homepage_welcome_url": "about:blank",
         "toolkit.telemetry.enabled": False,
         # Until Bug 1238095 is fixed, we have to enable CPOWs in order
         # for Marionette tests to work properly.
         "dom.ipc.cpows.forbid-unsafe-from-browser": False,
     }
@@ -199,18 +204,16 @@ class DesktopInstance(GeckoInstance):
         'browser.safebrowsing.enabled': False,
         'browser.safebrowsing.malware.enabled': False,
         'browser.search.update': False,
         'browser.tabs.animate': False,
         'browser.tabs.warnOnClose': False,
         'browser.tabs.warnOnOpen': False,
         'browser.uitour.enabled': False,
         'dom.report_all_js_exceptions': True,
-        'extensions.enabledScopes': 5,
-        'extensions.autoDisableScopes': 10,
         'extensions.getAddons.cache.enabled': False,
         'extensions.installDistroAddons': False,
         'extensions.logging.enabled': True,
         'extensions.showMismatchUI': False,
         'extensions.update.enabled': False,
         'extensions.update.notifyUser': False,
         'geo.provider.testing': True,
         'javascript.options.showInConsole': True,
--- a/testing/marionette/unit.ini
+++ b/testing/marionette/unit.ini
@@ -1,13 +1,11 @@
 # 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/.
 
 # xpcshell unit tests for Marionette
 
 [DEFAULT]
-head =
-tail =
-skip-if = appname == "thunderbird"  # Thunderbird does not use marionette
+skip-if = appname == "thunderbird"
 
 [test_error.js]
 [test_message.js]
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -790,21 +790,16 @@ class MochitestArguments(ArgumentContain
 
         options.leakThresholds = {
             "default": options.defaultLeakThreshold,
             "tab": 10000,  # See dependencies of bug 1051230.
             # GMP rarely gets a log, but when it does, it leaks a little.
             "geckomediaplugin": 20000,
         }
 
-        # Bug 1091917 - We exit early in tab processes on Windows, so we don't
-        # get leak logs yet.
-        if mozinfo.isWin:
-            options.ignoreMissingLeaks.append("tab")
-
         # XXX We can't normalize test_paths in the non build_obj case here,
         # because testRoot depends on the flavor, which is determined by the
         # mach command and therefore not finalized yet. Conversely, test paths
         # need to be normalized here for the mach case.
         if options.test_paths and build_obj:
             # Normalize test paths so they are relative to test root
             options.test_paths = [build_obj._wrap_path_argument(p).relpath()
                                   for p in options.test_paths]
--- a/testing/mozharness/configs/android/android_panda_releng.py
+++ b/testing/mozharness/configs/android/android_panda_releng.py
@@ -166,16 +166,18 @@ config = {
                 "--app=%(app_name)s",
                 "--ignore-window-size",
                 "--bootstrap",
                 "--http-port=%(http_port)s",
                 "--ssl-port=%(ssl_port)s",
                 "--symbols-path=%(symbols_path)s",
                 "--extra-profile-file=reftest/fonts",
                 "--suite=reftest",
+                "--log-raw=%(raw_log_file)s",
+                "--log-errorsummary=%(error_summary_file)s",
             ],
             "tests": ["reftest/tests/layout/reftests/reftest.list"],
             "run_filename": "remotereftest.py",
             "testsdir": "reftest"
         },
         "robocop": {
             "options": [
                 "--dm_trans=sut",
--- a/testing/mozharness/configs/android/androidarm.py
+++ b/testing/mozharness/configs/android/androidarm.py
@@ -138,16 +138,18 @@ config = {
                 "--http-port=%(http_port)s",
                 "--ssl-port=%(ssl_port)s",
                 "--httpd-path",
                 "%(modules_dir)s",
                 "--symbols-path=%(symbols_path)s",
                 "--total-chunks=16",
                 "--extra-profile-file=fonts",
                 "--suite=reftest",
+                "--log-raw=%(raw_log_file)s",
+                "--log-errorsummary=%(error_summary_file)s",
             ],
             "tests": ["tests/layout/reftests/reftest.list"],
         },
         "crashtest": {
             "run_filename": "remotereftest.py",
             "testsdir": "reftest",
             "options": [
                 "--app=%(app)s",
--- a/testing/mozharness/configs/android/androidarm_4_3.py
+++ b/testing/mozharness/configs/android/androidarm_4_3.py
@@ -136,16 +136,18 @@ config = {
                 "--utility-path=%(utility_path)s",
                 "--http-port=%(http_port)s",
                 "--ssl-port=%(ssl_port)s",
                 "--httpd-path", "%(modules_dir)s",
                 "--symbols-path=%(symbols_path)s",
                 "--total-chunks=16",
                 "--extra-profile-file=fonts",
                 "--suite=reftest",
+                "--log-raw=%(raw_log_file)s",
+                "--log-errorsummary=%(error_summary_file)s",
             ],
             "tests": ["tests/layout/reftests/reftest.list",],
         },
         "reftest-debug": {
             "run_filename": "remotereftest.py",
             "testsdir": "reftest",
             "options": [
                 "--app=%(app)s",
--- a/testing/mozharness/configs/builds/releng_base_android_64_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_android_64_builds.py
@@ -27,16 +27,18 @@ config = {
     'enable_signing': True,
     # mock shtuff
     'mock_mozilla_dir':  '/builds/mock_mozilla',
     'mock_target': 'mozilla-centos6-x86_64-android',
     'mock_files': [
         ('/home/cltbld/.ssh', '/home/mock_mozilla/.ssh'),
         ('/home/cltbld/.hgrc', '/builds/.hgrc'),
         ('/home/cltbld/.boto', '/builds/.boto'),
+        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
+        ('/tools/tooltool.py', '/builds/tooltool.py'),
         ('/builds/mozilla-api.key', '/builds/mozilla-api.key'),
         ('/builds/mozilla-fennec-geoloc-api.key', '/builds/mozilla-fennec-geoloc-api.key'),
         ('/builds/crash-stats-api.token', '/builds/crash-stats-api.token'),
         ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
     ],
     'enable_ccache': True,
     'vcs_share_base': '/builds/hg-shared',
     'objdir': 'obj-firefox',
--- a/testing/mozharness/configs/builds/releng_base_linux_32_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_linux_32_builds.py
@@ -38,16 +38,17 @@ config = {
         ('/home/cltbld/.hgrc', '/builds/.hgrc'),
         ('/home/cltbld/.boto', '/builds/.boto'),
         ('/builds/gapi.data', '/builds/gapi.data'),
         ('/builds/relengapi.tok', '/builds/relengapi.tok'),
         ('/tools/tooltool.py', '/builds/tooltool.py'),
         ('/builds/mozilla-desktop-geoloc-api.key', '/builds/mozilla-desktop-geoloc-api.key'),
         ('/builds/crash-stats-api.token', '/builds/crash-stats-api.token'),
         ('/builds/adjust-sdk.token', '/builds/adjust-sdk.token'),
+        ('/builds/adjust-sdk-beta.token', '/builds/adjust-sdk-beta.token'),
         ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
     ],
     'enable_ccache': True,
     'vcs_share_base': '/builds/hg-shared',
     'objdir': 'obj-firefox',
     'tooltool_script': ["/builds/tooltool.py"],
     'tooltool_bootstrap': "setup.sh",
     'enable_count_ctors': True,
--- a/testing/mozharness/configs/builds/releng_base_linux_64_builds.py
+++ b/testing/mozharness/configs/builds/releng_base_linux_64_builds.py
@@ -38,16 +38,17 @@ config = {
         ('/home/cltbld/.hgrc', '/builds/.hgrc'),
         ('/home/cltbld/.boto', '/builds/.boto'),
         ('/builds/gapi.data', '/builds/gapi.data'),
         ('/builds/relengapi.tok', '/builds/relengapi.tok'),
         ('/tools/tooltool.py', '/builds/tooltool.py'),
         ('/builds/mozilla-desktop-geoloc-api.key', '/builds/mozilla-desktop-geoloc-api.key'),
         ('/builds/crash-stats-api.token', '/builds/crash-stats-api.token'),
         ('/builds/adjust-sdk.token', '/builds/adjust-sdk.token'),
+        ('/builds/adjust-sdk-beta.token', '/builds/adjust-sdk-beta.token'),
         ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
     ],
     'enable_ccache': True,
     'vcs_share_base': '/builds/hg-shared',
     'objdir': 'obj-firefox',
     'tooltool_script': ["/builds/tooltool.py"],
     'tooltool_bootstrap': "setup.sh",
     'enable_count_ctors': True,
--- a/testing/mozharness/configs/hazards/common.py
+++ b/testing/mozharness/configs/hazards/common.py
@@ -77,16 +77,18 @@ config = {
         'imake',  # required for makedepend!?!
         'pulseaudio-libs-devel',
         'freetype-2.3.11-6.el6_1.8.x86_64',
         'freetype-devel-2.3.11-6.el6_1.8.x86_64',
         'gstreamer-devel', 'gstreamer-plugins-base-devel',
     ],
     "mock_files": [
         ("/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"),
+        ('/home/cltbld/.hgrc', '/builds/.hgrc'),
+        ('/builds/relengapi.tok', '/builds/relengapi.tok'),
         ("/tools/tooltool.py", "/tools/tooltool.py"),
         ('/usr/local/lib/hgext', '/usr/local/lib/hgext'),
     ],
     "env_replacements": {
         "pythondir": PYTHON_DIR,
         "gccdir": "%(abs_work_dir)s/gcc",
         "sixgilldir": "%(abs_work_dir)s/sixgill",
     },
--- a/testing/mozharness/configs/unittests/linux_unittest.py
+++ b/testing/mozharness/configs/unittests/linux_unittest.py
@@ -152,17 +152,19 @@ config = {
             "run_filename": "runtestlist.py",
             "testsdir": "mozmill"
         },
         "reftest": {
             "options": [
                 "--appname=%(binary_path)s",
                 "--utility-path=tests/bin",
                 "--extra-profile-file=tests/bin/plugins",
-                "--symbols-path=%(symbols_path)s"
+                "--symbols-path=%(symbols_path)s",
+                "--log-raw=%(raw_log_file)s",
+                "--log-errorsummary=%(error_summary_file)s",
             ],
             "run_filename": "runreftest.py",
             "testsdir": "reftest"
         },
         "webapprt": {
             "options": [
                 "--app=%(app_path)s",
                 "--utility-path=tests/bin",
--- a/testing/mozharness/configs/unittests/win_unittest.py
+++ b/testing/mozharness/configs/unittests/win_unittest.py
@@ -115,17 +115,19 @@ config = {
             "run_filename": "runtestlist.py",
             "testsdir": "mozmill"
         },
         "reftest": {
             "options": [
                 "--appname=%(binary_path)s",
                 "--utility-path=tests/bin",
                 "--extra-profile-file=tests/bin/plugins",
-                "--symbols-path=%(symbols_path)s"
+                "--symbols-path=%(symbols_path)s",
+                "--log-raw=%(raw_log_file)s",
+                "--log-errorsummary=%(error_summary_file)s",
             ],
             "run_filename": "runreftest.py",
             "testsdir": "reftest"
         },
         "webapprt": {
             "options": [
                 "--app=%(app_path)s",
                 "--utility-path=tests/bin",
--- a/testing/mozharness/mozharness/base/vcs/mercurial.py
+++ b/testing/mozharness/mozharness/base/vcs/mercurial.py
@@ -415,16 +415,17 @@ class MercurialVCS(ScriptMixin, LogMixin
             self.exception(level='error')
             self.rmtree(dest)
 
     def share(self, source, dest, branch=None, revision=None):
         """Creates a new working directory in "dest" that shares history
         with "source" using Mercurial's share extension
         """
         self.info("Sharing %s to %s." % (source, dest))
+        self.mkdir_p(dest)
         if self.run_command(self.hg + ['share', '-U', source, dest],
                             error_list=HgErrorList):
             raise VCSException("Unable to share %s to %s!" % (source, dest))
         return self.update(dest, branch=branch, revision=revision)
 
     # End hg share methods 2}}}
 
     def ensure_repo_and_revision(self):
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -1146,17 +1146,17 @@ or run without that action (ie: --no-{ac
             c['tooltool_url'],
             c['tooltool_bootstrap'],
         ]
         cmd.extend(c['tooltool_script'])
         auth_file = self._get_tooltool_auth_file()
         if auth_file:
             cmd.extend(['--authentication-file', auth_file])
         self.info(str(cmd))
-        self.run_command(cmd, cwd=dirs['abs_src_dir'], halt_on_failure=True)
+        self.run_command_m(cmd, cwd=dirs['abs_src_dir'], halt_on_failure=True)
 
     def query_revision(self, source_path=None):
         """ returns the revision of the build
 
          first will look for it in buildbot_properties and then in
          buildbot_config. Failing that, it will actually poll the source of
          the repo if it exists yet.
 
--- a/testing/mozharness/mozharness/mozilla/tooltool.py
+++ b/testing/mozharness/mozharness/mozilla/tooltool.py
@@ -73,18 +73,26 @@ class TooltoolMixin(object):
         if auth_file and os.path.exists(auth_file):
             cmd.extend(['--authentication-file', auth_file])
 
         cmd.extend(['fetch', '-m', manifest, '-o'])
 
         if cache:
             cmd.extend(['-c', cache])
 
+        # when mock is enabled run tooltool in mock. We can't use
+        # run_command_m in all cases because it won't exist unless
+        # MockMixin is used on the parent class
+        if self.config.get('mock_target'):
+            cmd_runner = self.run_command_m
+        else:
+            cmd_runner = self.run_command
+
         self.retry(
-            self.run_command,
+            cmd_runner,
             args=(cmd, ),
             kwargs={'cwd': output_dir,
                     'error_list': TooltoolErrorList,
                     'privileged': privileged,
                     },
             good_statuses=(0, ),
             error_message="Tooltool %s fetch failed!" % manifest,
             error_level=FATAL,
deleted file mode 100755
--- a/testing/mozharness/scripts/merge_day/b2g_tag.py
+++ /dev/null
@@ -1,379 +0,0 @@
-#!/usr/bin/env python
-# ***** BEGIN LICENSE BLOCK *****
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. I