Merge inbound to mozilla-central. a=merge
authorshindli <shindli@mozilla.com>
Thu, 15 Mar 2018 12:15:17 +0200
changeset 408275 fcb11e93adf57210167de0b27b15433e9c3f45e4
parent 408221 68dfe5ee5b80ee99b7e389d739a30089f6f1e55d (current diff)
parent 408274 c71ee5e970f63c9e433ecad757a1145a78bad3ea (diff)
child 408282 cad403cafed9b17d1b801837abcd039a0bce82d5
child 408299 6de08b2d80c84e898decdec99318e09434e92d77
push id33630
push usershindli@mozilla.com
push dateThu, 15 Mar 2018 10:14:59 +0000
treeherdermozilla-central@fcb11e93adf5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/nsGkAtomList.h
dom/base/nsGkAtoms.cpp
dom/base/nsGkAtoms.h
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/workers/WorkerPrivate.cpp
js/src/jsapi.h
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/tests/unit/test_writeToGlobalPrototype.js
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
modules/libpref/init/all.js
security/nss/lib/freebl/poly1305-donna-x64-sse2-incremental-source.c
security/nss/lib/freebl/poly1305.c
security/nss/lib/freebl/poly1305.h
toolkit/components/telemetry/Histograms.json
toolkit/mozapps/extensions/AddonPathService.cpp
toolkit/mozapps/extensions/AddonPathService.h
toolkit/mozapps/extensions/amIAddonManager.idl
toolkit/mozapps/extensions/amIAddonPathService.idl
toolkit/mozapps/extensions/test/browser/browser_non_mpc.js
toolkit/mozapps/extensions/test/browser/browser_system_addons_are_e10s.js
toolkit/mozapps/extensions/test/xpcshell/test_addon_path_service.js
toolkit/mozapps/extensions/test/xpcshell/test_mapURIToAddonID.js
toolkit/mozapps/extensions/test/xpcshell/test_multiprocessCompatible.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1552,36 +1552,25 @@ pref("browser.tabs.remote.warmup.unloadD
 
 // For the about:tabcrashed page
 pref("browser.tabs.crashReporting.sendReport", true);
 pref("browser.tabs.crashReporting.includeURL", false);
 pref("browser.tabs.crashReporting.requestEmail", false);
 pref("browser.tabs.crashReporting.emailMe", false);
 pref("browser.tabs.crashReporting.email", "");
 
-// But don't allow non-MPC extensions by default on Nightly
-#if defined(NIGHTLY_BUILD)
-pref("extensions.allow-non-mpc-extensions", false);
-#endif
-
 pref("extensions.legacy.enabled", false);
 
 // How often to check for CPOW timeouts. CPOWs are only timed out by
 // the hang monitor.
 pref("dom.ipc.cpow.timeout", 500);
 
 // Causes access on unsafe CPOWs from browser code to throw by default.
 pref("dom.ipc.cpows.forbid-unsafe-from-browser", true);
 
-// Don't allow add-ons marked as multiprocessCompatible to use CPOWs.
-pref("dom.ipc.cpows.forbid-cpows-in-compat-addons", true);
-
-// ...except for these add-ons:
-pref("dom.ipc.cpows.allow-cpows-in-compat-addons", "{b9db16a4-6edc-47ec-a1f4-b86292ed211d},firegestures@xuldev.org,{DDC359D1-844A-42a7-9AA1-88A850A938A8},privateTab@infocatcher,mousegesturessuite@lemon_juice.addons.mozilla.org,treestyletab@piro.sakura.ne.jp,cliqz@cliqz.com,{AE93811A-5C9A-4d34-8462-F7B864FC4696},contextsearch2@lwz.addons.mozilla.org,{EF522540-89F5-46b9-B6FE-1829E2B572C6},{677a8f98-fd64-40b0-a883-b8c95d0cbf17},images@wink.su,fx-devtools,url_advisor@kaspersky.com,{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d},{dc572301-7619-498c-a57d-39143191b318},dta@downthemall.net,{86095750-AD15-46d8-BF32-C0789F7E6A32},screenwise-prod@google.com,{91aa5abe-9de4-4347-b7b5-322c38dd9271},secureLogin@blueimp.net,ich@maltegoetz.de,come.back.block.image.from@cat-in-136.blogspot.com,{7b1bf0b6-a1b9-42b0-b75d-252036438bdc},s3crypto@data,{1e0fd655-5aea-4b4c-a583-f76ef1e3af9c},akahuku.fx.sp@toshiakisp.github.io,{aff87fa2-a58e-4edd-b852-0a20203c1e17},{1018e4d6-728f-4b20-ad56-37578a4de76b},rehostimage@engy.us,lazarus@interclue.com,{b2e69492-2358-071a-7056-24ad0c3defb1},flashstopper@byo.co.il,{e4a8a97b-f2ed-450b-b12d-ee082ba24781},jid1-f3mYMbCpz2AZYl@jetpack,{8c550e28-88c9-4764-bb52-aa489cf2efcd},{37fa1426-b82d-11db-8314-0800200c9a66},{ac2cfa60-bc96-11e0-962b-0800200c9a66},igetter@presenta.net,killspinners@byo.co.il,abhere2@moztw.org,{fc6339b8-9581-4fc7-b824-dffcb091fcb7},wampi@wink.su,backtrack@byalexv.co.uk,Gladiator_X@mail.ru,{73a6fe31-595d-460b-a920-fcc0f8843232},{46551EC9-40F0-4e47-8E18-8E5CF550CFB8},acewebextension_unlisted@acestream.org,@screen_maker,yasearch@yandex.ru,sp@avast.com,s3google@translator,igetterextension@presenta.net,{C1A2A613-35F1-4FCF-B27F-2840527B6556},screenwise-testing@google.com,helper-sig@savefrom.net,ImageSaver@Merci.chao,proxtube@abz.agency,wrc@avast.com,{9AA46F4F-4DC7-4c06-97AF-5035170634FE},jid1-CikLKKPVkw6ipw@jetpack,artur.dubovoy@gmail.com,nlgfeb@nlgfeb.ext,{A065A84F-95B6-433A-A0C8-4C040B77CE8A},fdm_ffext@freedownloadmanager.org");
-
 // Enable e10s hang monitoring (slow script checking and plugin hang
 // detection).
 pref("dom.ipc.processHangMonitor", true);
 
 #ifdef DEBUG
 // Don't report hangs in DEBUG builds. They're too slow and often a
 // debugger is attached.
 pref("dom.ipc.reportProcessHangs", false);
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -253,16 +253,17 @@ skip-if = os == "mac" # Bug 1102331 - do
 [browser_bug719271.js]
 skip-if = os == "win" && debug && e10s # Bug 1315042
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug724239.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug734076.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug735471.js]
+uses-unsafe-cpows = true
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug749738.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug763468_perwindowpb.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug767836_perwindowpb.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug817947.js]
@@ -276,16 +277,17 @@ skip-if = os == "win" && debug && e10s #
 [browser_bug970746.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_bug1015721.js]
 skip-if = os == 'win'
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_accesskeys.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_clipboard.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_clipboard_pastefile.js]
 skip-if = true # Disabled due to the clipboard not supporting real file types yet (bug 1288773)
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_compacttheme.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_contentAreaClick.js]
@@ -342,16 +344,17 @@ skip-if = e10s # Bug 863514 - no gesture
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_invalid_uri_back_forward_manipulation.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_keywordBookmarklets.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_keywordSearch.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_keywordSearch_postData.js]
+uses-unsafe-cpows = true
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_lastAccessedTab.js]
 skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bug 969405)
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_menuButtonFitts.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_middleMouse_noJSPaste.js]
 subsuite = clipboard
@@ -546,16 +549,17 @@ support-files =
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_e10s_about_process.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_e10s_chrome_process.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_e10s_javascript.js]
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_blockHPKP.js]
+uses-unsafe-cpows = true
 tags = psm
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_windowactivation.js]
 support-files =
   file_window_activation.html
   file_window_activation2.html
 # DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
 [browser_contextmenu_childprocess.js]
--- a/browser/base/content/test/general/browser_clipboard.js
+++ b/browser/base/content/test/general/browser_clipboard.js
@@ -8,17 +8,17 @@ var testPage = "<body style='margin: 0'>
 
 add_task(async function() {
   let tab = BrowserTestUtils.addTab(gBrowser);
   let browser = gBrowser.getBrowserForTab(tab);
 
   gBrowser.selectedTab = tab;
 
   await promiseTabLoadEvent(tab, "data:text/html," + escape(testPage));
-  await SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
+  await SimpleTest.promiseFocus(browser);
 
   const modifier = (navigator.platform.includes("Mac")) ?
                    Ci.nsIDOMWindowUtils.MODIFIER_META :
                    Ci.nsIDOMWindowUtils.MODIFIER_CONTROL;
 
   function sendKey(message) {
     BrowserTestUtils.synthesizeKey(message.data.key,
                                    {code: message.data.code, accelKey: true},
@@ -128,17 +128,17 @@ add_task(async function() {
   await contextMenuShown;
 
   document.getElementById("context-copyimage-contents").doCommand();
 
   contextMenu.hidePopup();
   await promisePopupHidden(contextMenu);
 
   // Focus the content again
-  await SimpleTest.promiseFocus(browser.contentWindowAsCPOW);
+  await SimpleTest.promiseFocus(browser);
 
   await ContentTask.spawn(browser, { modifier, htmlPrefix, htmlPostfix }, async function(arg) {
     var doc = content.document;
     var main = doc.getElementById("main");
     main.focus();
 
     await new Promise((resolve, reject) => {
       addEventListener("paste", function copyEvent(event) {
--- a/browser/base/content/test/pageinfo/browser.ini
+++ b/browser/base/content/test/pageinfo/browser.ini
@@ -6,13 +6,14 @@ support-files =
 [browser_pageinfo_firstPartyIsolation.js]
 support-files =
   image.html
   ../general/audio.ogg
   ../general/moz.png
   ../general/video.ogg
 [browser_pageinfo_images.js]
 [browser_pageinfo_image_info.js]
+uses-unsafe-cpows = true
 skip-if = (os == 'linux' && e10s) # bug 1161699
 [browser_pageinfo_svg_image.js]
 support-files =
   svg_image.html
   ../general/title_test.svg
--- a/browser/base/content/test/popupNotifications/browser_popupNotification_2.js
+++ b/browser/base/content/test/popupNotifications/browser_popupNotification_2.js
@@ -170,17 +170,17 @@ var tests = [
     }
   },
   // Test that popupnotifications without popups have anchor icons shown
   { id: "Test#7",
     async run() {
       let notifyObj = new BasicNotification(this.id);
       notifyObj.anchorID = "geo-notification-icon";
       notifyObj.addOptions({neverShow: true});
-      let promiseTopic = promiseTopicObserved("PopupNotifications-updateNotShowing");
+      let promiseTopic = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
       showNotification(notifyObj);
       await promiseTopic;
       isnot(document.getElementById("geo-notification-icon").boxObject.width, 0,
             "geo anchor should be visible");
       goNext();
     }
   },
   // Test notification close button
--- a/browser/base/content/test/siteIdentity/browser.ini
+++ b/browser/base/content/test/siteIdentity/browser.ini
@@ -19,16 +19,17 @@ support-files =
 [browser_bug902156.js]
 tags = mcb
 support-files =
   file_bug902156.js
   file_bug902156_1.html
   file_bug902156_2.html
   file_bug902156_3.html
 [browser_bug906190.js]
+uses-unsafe-cpows = true
 tags = mcb
 support-files =
   file_bug906190_1.html
   file_bug906190_2.html
   file_bug906190_3_4.html
   file_bug906190_redirected.html
   file_bug906190.js
   file_bug906190.sjs
--- a/browser/base/content/test/urlbar/browser.ini
+++ b/browser/base/content/test/urlbar/browser.ini
@@ -69,17 +69,19 @@ support-files =
 [browser_urlbarDecode.js]
 [browser_urlbarDelete.js]
 [browser_urlbarEnter.js]
 [browser_urlbar_whereToOpen.js]
 [browser_urlbarEnterAfterMouseOver.js]
 skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
 [browser_urlbarFocusedCmdK.js]
 [browser_urlbarHashChangeProxyState.js]
+uses-unsafe-cpows = true
 [browser_urlbarKeepStateAcrossTabSwitches.js]
+uses-unsafe-cpows = true
 [browser_urlbarOneOffs.js]
 support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
 [browser_urlbarOneOffs_searchSuggestions.js]
 support-files =
   searchSuggestionEngine.xml
   searchSuggestionEngine.sjs
--- a/browser/components/contextualidentity/test/browser/browser.ini
+++ b/browser/components/contextualidentity/test/browser/browser.ini
@@ -12,16 +12,17 @@ support-files =
 [browser_favicon.js]
 [browser_forgetaboutsite.js]
 [browser_forgetAPI_cookie_getCookiesWithOriginAttributes.js]
 [browser_restore_getCookiesWithOriginAttributes.js]
 [browser_forgetAPI_EME_forgetThisSite.js]
 [browser_forgetAPI_quota_clearStoragesForPrincipal.js]
 [browser_newtabButton.js]
 [browser_usercontext.js]
+uses-unsafe-cpows = true
 [browser_usercontextid_tabdrop.js]
 skip-if = os == "mac" || os == "win" # Intermittent failure - bug 1268276
 [browser_windowName.js]
 tags = openwindow
 [browser_windowOpen.js]
 tags = openwindow
 [browser_serviceworkers.js]
 [browser_broadcastchannel.js]
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -702,17 +702,17 @@
        role="group"
        type="arrow"
        hidden="true"
        flip="slide"
        position="bottomcenter topright"
        tabspecific="true">
   <popupnotification id="extension-new-tab-notification"
                      popupid="extension-new-tab"
-                     label="&newTabControlled.header.message2;"
+                     label="&newTabControlled.header.message;"
                      buttonlabel="&newTabControlled.keepButton.label;"
                      buttonaccesskey="&newTabControlled.keepButton.accesskey;"
                      secondarybuttonlabel="&newTabControlled.disableButton.label;"
                      secondarybuttonaccesskey="&newTabControlled.disableButton.accesskey;"
                      closebuttonhidden="true"
                      dropmarkerhidden="true"
                      checkboxhidden="true">
     <popupnotificationcontent orient="vertical">
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -41,16 +41,17 @@ skip-if = os == "linux"
 [browser_923857_customize_mode_event_wrapping_during_reset.js]
 [browser_927717_customize_drag_empty_toolbar.js]
 
 [browser_934113_menubar_removable.js]
 # Because this test is about the menubar, it can't be run on mac
 skip-if = os == "mac"
 
 [browser_934951_zoom_in_toolbar.js]
+uses-unsafe-cpows = true
 [browser_938980_navbar_collapsed.js]
 [browser_938995_indefaultstate_nonremovable.js]
 [browser_940013_registerToolbarNode_calls_registerArea.js]
 [browser_940307_panel_click_closure_handling.js]
 [browser_940946_removable_from_navbar_customizemode.js]
 [browser_941083_invalidate_wrapper_cache_createWidget.js]
 [browser_942581_unregisterArea_keeps_placements.js]
 [browser_944887_destroyWidget_should_destroy_in_palette.js]
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus_urlPatterns.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_urlPatterns.js
@@ -251,17 +251,17 @@ add_task(async function() {
     ["documentUrlPatterns-patternMatches-contextLink", true],
     ["documentUrlPatterns-patternDoesNotMatch-contextAll", false],
     ["documentUrlPatterns-patternDoesNotMatch-contextImage", false],
     ["documentUrlPatterns-patternDoesNotMatch-contextLink", false],
   ];
   await confirmContextMenuItems(contextMenu, expected);
   await closeContextMenu();
 
-  contextMenu = await openContextMenuInFrame("frame");
+  contextMenu = await openContextMenuInFrame("#frame");
   expected = [
     ["documentUrlPatterns-patternMatches-contextAll", true],
     ["documentUrlPatterns-patternMatches-contextFrame", true],
   ];
   await confirmContextMenuItems(contextMenu, expected);
   await closeContextMenu();
 
   await extension.unload();
--- a/browser/components/extensions/test/browser/browser_ext_menus.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus.js
@@ -245,27 +245,27 @@ add_task(async function test_onclick_fra
   }
 
   const extension = ExtensionTestUtils.loadExtension({manifest, background});
   const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
 
   await extension.startup();
   await extension.awaitMessage("ready");
 
-  async function click(selectorOrId) {
-    const func = (selectorOrId == "body") ? openContextMenu : openContextMenuInFrame;
-    const menu = await func(selectorOrId);
+  async function click(selector) {
+    const func = selector === "body" ? openContextMenu : openContextMenuInFrame;
+    const menu = await func(selector);
     const items = menu.getElementsByAttribute("label", "modify");
     await closeExtensionContextMenu(items[0]);
     return extension.awaitMessage("click");
   }
 
   let info = await click("body");
   is(info.frameId, 0, "top level click");
-  info = await click("frame");
+  info = await click("#frame");
   isnot(info.frameId, undefined, "frame click, frameId is not undefined");
   isnot(info.frameId, 0, "frame click, frameId probably okay");
 
   await BrowserTestUtils.removeTab(tab);
   await extension.unload();
 });
 
 add_task(async function test_multiple_contexts_init() {
--- a/browser/components/extensions/test/browser/browser_ext_menus_events.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus_events.js
@@ -352,17 +352,17 @@ add_task(async function test_show_hide_f
       pageUrl: PAGE,
       frameUrl: PAGE_BASE + "context_frame.html",
     },
     async doOpenMenu() {
       frameId = await ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
         let {contentWindow} = content.document.getElementById("frame");
         return WebNavigationFrames.getFrameId(contentWindow);
       });
-      await openContextMenuInFrame("frame");
+      await openContextMenuInFrame("#frame");
     },
     async doCloseMenu() {
       await closeExtensionContextMenu();
     },
   });
 });
 
 add_task(async function test_show_hide_password() {
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -284,22 +284,20 @@ async function openContextMenuInSidebar(
   let browser = SidebarUI.browser.contentDocument.getElementById("webext-panels-browser");
   let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
   await BrowserTestUtils.synthesizeMouseAtCenter(selector, {type: "mousedown", button: 2}, browser);
   await BrowserTestUtils.synthesizeMouseAtCenter(selector, {type: "contextmenu"}, browser);
   await popupShownPromise;
   return contentAreaContextMenu;
 }
 
-async function openContextMenuInFrame(frameId) {
+async function openContextMenuInFrame(frameSelector) {
   let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
   let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
-  let doc = gBrowser.selectedBrowser.contentDocumentAsCPOW;
-  let frame = doc.getElementById(frameId);
-  EventUtils.synthesizeMouseAtCenter(frame.contentDocument.body, {type: "contextmenu"}, frame.contentWindow);
+  await BrowserTestUtils.synthesizeMouseAtCenter([frameSelector, "body"], {type: "contextmenu"}, gBrowser.selectedBrowser);
   await popupShownPromise;
   return contentAreaContextMenu;
 }
 
 async function openContextMenu(selector = "#img1") {
   let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
   let popupShownPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popupshown");
   await BrowserTestUtils.synthesizeMouseAtCenter(selector, {type: "mousedown", button: 2}, gBrowser.selectedBrowser);
--- a/browser/extensions/onboarding/test/browser/browser.ini
+++ b/browser/extensions/onboarding/test/browser/browser.ini
@@ -8,11 +8,13 @@ skip-if = debug || os == "mac" # Full ke
 [browser_onboarding_notification.js]
 [browser_onboarding_notification_2.js]
 [browser_onboarding_notification_3.js]
 [browser_onboarding_notification_4.js]
 [browser_onboarding_notification_5.js]
 [browser_onboarding_notification_click_auto_complete_tour.js]
 [browser_onboarding_select_default_tour.js]
 [browser_onboarding_skip_tour.js]
+uses-unsafe-cpows = true
 [browser_onboarding_tours.js]
 [browser_onboarding_tourset.js]
+uses-unsafe-cpows = true
 [browser_onboarding_uitour.js]
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -969,17 +969,17 @@ you can use these alternative items. Oth
 <!ENTITY updateRestart.message2 "After a quick restart, &brandShorterName; will restore all your open tabs and windows that are not in Private Browsing mode.">
 <!ENTITY updateRestart.header.message2 "Restart to update &brandShorterName;.">
 <!ENTITY updateRestart.acceptButton.label "Restart and Restore">
 <!ENTITY updateRestart.acceptButton.accesskey "R">
 <!ENTITY updateRestart.cancelButton.label "Not Now">
 <!ENTITY updateRestart.cancelButton.accesskey "N">
 <!ENTITY updateRestart.panelUI.label2 "Restart to update &brandShorterName;">
 
-<!ENTITY newTabControlled.header.message2 "Your New Tab has changed.">
+<!ENTITY newTabControlled.header.message "Your New Tab has changed.">
 <!ENTITY newTabControlled.keepButton.label "Keep Changes">
 <!ENTITY newTabControlled.keepButton.accesskey "K">
 <!ENTITY newTabControlled.disableButton.label "Disable Extension">
 <!ENTITY newTabControlled.disableButton.accesskey "D">
 
 <!ENTITY pageActionButton.tooltip "Page actions">
 <!ENTITY pageAction.addToUrlbar.label "Add to Address Bar">
 <!ENTITY pageAction.removeFromUrlbar.label "Remove from Address Bar">
--- a/browser/modules/test/browser/browser_BrowserErrorReporter.js
+++ b/browser/modules/test/browser/browser_BrowserErrorReporter.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 ChromeUtils.import("resource:///modules/BrowserErrorReporter.jsm", this);
 
-Cu.importGlobalProperties(["fetch"]);
-
 /* global sinon */
 Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
 registerCleanupFunction(function() {
   delete window.sinon;
 });
 
 const PREF_ENABLED = "browser.chrome.errorReporter.enabled";
 const PREF_PROJECT_ID = "browser.chrome.errorReporter.projectId";
--- a/browser/modules/test/browser/browser_ContentSearch.js
+++ b/browser/modules/test/browser/browser_ContentSearch.js
@@ -1,18 +1,16 @@
 /* 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/. */
 
 const TEST_MSG = "ContentSearchTest";
 const CONTENT_SEARCH_MSG = "ContentSearch";
 const TEST_CONTENT_SCRIPT_BASENAME = "contentSearch.js";
 
-Cu.importGlobalProperties(["XMLHttpRequest"]);
-
 var gMsgMan;
 /* import-globals-from ../../../components/search/test/head.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/browser/components/search/test/head.js",
   this);
 
 let originalEngine = Services.search.currentEngine;
 
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -129,177 +129,241 @@ support-files =
   head.js
   sjs_post-page.sjs
   sjs_random-javascript.sjs
   testactors.js
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/shared/test/shared-head.js
 
 [browser_dbg_aaa_run_first_leaktest.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_addon-modules.js]
 skip-if = e10s # TODO
 tags = addons
 [browser_dbg_addon-modules-unpacked.js]
 skip-if = e10s # TODO
 tags = addons
 [browser_dbg_addon-console.js]
 skip-if = e10s && debug || os == 'win' # bug 1005274
 tags = addons
 [browser_dbg_auto-pretty-print-01.js]
+uses-unsafe-cpows = true
 [browser_dbg_auto-pretty-print-02.js]
+uses-unsafe-cpows = true
 [browser_dbg_auto-pretty-print-03.js]
+uses-unsafe-cpows = true
 [browser_dbg_bfcache.js]
 skip-if = e10s || true # bug 1113935
 [browser_dbg_blackboxing-01.js]
+uses-unsafe-cpows = true
 [browser_dbg_blackboxing-02.js]
+uses-unsafe-cpows = true
 [browser_dbg_blackboxing-03.js]
+uses-unsafe-cpows = true
 [browser_dbg_blackboxing-04.js]
+uses-unsafe-cpows = true
 [browser_dbg_blackboxing-05.js]
 skip-if = true # Bug 1385304
 [browser_dbg_blackboxing-06.js]
+uses-unsafe-cpows = true
 [browser_dbg_blackboxing-07.js]
+uses-unsafe-cpows = true
 [browser_dbg_breadcrumbs-access.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-in-anon.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-next.js]
 skip-if = true # Bug 1437712
 [browser_dbg_break-on-next-console.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-01.js]
 skip-if = true # bug 1368908
 [browser_dbg_break-on-dom-02.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-03.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-04.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-05.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-06.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-07.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-08.js]
+uses-unsafe-cpows = true
 [browser_dbg_break-on-dom-event-01.js]
 skip-if = e10s || os == "mac" || e10s # Bug 895426
 [browser_dbg_break-on-dom-event-02.js]
 skip-if = e10s # TODO
 [browser_dbg_break-unselected.js]
 [browser_dbg_breakpoints-actual-location.js]
+uses-unsafe-cpows = true
 [browser_dbg_breakpoints-actual-location2.js]
+uses-unsafe-cpows = true
 [browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_breakpoints-button-01.js]
+uses-unsafe-cpows = true
 [browser_dbg_breakpoints-button-02.js]
+uses-unsafe-cpows = true
 [browser_dbg_breakpoints-condition-thrown-message.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_breakpoints-contextmenu-add.js]
+uses-unsafe-cpows = true
 [browser_dbg_breakpoints-contextmenu.js]
+uses-unsafe-cpows = true
 [browser_dbg_breakpoints-disabled-reload.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_breakpoints-editor.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_breakpoints-eval.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_breakpoints-highlight.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_breakpoints-new-script.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_breakpoints-other-tabs.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_breakpoints-pane.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_breakpoints-reload.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_bug-896139.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_chrome-create.js]
 skip-if = (e10s && debug) || (verify && os == "linux") # Exit code mismatch with verify
 [browser_dbg_chrome-debugging.js]
 skip-if = e10s && debug
 [browser_dbg_clean-exit-window.js]
 skip-if = true # Bug 933950 (leaky test)
 [browser_dbg_clean-exit.js]
 skip-if = true # Bug 1044985 (racy test)
 [browser_dbg_closure-inspection.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_cmd-blackbox.js]
 skip-if = e10s && debug
 [browser_dbg_cmd-break.js]
 skip-if = e10s # TODO
 [browser_dbg_cmd-dbg.js]
 skip-if = e10s # TODO
 [browser_dbg_conditional-breakpoints-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_conditional-breakpoints-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_conditional-breakpoints-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_conditional-breakpoints-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_conditional-breakpoints-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_console-eval.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_console-named-eval.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_server-conditional-bp-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_server-conditional-bp-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_server-conditional-bp-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_server-conditional-bp-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_server-conditional-bp-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_controller-evaluate-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_controller-evaluate-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_debugger-statement.js]
 skip-if = e10s && debug
 [browser_dbg_editor-contextmenu.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_editor-mode.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_event-listeners-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_event-listeners-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_event-listeners-03.js]
 skip-if = e10s && debug
 [browser_dbg_file-reload.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_function-display-name.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_global-method-override.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_globalactor.js]
 skip-if = e10s # TODO
 [browser_dbg_hide-toolbar-buttons.js]
 skip-if = e10s
 [browser_dbg_host-layout.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_jump-to-function-definition.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_iframes.js]
 skip-if = e10s # TODO
 [browser_dbg_instruments-pane-collapse.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_instruments-pane-collapse_keyboard.js]
+uses-unsafe-cpows = true
 skip-if = (os == 'mac' && e10s && debug) # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control
 [browser_dbg_interrupts.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_listaddons.js]
 skip-if = e10s && debug
 tags = addons
 [browser_dbg_listtabs-01.js]
 skip-if = e10s # TODO
 [browser_dbg_listtabs-02.js]
 skip-if = true # Never worked for remote frames, needs a mock DebuggerServerConnection
 [browser_dbg_listtabs-03.js]
 skip-if = e10s && debug
 [browser_dbg_listworkers.js]
 [browser_dbg_location-changes-01-simple.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_location-changes-02-blank.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_location-changes-03-new.js]
 skip-if = e10s # TODO
 [browser_dbg_location-changes-04-breakpoint.js]
 skip-if = e10s # TODO
 [browser_dbg_multiple-windows.js]
 skip-if = e10s # TODO
 [browser_dbg_navigation.js]
--- a/devtools/client/debugger/test/mochitest/browser2.ini
+++ b/devtools/client/debugger/test/mochitest/browser2.ini
@@ -129,26 +129,32 @@ support-files =
   head.js
   sjs_post-page.sjs
   sjs_random-javascript.sjs
   testactors.js
   !/devtools/client/commandline/test/helpers.js
   !/devtools/client/shared/test/shared-head.js
 
 [browser_dbg_no-dangling-breakpoints.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_no-page-sources.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_on-pause-highlight.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_on-pause-raise.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug || os == "linux" # Bug 888811 & bug 891176
 [browser_dbg_optimized-out-vars.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_panel-size.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_parser-01.js]
 skip-if = e10s && debug
 [browser_dbg_parser-02.js]
 skip-if = e10s && debug
 [browser_dbg_parser-03.js]
 skip-if = e10s && debug
 [browser_dbg_parser-04.js]
@@ -167,297 +173,427 @@ skip-if = e10s && debug
 skip-if = e10s && debug
 [browser_dbg_parser-11.js]
 [browser_dbg_parser-computed-name.js]
 [browser_dbg_parser-function-defaults.js]
 [browser_dbg_parser-spread-expression.js]
 [browser_dbg_parser-template-strings.js]
 skip-if = e10s && debug
 [browser_dbg_pause-exceptions-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pause-exceptions-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pause-no-step.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pause-resume.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pause-warning.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_paused-keybindings.js]
 skip-if = e10s
 [browser_dbg_post-page.js]
+uses-unsafe-cpows = true
 [browser_dbg_pretty-print-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-06.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-07.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-08.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-09.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-10.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-11.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-12.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-13.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_pretty-print-on-paused.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_progress-listener-bug.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_promises-allocation-stack.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_promises-chrome-allocation-stack.js]
+uses-unsafe-cpows = true
 skip-if = true # Bug 1177730
 [browser_dbg_promises-fulfillment-stack.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_promises-rejection-stack.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_reload-preferred-script-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_reload-preferred-script-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_reload-same-script.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_scripts-switching-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_scripts-switching-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_scripts-switching-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-autofill-identifier.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-basic-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-basic-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-basic-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-basic-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-global-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-global-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-global-03.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_search-global-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-global-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-global-06.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-popup-jank.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-sources-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-sources-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-sources-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_search-symbols.js]
+uses-unsafe-cpows = true
 skip-if = (e10s && debug) || os == "linux" # Bug 1132375
 [browser_dbg_searchbox-help-popup-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_searchbox-help-popup-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_searchbox-parse.js]
+uses-unsafe-cpows = true
 skip-if = (debug) || (os == 'linux' && asan) # asan, bug 1313861, debug: bug 1313861
 [browser_dbg_source-maps-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_source-maps-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_source-maps-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_source-maps-04.js]
 skip-if = e10s # Bug 1093535
 [browser_dbg_sources-cache.js]
+uses-unsafe-cpows = true
 [browser_dbg_sources-contextmenu-01.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_sources-contextmenu-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_sources-eval-01.js]
 skip-if = true # non-named eval sources turned off for now, bug 1124106
 [browser_dbg_sources-eval-02.js]
+uses-unsafe-cpows = true
 [browser_dbg_sources-iframe-reload.js]
+uses-unsafe-cpows = true
 [browser_dbg_sources-keybindings.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (e10s && debug) || (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_sources-labels.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_sources-large.js]
+uses-unsafe-cpows = true
 [browser_dbg_sources-sorting.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_sources-bookmarklet.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_sources-webext-contentscript.js]
+uses-unsafe-cpows = true
 [browser_dbg_split-console-paused-reload.js]
 skip-if = true # Bug 1288348 - previously e10s && debug
 [browser_dbg_stack-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_stack-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_stack-03.js]
 skip-if = e10s || (!e10s && os == "win") || coverage # TODO, win !e10s: Bug 1391369, coverage: Bug 1400683
 [browser_dbg_stack-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug || (!e10s && os == "win") # Bug 1391369
 [browser_dbg_stack-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && (debug || asan) || (!e10s && os == "win") # timeouts, Bug 1391369
 [browser_dbg_stack-06.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug || (!e10s && os == "win") # Bug 1391369
 [browser_dbg_stack-07.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug || (!e10s && os == "win") # Bug 1391369
 [browser_dbg_stack-contextmenu-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_stack-contextmenu-02.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (e10s && debug) || (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_step-out.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_tabactor-01.js]
 skip-if = e10s # TODO
 [browser_dbg_tabactor-02.js]
 skip-if = e10s # TODO
 [browser_dbg_terminate-on-tab-close.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-06.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-07.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-08.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-accessibility.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (e10s && debug) || (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_dbg_variables-view-data.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-cancel.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-click.js]
 skip-if = e10s || (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
 [browser_dbg_variables-view-edit-getset-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-getset-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-value-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-value-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-edit-watch.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-pref.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-filter-searchbox.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-frame-parameters-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-frame-parameters-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-frame-parameters-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-frame-with.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-frozen-sealed-nonext.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-hide-non-enums.js]
+uses-unsafe-cpows = true
 [browser_dbg_variables-view-large-array-buffer.js]
+uses-unsafe-cpows = true
 [browser_dbg_variables-view-map-set.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-override-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-override-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-04.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-05.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-06.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-07.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-08.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-09.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-10.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-11.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-12.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-13.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-14.js]
 skip-if = true # Bug 1029545
 [browser_dbg_variables-view-popup-15.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-popup-16.js]
+uses-unsafe-cpows = true
 skip-if = e10s  && debug
 [browser_dbg_variables-view-popup-17.js]
+uses-unsafe-cpows = true
 skip-if = e10s  && debug
 [browser_dbg_variables-view-reexpand-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-reexpand-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-reexpand-03.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_variables-view-webidl.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_watch-expressions-01.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_watch-expressions-02.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_worker-console-01.js]
 skip-if = true # bug 1368569
 [browser_dbg_worker-console-02.js]
 skip-if = e10s && debug
 [browser_dbg_worker-console-03.js]
 skip-if = debug # bug 1334683
 [browser_dbg_worker-console-04.js]
 skip-if = e10s && debug
 [browser_dbg_worker-source-map.js]
+uses-unsafe-cpows = true
 skip-if = e10s && debug
 [browser_dbg_worker-window.js]
 skip-if = e10s && debug
 [browser_dbg_WorkerActor.attach.js]
 skip-if = e10s && debug
 [browser_dbg_WorkerActor.attachThread.js]
 skip-if = e10s && debug
 [browser_dbg_split-console-keypress.js]
+uses-unsafe-cpows = true
 skip-if = (debug || os == "linux") # Bug 1214439
--- a/devtools/client/framework/test/browser.ini
+++ b/devtools/client/framework/test/browser.ini
@@ -125,9 +125,9 @@ skip-if = os == "mac" && os_version == "
 [browser_toolbox_window_title_changes.js]
 [browser_toolbox_window_title_frame_select.js]
 [browser_toolbox_zoom.js]
 [browser_two_tabs.js]
 # We want these tests to run for mochitest-dt as well, so we include them here:
 [../../../../browser/base/content/test/static/browser_parsable_css.js]
 skip-if = debug || asan || (os == 'linux' && bits == 32) # no point in running on both opt and debug, and will likely intermittently timeout on debug
 [../../../../browser/base/content/test/static/browser_all_files_referenced.js]
-skip-if = debug || asan || (os == 'linux' && bits == 32) # no point in running on both opt and debug, and will likely intermittently timeout on debug
+skip-if = debug || asan || bits == 32 # no point in running on both opt and debug, and will likely intermittently timeout on debug
--- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js
+++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js
@@ -465,16 +465,27 @@ class BoxModelMain extends PureComponent
         ref: div => {
           this.positionLayout = div;
         },
         onClick: this.onLevelClick,
         onKeyDown: this.onKeyDown,
         onMouseOver: this.onHighlightMouseOver,
         onMouseOut: this.props.onHideBoxModelHighlighter,
       },
+      displayPosition ?
+        dom.span(
+          {
+            className: "boxmodel-legend",
+            "data-box": "position",
+            title: BOXMODEL_L10N.getStr("boxmodel.position"),
+          },
+          BOXMODEL_L10N.getStr("boxmodel.position")
+        )
+        :
+        null,
       dom.div(
         {
           className: "boxmodel-box"
         },
         dom.span(
           {
             className: "boxmodel-legend",
             "data-box": "margin",
--- a/devtools/client/inspector/boxmodel/test/browser_boxmodel_guides.js
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_guides.js
@@ -38,17 +38,17 @@ add_task(async function() {
   await testGuideOnLayoutHover(elt, "padding", inspector);
 
   elt = boxmodel.document.querySelector(".boxmodel-content");
   await testGuideOnLayoutHover(elt, "content", inspector);
 });
 
 async function testGuideOnLayoutHover(elt, expectedRegion, inspector) {
   info("Synthesizing mouseover on the boxmodel-view");
-  EventUtils.synthesizeMouse(elt, 2, 2, {type: "mouseover"},
+  EventUtils.synthesizeMouse(elt, 50, 2, {type: "mouseover"},
     elt.ownerDocument.defaultView);
 
   info("Waiting for the node-highlight event from the toolbox");
   await inspector.toolbox.once("node-highlight");
 
   // Wait for the next event tick to make sure the remaining part of the
   // test is executed after finishing synthesizing mouse event.
   await new Promise(executeSoon);
--- a/devtools/client/jsonview/test/browser.ini
+++ b/devtools/client/jsonview/test/browser.ini
@@ -19,41 +19,64 @@ support-files =
   valid_json.json
   valid_json.json^headers^
   !/devtools/client/commandline/test/head.js
   !/devtools/client/framework/test/head.js
   !/devtools/client/shared/test/frame-script-utils.js
   !/devtools/client/shared/test/shared-head.js
 
 [browser_json_refresh.js]
+uses-unsafe-cpows = true
 [browser_jsonview_bug_1380828.js]
+uses-unsafe-cpows = true
 [browser_jsonview_chunked_json.js]
 support-files =
   chunked_json.sjs
 [browser_jsonview_content_type.js]
+uses-unsafe-cpows = true
 [browser_jsonview_copy_headers.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_jsonview_copy_json.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_jsonview_copy_rawdata.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_jsonview_csp_json.js]
+uses-unsafe-cpows = true
 [browser_jsonview_empty_object.js]
+uses-unsafe-cpows = true
 [browser_jsonview_encoding.js]
+uses-unsafe-cpows = true
 [browser_jsonview_filter.js]
+uses-unsafe-cpows = true
 [browser_jsonview_ignore_charset.js]
+uses-unsafe-cpows = true
 [browser_jsonview_invalid_json.js]
+uses-unsafe-cpows = true
 [browser_jsonview_manifest.js]
+uses-unsafe-cpows = true
 [browser_jsonview_nojs.js]
+uses-unsafe-cpows = true
 [browser_jsonview_nul.js]
+uses-unsafe-cpows = true
 [browser_jsonview_object-type.js]
+uses-unsafe-cpows = true
 [browser_jsonview_row_selection.js]
+uses-unsafe-cpows = true
 [browser_jsonview_save_json.js]
+uses-unsafe-cpows = true
 support-files =
   !/toolkit/content/tests/browser/common/mockTransfer.js
 [browser_jsonview_serviceworker.js]
+uses-unsafe-cpows = true
 [browser_jsonview_slash.js]
+uses-unsafe-cpows = true
 [browser_jsonview_theme.js]
+uses-unsafe-cpows = true
 [browser_jsonview_url_linkification.js]
+uses-unsafe-cpows = true
 [browser_jsonview_valid_json.js]
+uses-unsafe-cpows = true
--- a/devtools/client/locales/en-US/boxmodel.properties
+++ b/devtools/client/locales/en-US/boxmodel.properties
@@ -10,16 +10,20 @@
 # You want to make that choice consistent across the developer tools.
 # A good criteria is the language in which you'd find the best
 # documentation on web development on the web.
 
 # LOCALIZATION NOTE (boxmodel.title) This is the title of the box model panel and is
 # displayed as a label.
 boxmodel.title=Box Model
 
+# LOCALIZATION NOTE (boxmodel.position) This refers to the position in the box model and
+# might be displayed as a label or as a tooltip.
+boxmodel.position=position
+
 # LOCALIZATION NOTE (boxmodel.margin) This refers to the margin in the box model and
 # might be displayed as a label or as a tooltip.
 boxmodel.margin=margin
 
 # LOCALIZATION NOTE (boxmodel.border) This refers to the border in the box model and
 # might be displayed as a label or as a tooltip.
 boxmodel.border=border
 
--- a/devtools/client/scratchpad/test/browser.ini
+++ b/devtools/client/scratchpad/test/browser.ini
@@ -5,43 +5,46 @@ support-files = head.js
 
 [browser_scratchpad_autocomplete.js]
 [browser_scratchpad_browser_last_window_closing.js]
 [browser_scratchpad_reset_undo.js]
 [browser_scratchpad_display_outputs_errors.js]
 [browser_scratchpad_eval_func.js]
 [browser_scratchpad_goto_line_ui.js]
 [browser_scratchpad_reload_and_run.js]
+uses-unsafe-cpows = true
 [browser_scratchpad_display_non_error_exceptions.js]
 [browser_scratchpad_modeline.js]
 [browser_scratchpad_chrome_context_pref.js]
 [browser_scratchpad_help_key.js]
 [browser_scratchpad_recent_files.js]
 [browser_scratchpad_confirm_close.js]
 disabled=bug 807234 becoming basically permanent
 [browser_scratchpad_sessions.js]
 [browser_scratchpad_tab.js]
 [browser_scratchpad_wrong_window_focus.js]
 [browser_scratchpad_unsaved.js]
 [browser_scratchpad_falsy.js]
 [browser_scratchpad_edit_ui_updates.js]
 [browser_scratchpad_revert_to_saved.js]
 [browser_scratchpad_run_error_goto_line.js]
 [browser_scratchpad_contexts.js]
+uses-unsafe-cpows = true
 [browser_scratchpad_execute_print.js]
 [browser_scratchpad_files.js]
 [browser_scratchpad_initialization.js]
 [browser_scratchpad_inspect.js]
 [browser_scratchpad_inspect_primitives.js]
 [browser_scratchpad_long_string.js]
 [browser_scratchpad_open.js]
 support-files = NS_ERROR_ILLEGAL_INPUT.txt
 [browser_scratchpad_open_error_console.js]
 [browser_scratchpad_throw_output.js]
 [browser_scratchpad_pprint-02.js]
 [browser_scratchpad_pprint.js]
 [browser_scratchpad_pprint_error_goto_line.js]
 [browser_scratchpad_restore.js]
 [browser_scratchpad_tab_switch.js]
+uses-unsafe-cpows = true
 [browser_scratchpad_ui.js]
 [browser_scratchpad_close_toolbox.js]
 [browser_scratchpad_remember_view_options.js]
 [browser_scratchpad_disable_view_menu_items.js]
--- a/devtools/client/sourceeditor/test/browser.ini
+++ b/devtools/client/sourceeditor/test/browser.ini
@@ -36,14 +36,17 @@ support-files =
 [browser_editor_history.js]
 [browser_editor_markers.js]
 [browser_editor_movelines.js]
 [browser_editor_prefs.js]
 [browser_editor_script_injection.js]
 [browser_editor_addons.js]
 [browser_codemirror.js]
 [browser_css_autocompletion.js]
+uses-unsafe-cpows = true
 [browser_css_getInfo.js]
+uses-unsafe-cpows = true
 [browser_css_statemachine.js]
+uses-unsafe-cpows = true
 [browser_detectindent.js]
 [browser_vimemacs.js]
 skip-if = os == 'linux'&&debug # bug 981707
 
--- a/devtools/client/themes/boxmodel.css
+++ b/devtools/client/themes/boxmodel.css
@@ -2,16 +2,22 @@
  * 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/ */
 
 /**
  * This is the stylesheet of the Box Model view implemented in the layout panel.
  */
 
 .boxmodel-container {
+  --marginbox-color: #fdffdf;
+  --borderbox-color: var(--grey-50);
+  --paddingbox-color: #e3dcff;
+  --contentbox-color: #cff0fb;
+  --marginbox-border-color: #d8e60a;
+  --contentbox-border-color: #54A9FF;
   overflow: auto;
   padding-bottom: 4px;
   max-width: 600px;
   margin: 0 auto;
 }
 
 /* Header */
 
@@ -36,67 +42,72 @@
   width: calc(100% - 2 * 14px);
   min-width: 240px;
   /* The view will grow bigger as the window gets resized, until 400px */
   max-width: 400px;
 }
 
 .boxmodel-box {
   margin: 25px;
-  /* The regions are semi-transparent, so the white background is partly
-     visible */
-  background-color: white;
 }
 
+.boxmodel-size {
+  color: var(--grey-90);
+}
+
+.boxmodel-position,
 .boxmodel-margin,
-.boxmodel-size {
-  color: var(--theme-highlight-blue);
+.boxmodel-padding {
+  color: var(--grey-50);
 }
 
 .theme-dark .boxmodel-margin,
 .theme-dark .boxmodel-size {
   color: var(--grey-60);
 }
 
 /* Regions are 3 nested elements with wide borders and outlines */
 
 .boxmodel-contents {
   height: 18px;
-}
-
-.boxmodel-margins,
-.boxmodel-borders,
-.boxmodel-paddings {
-  border-color: hsla(210,100%,85%,0.2);
-  border-width: 18px;
-  border-style: solid;
-  outline: dotted 1px hsl(210,100%,85%);
+  outline: dashed 1px var(--contentbox-border-color);
 }
 
 .boxmodel-margins {
-  /* This opacity applies to all of the regions, since they are nested */
-  opacity: .8;
+  border-width: 22px;
+  border-style: solid;
+  outline: dashed 1px var(--marginbox-border-color);
+}
+
+.boxmodel-borders {
+  border-width: 5px;
+  border-style: solid;
+}
+
+.boxmodel-paddings {
+  border-width: 27px;
+  border-style: solid;
 }
 
 /* Regions colors */
 
 .boxmodel-margins {
-  border-color: #edff64;
+  border-color: var(--marginbox-color);
 }
 
 .boxmodel-borders {
-  border-color: #444444;
+  border-color: var(--borderbox-color);
 }
 
 .boxmodel-paddings {
-  border-color: #6a5acd;
+  border-color: var(--paddingbox-color);
 }
 
 .boxmodel-contents {
-  background-color: #87ceeb;
+  background-color: var(--contentbox-color);
 }
 
 .theme-firebug .boxmodel-main,
 .theme-firebug .boxmodel-header {
   font-family: var(--proportional-font-family);
 }
 
 .theme-firebug .boxmodel-main {
@@ -130,37 +141,37 @@
 
 .boxmodel-top,
 .boxmodel-bottom {
   width: calc(100% - 2px);
   text-align: center;
 }
 
 .boxmodel-padding.boxmodel-top {
-  top: 37px;
+  top: 34px;
 }
 
 .boxmodel-padding.boxmodel-bottom {
-  bottom: 38px;
+  bottom: 35px;
 }
 
 .boxmodel-border.boxmodel-top {
-  top: 19px;
+  top: 17px;
 }
 
 .boxmodel-border.boxmodel-bottom {
-  bottom: 20px;
+  bottom: 17px;
 }
 
 .boxmodel-margin.boxmodel-top {
-  top: 1px;
+  top: 0px;
 }
 
 .boxmodel-margin.boxmodel-bottom {
-  bottom: 2px;
+  bottom: 1px;
 }
 
 .boxmodel-size,
 .boxmodel-position.boxmodel-left,
 .boxmodel-position.boxmodel-right,
 .boxmodel-margin.boxmodel-left,
 .boxmodel-margin.boxmodel-right,
 .boxmodel-border.boxmodel-left,
@@ -184,37 +195,37 @@
 .boxmodel-border.boxmodel-right,
 .boxmodel-border.boxmodel-left,
 .boxmodel-padding.boxmodel-right,
 .boxmodel-padding.boxmodel-left {
   width: 21px;
 }
 
 .boxmodel-padding.boxmodel-left {
-  left: 60px;
+  left: 56px;
 }
 
 .boxmodel-padding.boxmodel-right {
-  right: 60px;
+  right: 56px;
 }
 
 .boxmodel-border.boxmodel-left {
-  left: 41px;
+  left: 39px;
 }
 
 .boxmodel-border.boxmodel-right {
-  right: 42px;
+  right: 39px;
 }
 
 .boxmodel-margin.boxmodel-right {
-  right: 25px;
+  right: 24px;
 }
 
 .boxmodel-margin.boxmodel-left {
-  left: 25px;
+  left: 24px;
 }
 
 .boxmodel-rotate.boxmodel-left:not(.boxmodel-editing) {
   transform: rotate(-90deg);
 }
 
 .boxmodel-rotate.boxmodel-right:not(.boxmodel-editing) {
   transform: rotate(90deg);
@@ -237,30 +248,26 @@
   border-top: none;
   border-left: 1px solid var(--theme-highlight-purple);
   width: auto;
   height: 30px;
 }
 
 /* Box Model Positioning: contains top, right, bottom, left */
 
-.boxmodel-position {
-  color: var(--theme-highlight-purple);
-}
-
 .boxmodel-position.boxmodel-top,
 .boxmodel-position.boxmodel-bottom {
-  border-left: 1px solid var(--theme-highlight-purple);
+  border-left: 1px solid var(--grey-50);
   left: calc(50% - 2px);
   padding-left: 1px;
 }
 
 .boxmodel-position.boxmodel-right,
 .boxmodel-position.boxmodel-left {
-  border-top: 1px solid var(--theme-highlight-purple);
+  border-top: 1px solid var(--grey-50);
   line-height: 15px;
   top: calc(50% - 1px);
   width: 30px;
 }
 
 .boxmodel-position.boxmodel-top {
   top: -18px;
 }
@@ -276,41 +283,61 @@
 .boxmodel-position.boxmodel-left {
   left: -9px;
 }
 
 /* Legend: displayed inside regions */
 
 .boxmodel-legend {
   position: absolute;
-  margin: 2px 6px;
   z-index: 1;
 }
 
 .boxmodel-legend[data-box="margin"] {
-  color: var(--theme-highlight-blue);
-}
-
-.theme-dark .boxmodel-legend[data-box="margin"] {
-  color: var(--grey-60);
+  margin-left: 9px;
+  margin-top: 4px;
+  color: var(--grey-90);
 }
 
 .boxmodel-legend[data-box="position"] {
-  color: var(--theme-highlight-purple);
-  margin: -18px -9px;
+  color: var(--grey-90);
+  margin: -18px 13px;
+}
+
+.boxmodel-legend[data-box="padding"] {
+  margin-top: 12px;
+  margin-left: 12px;
+  color: var(--grey-90);
+}
+
+.boxmodel-legend[data-box="border"] {
+  background-color: var(--borderbox-color);
+  height: 15px;
+  padding-top: 1px;
+  padding-left: 4px;
+  padding-right: 4px;
+  border-radius: 3px;
+  margin: 0px 0px;
 }
 
 /* Editable fields */
 
 .boxmodel-editable {
+  position: relative;
   border: 1px dashed transparent;
   -moz-user-select: none;
   white-space: nowrap;
 }
 
+.boxmodel-editable[data-box="border"] {
+  background-color: var(--borderbox-color);
+  border-radius: 3px;
+  padding: 0 2px;
+}
+
 .boxmodel-editable:hover {
   border-bottom-color: hsl(0, 0%, 50%);
 }
 
 .boxmodel-size > span {
   cursor: default;
 }
 
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -258,16 +258,17 @@ subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_context_menu_copy_link_location.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_context_menu_copy_object.js]
 subsuite = clipboard
 [browser_webconsole_context_menu_object_in_sidebar.js]
 [browser_webconsole_context_menu_open_url.js]
+uses-unsafe-cpows = true
 [browser_webconsole_context_menu_store_as_global.js]
 [browser_webconsole_csp_ignore_reflected_xss_message.js]
 skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
 [browser_webconsole_csp_violation.js]
 [browser_webconsole_cspro.js]
 [browser_webconsole_document_focus.js]
 [browser_webconsole_duplicate_errors.js]
 [browser_webconsole_errors_after_page_reload.js]
@@ -302,16 +303,17 @@ skip-if = true #	Bug 1405343
 [browser_webconsole_loglimit.js]
 [browser_webconsole_logWarningInPage.js]
 [browser_webconsole_longstring_expand.js]
 skip-if = true #	Bug 1403448
 [browser_webconsole_longstring_hang.js]
 skip-if = true #	Bug 1403448
 [browser_webconsole_message_categories.js]
 [browser_webconsole_multiple_windows_and_tabs.js]
+uses-unsafe-cpows = true
 [browser_webconsole_network_attach.js]
 [browser_webconsole_network_exceptions.js]
 [browser_webconsole_network_messages_expand.js]
 skip-if = (os == 'linux') || (os == 'win' && os_version == '10.0' && debug && bits == 64)  # Bug 1429361, disabled on Linux/Win for frequent failures
 [browser_webconsole_network_messages_openinnet.js]
 [browser_webconsole_network_messages_status_code.js]
 [browser_webconsole_network_requests_from_chrome.js]
 [browser_webconsole_network_reset_filter.js]
--- a/devtools/client/webconsole/test/browser.ini
+++ b/devtools/client/webconsole/test/browser.ini
@@ -145,32 +145,34 @@ support-files =
   !/devtools/client/netmonitor/test/sjs_cors-test-server.sjs
   !/devtools/client/shared/test/shared-head.js
   !/image/test/mochitest/blue.png
 
 [browser_bug1045902_console_csp_ignore_reflected_xss_message.js]
 skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
 [browser_bug664688_sandbox_update_after_navigation.js]
 [browser_bug_638949_copy_link_location.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_bug_862916_console_dir_and_filter_off.js]
 skip-if = (e10s && (os == 'win' || os == 'mac')) # Bug 1243976
 [browser_bug_865288_repeat_different_objects.js]
 [browser_bug_865871_variables_view_close_on_esc_key.js]
 [browser_bug_869003_inspect_cross_domain_object.js]
 [browser_bug_871156_ctrlw_close_tab.js]
 [browser_cached_messages.js]
 [browser_console.js]
 [browser_console_certificate_imminent_distrust.js]
 [browser_console_clear_method.js]
 [browser_console_clear_on_reload.js]
 [browser_console_click_focus.js]
 [browser_console_consolejsm_output.js]
 [browser_console_copy_command.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_console_dead_objects.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_console_copy_entire_message_context_menu.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_console_devtools_loader_exception.js]
@@ -184,44 +186,47 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_console_netlogging.js]
 [browser_console_nsiconsolemessage.js]
 [browser_console_optimized_out_vars.js]
 [browser_console_private_browsing.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests
 [browser_console_restore.js]
 [browser_console_server_logging.js]
 [browser_console_variables_view.js]
+uses-unsafe-cpows = true
 [browser_console_variables_view_filter.js]
 [browser_console_variables_view_dom_nodes.js]
 [browser_console_variables_view_dont_sort_non_sortable_classes_properties.js]
 [browser_console_variables_view_special_names.js]
 [browser_console_variables_view_while_debugging.js]
 [browser_console_variables_view_while_debugging_and_inspecting.js]
 [browser_eval_in_debugger_stackframe.js]
 [browser_eval_in_debugger_stackframe2.js]
 [browser_jsterm_inspect.js]
 skip-if = e10s && debug && (os == 'win' || os == 'mac') # Bug 1243966
 [browser_longstring_hang.js]
 [browser_output_breaks_after_console_dir_uninspectable.js]
+uses-unsafe-cpows = true
 [browser_output_longstring_expand.js]
 [browser_repeated_messages_accuracy.js]
 [browser_result_format_as_string.js]
 [browser_warn_user_about_replaced_api.js]
 [browser_webconsole_allow_mixedcontent_securityerrors.js]
 tags = mcb
 skip-if = (os == 'win' && bits == 64) # Bug 1390001
 [browser_webconsole_script_errordoc_urls.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_assert.js]
 [browser_webconsole_block_mixedcontent_securityerrors.js]
 tags = mcb
 skip-if = (os == 'win' && bits == 64) # Bug 1390001
 [browser_webconsole_bug_579412_input_focus.js]
 [browser_webconsole_bug_580001_closing_after_completion.js]
 [browser_webconsole_bug_580030_errors_after_page_reload.js]
+uses-unsafe-cpows = true
 [browser_webconsole_bug_582201_duplicate_errors.js]
 [browser_webconsole_bug_583816_No_input_and_Tab_key_pressed.js]
 [browser_webconsole_bug_585237_line_limit.js]
 [browser_webconsole_bug_585956_console_trace.js]
 [browser_webconsole_bug_585991_autocomplete_keys.js]
 [browser_webconsole_bug_585991_autocomplete_popup.js]
 [browser_webconsole_bug_586388_select_all.js]
 [browser_webconsole_bug_587617_output_copy.js]
@@ -238,16 +243,17 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_webconsole_bug_595350_multiple_windows_and_tabs.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_595934_message_categories.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_597103_deactivateHUDForContext_unfocused_window.js]
 [browser_webconsole_bug_597136_external_script_errors.js]
 [browser_webconsole_bug_597136_network_requests_from_chrome.js]
 [browser_webconsole_bug_597460_filter_scroll.js]
+uses-unsafe-cpows = true
 [browser_webconsole_bug_597756_reopen_closed_tab.js]
 [browser_webconsole_bug_599725_response_headers.js]
 [browser_webconsole_bug_600183_charset.js]
 [browser_webconsole_bug_601177_log_levels.js]
 [browser_webconsole_bug_601352_scroll.js]
 [browser_webconsole_bug_601667_filter_buttons.js]
 [browser_webconsole_bug_603750_websocket.js]
 [browser_webconsole_bug_611795.js]
@@ -260,25 +266,27 @@ skip-if = (os == 'linux' && bits == 32 &
 [browser_webconsole_bug_614793_jsterm_scroll.js]
 [browser_webconsole_bug_618078_network_exceptions.js]
 [browser_webconsole_bug_621644_jsterm_dollar.js]
 [browser_webconsole_bug_622303_persistent_filters.js]
 [browser_webconsole_bug_623749_ctrl_a_select_all_winnt.js]
 skip-if = os != "win"
 [browser_webconsole_bug_630733_response_redirect_headers.js]
 [browser_webconsole_bug_632275_getters_document_width.js]
+uses-unsafe-cpows = true
 [browser_webconsole_bug_632347_iterators_generators.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s
 [browser_webconsole_bug_632817.js]
 skip-if = true # Bug 1244707
 [browser_webconsole_bug_642108_pruneTest.js]
 [browser_webconsole_autocomplete_and_selfxss.js]
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_bug_644419_log_limits.js]
+uses-unsafe-cpows = true
 [browser_webconsole_bug_646025_console_file_location.js]
 [browser_webconsole_bug_651501_document_body_autocomplete.js]
 [browser_webconsole_bug_653531_highlighter_console_helper.js]
 skip-if = true # Requires direct access to content nodes
 [browser_webconsole_bug_658368_time_methods.js]
 [browser_webconsole_bug_659907_console_dir.js]
 [browser_webconsole_bug_660806_history_nav.js]
 [browser_webconsole_bug_664131_console_group.js]
@@ -316,17 +324,19 @@ skip-if = e10s # Bug 1042253 - webconsol
 skip-if = e10s && (os == 'win' || os == 'mac') # Bug 1243987
 [browser_webconsole_cached_autocomplete.js]
 [browser_webconsole_chrome.js]
 [browser_webconsole_clear_method.js]
 [browser_webconsole_clickable_urls.js]
 [browser_webconsole_closure_inspection.js]
 [browser_webconsole_completion.js]
 [browser_webconsole_console_extras.js]
+uses-unsafe-cpows = true
 [browser_webconsole_console_logging_api.js]
+uses-unsafe-cpows = true
 [browser_webconsole_console_logging_workers_api.js]
 [browser_webconsole_console_trace_async.js]
 [browser_webconsole_count.js]
 [browser_webconsole_dont_navigate_on_doubleclick.js]
 [browser_webconsole_execution_scope.js]
 [browser_webconsole_for_of.js]
 [browser_webconsole_history.js]
 [browser_webconsole_hpkp_invalid-headers.js]
@@ -334,43 +344,50 @@ skip-if = (os == 'win' && bits == 64) # 
 [browser_webconsole_hsts_invalid-headers.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests
 [browser_webconsole_input_field_focus_on_panel_select.js]
 [browser_webconsole_inspect-parsed-documents.js]
 [browser_webconsole_js_input_expansion.js]
 [browser_webconsole_jsterm.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
 [browser_webconsole_live_filtering_of_message_types.js]
+uses-unsafe-cpows = true
 [browser_webconsole_live_filtering_on_search_strings.js]
+uses-unsafe-cpows = true
 [browser_webconsole_message_node_id.js]
 [browser_webconsole_multiline_input.js]
 [browser_webconsole_netlogging.js]
 skip-if = true # Bug 1298364
 [browser_webconsole_netlogging_basic.js]
 [browser_webconsole_netlogging_panel.js]
 [browser_webconsole_netlogging_reset_filter.js]
 [browser_webconsole_notifications.js]
+uses-unsafe-cpows = true
 [browser_webconsole_open-links-without-callback.js]
+uses-unsafe-cpows = true
 [browser_webconsole_promise.js]
 [browser_webconsole_output_copy_newlines.js]
+uses-unsafe-cpows = true
 subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_output_order.js]
 [browser_webconsole_scratchpad_panel_link.js]
 [browser_webconsole_split.js]
 [browser_webconsole_split_escape_key.js]
 [browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
 [browser_webconsole_trackingprotection_errors.js]
 tags = trackingprotection
 skip-if = (os == 'win' && bits == 64) # Bug 1390001
 [browser_webconsole_view_source.js]
 skip-if = (os == 'win' && bits == 64) # Bug 1390001
 [browser_webconsole_reflow.js]
+uses-unsafe-cpows = true
 [browser_webconsole_log_file_filter.js]
+uses-unsafe-cpows = true
 [browser_webconsole_expandable_timestamps.js]
 [browser_webconsole_autocomplete_accessibility.js]
 [browser_webconsole_autocomplete_in_debugger_stackframe.js]
 [browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
 [browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js]
 [browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js]
 [browser_console_history_persist.js]
 [browser_webconsole_output_01.js]
--- a/devtools/server/actors/addon.js
+++ b/devtools/server/actors/addon.js
@@ -10,17 +10,16 @@ var { ActorPool } = require("devtools/se
 var { TabSources } = require("./utils/TabSources");
 var makeDebugger = require("./utils/make-debugger");
 var { ConsoleAPIListener } = require("devtools/server/actors/webconsole/listeners");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var { assert, update } = DevToolsUtils;
 
 loader.lazyRequireGetter(this, "AddonThreadActor", "devtools/server/actors/thread", true);
 loader.lazyRequireGetter(this, "unwrapDebuggerObjectGlobal", "devtools/server/actors/thread", true);
-loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
 loader.lazyRequireGetter(this, "WebConsoleActor", "devtools/server/actors/webconsole", true);
 
 loader.lazyImporter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
 
 function BrowserAddonActor(connection, addon) {
   this.conn = connection;
   this._addon = addon;
   this._contextPool = new ActorPool(this.conn);
@@ -213,37 +212,17 @@ BrowserAddonActor.prototype = {
       if (metadata) {
         return metadata.addonID === this.id;
       }
     } catch (e) {
       // ignore
     }
 
     if (global instanceof Ci.nsIDOMWindow) {
-      return mapURIToAddonID(global.document.documentURIObject) == this.id;
-    }
-
-    // Check the global for a __URI__ property and then try to map that to an
-    // add-on
-    let uridescriptor = givenGlobal.getOwnPropertyDescriptor("__URI__");
-    if (uridescriptor && "value" in uridescriptor && uridescriptor.value) {
-      let uri;
-      try {
-        uri = Services.io.newURI(uridescriptor.value);
-      } catch (e) {
-        DevToolsUtils.reportException(
-          "BrowserAddonActor.prototype._shouldAddNewGlobalAsDebuggee",
-          new Error("Invalid URI: " + uridescriptor.value)
-        );
-        return false;
-      }
-
-      if (mapURIToAddonID(uri) == this.id) {
-        return true;
-      }
+      return global.document.nodePrincipal.addonId;
     }
 
     return false;
   },
 
   /**
    * Override the eligibility check for scripts and sources to make
    * sure every script and source with a URL is stored when debugging
--- a/devtools/server/actors/utils/map-uri-to-addon-id.js
+++ b/devtools/server/actors/utils/map-uri-to-addon-id.js
@@ -1,43 +1,43 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
+const {Cu} = require("chrome");
+
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const Services = require("Services");
-
-loader.lazyServiceGetter(this, "AddonPathService",
-                         "@mozilla.org/addon-path-service;1",
-                         "amIAddonPathService");
+const {WebExtensionPolicy} = Cu.getGlobalForObject(Services);
 
 const B2G_ID = "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}";
 const GRAPHENE_ID = "{d1bfe7d9-c01e-4237-998b-7b5f960a4314}";
 
 /**
  * This is a wrapper around amIAddonPathService.mapURIToAddonID which always returns
  * false on B2G and graphene to avoid loading the add-on manager there and
  * reports any exceptions rather than throwing so that the caller doesn't have
  * to worry about them.
  */
 if (!Services.appinfo
     || Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
     || Services.appinfo.ID === undefined /* XPCShell */
     || Services.appinfo.ID == B2G_ID
     || Services.appinfo.ID == GRAPHENE_ID
-    || !AddonPathService) {
+    || !WebExtensionPolicy) {
   module.exports = function mapURIToAddonId(uri) {
     return false;
   };
 } else {
   module.exports = function mapURIToAddonId(uri) {
     try {
-      return AddonPathService.mapURIToAddonId(uri);
+      let policy = WebExtensionPolicy.getByURI(uri);
+      return policy && policy.id;
     } catch (e) {
       DevToolsUtils.reportException("mapURIToAddonId", e);
       return false;
     }
   };
 }
--- a/devtools/server/tests/browser/browser.ini
+++ b/devtools/server/tests/browser/browser.ini
@@ -59,18 +59,21 @@ skip-if = e10s # Bug 1183605 - devtools/
 [browser_canvasframe_helper_05.js]
 skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
 [browser_canvasframe_helper_06.js]
 skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
 [browser_layout_getGrids.js]
 [browser_layout_simple.js]
 [browser_markers-cycle-collection.js]
 [browser_markers-docloading-01.js]
+uses-unsafe-cpows = true
 [browser_markers-docloading-02.js]
+uses-unsafe-cpows = true
 [browser_markers-docloading-03.js]
+uses-unsafe-cpows = true
 [browser_markers-gc.js]
 [browser_markers-minor-gc.js]
 [browser_markers-parse-html.js]
 [browser_markers-styles.js]
 [browser_markers-timestamp.js]
 [browser_navigateEvents.js]
 skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
 [browser_perf-01.js]
@@ -87,17 +90,20 @@ skip-if = true # Needs to be updated for
 [browser_perf-recording-actor-01.js]
 skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
 [browser_perf-recording-actor-02.js]
 skip-if = e10s # Bug 1183605 - devtools/server/tests/browser/ tests are still disabled in E10S
 [browser_perf-samples-01.js]
 [browser_perf-samples-02.js]
 [browser_storage_cookies-duplicate-names.js]
 [browser_storage_dynamic_windows.js]
+uses-unsafe-cpows = true
 [browser_storage_listings.js]
+uses-unsafe-cpows = true
 [browser_storage_updates.js]
+uses-unsafe-cpows = true
 [browser_stylesheets_getTextEmpty.js]
 [browser_stylesheets_nested-iframes.js]
 [browser_timeline.js]
 [browser_timeline_actors.js]
 [browser_timeline_iframes.js]
 [browser_register_actor.js]
 [browser_webextension_inspected_window.js]
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -69,18 +69,16 @@ EXPORTS += [
     'nsDOMClassInfoID.h',
     'nsDOMJSUtils.h',
     'nsDOMNavigationTiming.h',
     'nsDOMString.h',
     'nsDOMTokenList.h',
     'nsFocusManager.h',
     'nsFrameMessageManager.h',
     'nsGenericDOMDataNode.h',
-    'nsGkAtomList.h',
-    'nsGkAtoms.h',
     'nsGlobalWindow.h',  # Because binding headers include it.
     'nsGlobalWindowInner.h',  # Because binding headers include it.
     'nsGlobalWindowOuter.h',  # Because binding headers include it.
     'nsIAnimationObserver.h',
     'nsIAttribute.h',
     'nsIContent.h',
     'nsIContentInlines.h',
     'nsIContentIterator.h',
@@ -294,17 +292,16 @@ UNIFIED_SOURCES += [
     'nsDOMNavigationTiming.cpp',
     'nsDOMSerializer.cpp',
     'nsDOMTokenList.cpp',
     'nsDOMWindowList.cpp',
     'nsFocusManager.cpp',
     'nsFrameLoader.cpp',
     'nsGenConImageContent.cpp',
     'nsGenericDOMDataNode.cpp',
-    'nsGkAtoms.cpp',
     'nsGlobalWindowCommands.cpp',
     'nsHistory.cpp',
     'nsHTMLContentSerializer.cpp',
     'nsIGlobalObject.cpp',
     'nsINode.cpp',
     'nsInProcessTabChildGlobal.cpp',
     'nsJSEnvironment.cpp',
     'nsJSTimeoutHandler.cpp',
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2881,16 +2881,17 @@ public:
                                                      nsPresContext* aPresContext);
   static nsView* GetViewToDispatchEvent(nsPresContext* aPresContext,
                                         nsIPresShell** aPresShell);
 
   /**
    * Synthesize a mouse event to the given widget
    * (see nsIDOMWindowUtils.sendMouseEvent).
    */
+  MOZ_CAN_RUN_SCRIPT
   static nsresult SendMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell,
                                  const nsAString& aType,
                                  float aX,
                                  float aY,
                                  int32_t aButton,
                                  int32_t aButtons,
                                  int32_t aClickCount,
                                  int32_t aModifiers,
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -309,54 +309,68 @@ nsDOMTokenList::Toggle(const nsAString& 
       AddInternal(attr, tokens);
       isPresent = true;
     }
   }
 
   return isPresent;
 }
 
-void
+bool
 nsDOMTokenList::Replace(const nsAString& aToken,
                         const nsAString& aNewToken,
                         ErrorResult& aError)
 {
   // Doing this here instead of using `CheckToken` because if aToken had invalid
   // characters, and aNewToken is empty, the returned error should be a
   // SyntaxError, not an InvalidCharacterError.
   if (aNewToken.IsEmpty()) {
     aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
-    return;
+    return false;
   }
 
   aError = CheckToken(aToken);
   if (aError.Failed()) {
-    return;
+    return false;
   }
 
   aError = CheckToken(aNewToken);
   if (aError.Failed()) {
-    return;
+    return false;
   }
 
   const nsAttrValue* attr = GetParsedAttr();
   if (!attr) {
-    return;
+    return false;
   }
 
-  ReplaceInternal(attr, aToken, aNewToken);
+  return ReplaceInternal(attr, aToken, aNewToken);
 }
 
-void
+bool
 nsDOMTokenList::ReplaceInternal(const nsAttrValue* aAttr,
                                 const nsAString& aToken,
                                 const nsAString& aNewToken)
 {
   RemoveDuplicates(aAttr);
 
+  // Trying to do a single pass here leads to really complicated code.  Just do
+  // the simple thing.
+  bool haveOld = false;
+  for (uint32_t i = 0; i < aAttr->GetAtomCount(); ++i) {
+    if (aAttr->AtomAt(i)->Equals(aToken)) {
+      haveOld = true;
+      break;
+    }
+  }
+  if (!haveOld) {
+    // Make sure to not touch the attribute value in this case.
+    return false;
+  }
+
   bool sawIt = false;
   nsAutoString resultStr;
   for (uint32_t i = 0; i < aAttr->GetAtomCount(); i++) {
     if (aAttr->AtomAt(i)->Equals(aToken) ||
         aAttr->AtomAt(i)->Equals(aNewToken)) {
       if (sawIt) {
         // We keep only the first
         continue;
@@ -369,19 +383,19 @@ nsDOMTokenList::ReplaceInternal(const ns
       continue;
     }
     if (!resultStr.IsEmpty()) {
       resultStr.AppendLiteral(" ");
     }
     resultStr.Append(nsDependentAtomString(aAttr->AtomAt(i)));
   }
 
-  if (sawIt) {
-    mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
-  }
+  MOZ_ASSERT(sawIt, "How could we not have found our token this time?");
+  mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
+  return true;
 }
 
 bool
 nsDOMTokenList::Supports(const nsAString& aToken,
                          ErrorResult& aError)
 {
   if (!mSupportedTokens) {
     aError.ThrowTypeError<MSG_TOKENLIST_NO_SUPPORTED_TOKENS>(
--- a/dom/base/nsDOMTokenList.h
+++ b/dom/base/nsDOMTokenList.h
@@ -70,17 +70,17 @@ public:
   void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aResult);
   bool Contains(const nsAString& aToken);
   void Add(const nsAString& aToken, mozilla::ErrorResult& aError);
   void Add(const nsTArray<nsString>& aTokens,
            mozilla::ErrorResult& aError);
   void Remove(const nsAString& aToken, mozilla::ErrorResult& aError);
   void Remove(const nsTArray<nsString>& aTokens,
               mozilla::ErrorResult& aError);
-  void Replace(const nsAString& aToken,
+  bool Replace(const nsAString& aToken,
                const nsAString& aNewToken,
                mozilla::ErrorResult& aError);
   bool Toggle(const nsAString& aToken,
               const mozilla::dom::Optional<bool>& force,
               mozilla::ErrorResult& aError);
   bool Supports(const nsAString& aToken,
                 mozilla::ErrorResult& aError);
 
@@ -94,17 +94,17 @@ protected:
   nsresult CheckToken(const nsAString& aStr);
   nsresult CheckTokens(const nsTArray<nsString>& aStr);
   void RemoveDuplicatesInternal(nsTArray<RefPtr<nsAtom>>* aArray,
                                 uint32_t aStart);
   void AddInternal(const nsAttrValue* aAttr,
                    const nsTArray<nsString>& aTokens);
   void RemoveInternal(const nsAttrValue* aAttr,
                       const nsTArray<nsString>& aTokens);
-  void ReplaceInternal(const nsAttrValue* aAttr,
+  bool ReplaceInternal(const nsAttrValue* aAttr,
                        const nsAString& aToken,
                        const nsAString& aNewToken);
   inline const nsAttrValue* GetParsedAttr();
 
   nsCOMPtr<Element> mElement;
   RefPtr<nsAtom> mAttrAtom;
   const mozilla::dom::DOMTokenListSupportedTokenArray mSupportedTokens;
 };
--- a/dom/base/nsDOMWindowUtils.h
+++ b/dom/base/nsDOMWindowUtils.h
@@ -79,16 +79,18 @@ protected:
   nsIWidget* GetWidgetForElement(nsIDOMElement* aElement);
 
   nsIPresShell* GetPresShell();
   nsPresContext* GetPresContext();
   nsIDocument* GetDocument();
   mozilla::layers::LayerTransactionChild* GetLayerTransaction();
   mozilla::layers::WebRenderBridgeChild* GetWebRenderBridge();
 
+  // Until callers are annotated.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   NS_IMETHOD SendMouseEventCommon(const nsAString& aType,
                                   float aX,
                                   float aY,
                                   int32_t aButton,
                                   int32_t aClickCount,
                                   int32_t aModifiers,
                                   bool aIgnoreRootScrollFrame,
                                   float aPressure,
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -269,16 +269,18 @@ protected:
    * switching focus to a sibling window.
    *
    * aIsLeavingDocument should be set to true if the document/window is being
    * blurred as well. Document/window blur events will be fired. It should be
    * false if an element is the same document is about to be focused.
    *
    * If aAdjustWidget is false, don't change the widget focus state.
    */
+  // MOZ_CAN_RUN_SCRIPT_BOUNDARY for now, until we annotate callers.
+  MOZ_CAN_RUN_SCRIPT_BOUNDARY
   bool Blur(nsPIDOMWindowOuter* aWindowToClear,
             nsPIDOMWindowOuter* aAncestorWindowToFocus,
             bool aIsLeavingDocument,
             bool aAdjustWidget,
             nsIContent* aContentToFocus = nullptr);
 
   /**
    * Focus an element in the active window and child frame.
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -208,17 +208,16 @@
 #include "mozilla/dom/VRDisplay.h"
 #include "mozilla/dom/VRDisplayEvent.h"
 #include "mozilla/dom/VRDisplayEventBinding.h"
 #include "mozilla/dom/VREventObserver.h"
 
 #include "nsRefreshDriver.h"
 #include "Layers.h"
 
-#include "mozilla/AddonPathService.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/Location.h"
 #include "nsHTMLDocument.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "prrng.h"
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -210,17 +210,16 @@
 #include "mozilla/dom/VRDisplay.h"
 #include "mozilla/dom/VRDisplayEvent.h"
 #include "mozilla/dom/VRDisplayEventBinding.h"
 #include "mozilla/dom/VREventObserver.h"
 
 #include "nsRefreshDriver.h"
 #include "Layers.h"
 
-#include "mozilla/AddonPathService.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/Location.h"
 #include "nsHTMLDocument.h"
 #include "nsWrapperCacheInlines.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "prrng.h"
@@ -1634,24 +1633,16 @@ CreateNativeGlobalForInner(JSContext* aC
   // no one creates one accidentally.
   nsCOMPtr<nsIExpandedPrincipal> nsEP = do_QueryInterface(aPrincipal);
   MOZ_RELEASE_ASSERT(!nsEP, "DOMWindow with nsEP is not supported");
 
   JS::CompartmentOptions options;
 
   SelectZoneGroup(aNewInner, options.creationOptions());
 
-  // Sometimes add-ons load their own XUL windows, either as separate top-level
-  // windows or inside a browser element. In such cases we want to tag the
-  // window's compartment with the add-on ID. See bug 1092156.
-  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
-    options.creationOptions().setAddonId(MapURIToAddonID(aURI));
-    options.creationOptions().setClampAndJitterTime(false);
-  }
-
   options.creationOptions().setSecureContext(aIsSecureContext);
 
   xpc::InitGlobalObjectOptions(options, aPrincipal);
 
   // Determine if we need the Components object.
   bool needComponents = nsContentUtils::IsSystemPrincipal(aPrincipal) ||
                         TreatAsRemoteXUL(aPrincipal);
   uint32_t flags = needComponents ? 0 : xpc::OMIT_COMPONENTS_OBJECT;
@@ -7877,8 +7868,9 @@ nsAutoPopupStatePusherInternal::nsAutoPo
   : mOldState(nsContentUtils::PushPopupControlState(aState, aForce))
 {
 }
 
 nsAutoPopupStatePusherInternal::~nsAutoPopupStatePusherInternal()
 {
   nsContentUtils::PopPopupControlState(mOldState);
 }
+
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -1,15 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "amIAddonManager.h"
 #include "nsWindowMemoryReporter.h"
 #include "nsWindowSizes.h"
 #include "nsGlobalWindow.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindowCollection.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
@@ -238,17 +237,16 @@ ReportCount(const nsCString& aBasePath, 
 {
   ReportAmount(aBasePath, aPathTail, aAmount, aDescription,
                nsIMemoryReporter::KIND_OTHER, nsIMemoryReporter::UNITS_COUNT,
                aHandleReport, aData);
 }
 
 static void
 CollectWindowReports(nsGlobalWindowInner *aWindow,
-                     amIAddonManager *addonManager,
                      nsWindowSizes *aWindowTotalSizes,
                      nsTHashtable<nsUint64HashKey> *aGhostWindowIDs,
                      WindowPaths *aWindowPaths,
                      WindowPaths *aTopWindowPaths,
                      nsIHandleReportCallback *aHandleReport,
                      nsISupports *aData,
                      bool aAnonymize)
 {
@@ -265,27 +263,16 @@ CollectWindowReports(nsGlobalWindowInner
     if (top) {
       location = GetWindowURI(top);
     }
   }
   if (!location) {
     location = GetWindowURI(aWindow);
   }
 
-  if (addonManager && location) {
-    bool ok;
-    nsAutoCString id;
-    if (NS_SUCCEEDED(addonManager->MapURIToAddonID(location, id, &ok)) && ok) {
-      // Add-on names are not privacy-sensitive, so we can use them with
-      // impunity.
-      windowPath += NS_LITERAL_CSTRING("add-ons/") + id +
-                    NS_LITERAL_CSTRING("/");
-    }
-  }
-
   windowPath += NS_LITERAL_CSTRING("window-objects/");
 
   if (top) {
     windowPath += NS_LITERAL_CSTRING("top(");
     AppendWindowURI(top->GetCurrentInnerWindowInternal(), windowPath, aAnonymize);
     windowPath.AppendPrintf(", id=%" PRIu64 ")", top->WindowID());
 
     aTopWindowPaths->Put(aWindow->WindowID(), windowPath);
@@ -615,23 +602,18 @@ nsWindowMemoryReporter::CollectReports(n
 "leaks in the browser or add-ons.");
 
   WindowPaths windowPaths;
   WindowPaths topWindowPaths;
 
   // Collect window memory usage.
   SizeOfState fakeState(nullptr);   // this won't be used
   nsWindowSizes windowTotalSizes(fakeState);
-  nsCOMPtr<amIAddonManager> addonManager;
-  if (XRE_IsParentProcess()) {
-    // Only try to access the service from the main process.
-    addonManager = do_GetService("@mozilla.org/addons/integration;1");
-  }
   for (uint32_t i = 0; i < windows.Length(); i++) {
-    CollectWindowReports(windows[i], addonManager,
+    CollectWindowReports(windows[i],
                          &windowTotalSizes, &ghostWindows,
                          &windowPaths, &topWindowPaths, aHandleReport,
                          aData, aAnonymize);
   }
 
   // Report JS memory usage.  We do this from here because the JS memory
   // reporter needs to be passed |windowPaths|.
   xpc::JSReporter::CollectReports(&windowPaths, &topWindowPaths,
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -39,16 +39,17 @@ support-files =
 tags = mcb
 [browser_bug1011748.js]
 [browser_bug1058164.js]
 [browser_force_process_selector.js]
 skip-if = !e10s # this only makes sense with e10s-multi
 [browser_messagemanager_loadprocessscript.js]
 [browser_aboutnewtab_process_selection.js]
 skip-if = !e10s # this only makes sense with e10s-multi
+uses-unsafe-cpows = true
 [browser_messagemanager_targetframeloader.js]
 [browser_messagemanager_unload.js]
 [browser_pagehide_on_tab_close.js]
 skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
 [browser_promiseDocumentFlushed.js]
 [browser_state_notifications.js]
 skip-if = true # Bug 1271028
 [browser_use_counters.js]
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -2,17 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Microsoft's API Name hackery sucks
 #undef CreateEvent
 
-#include "mozilla/AddonPathService.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/HalSensor.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/JSEventHandler.h"
@@ -982,18 +981,16 @@ EventListenerManager::CompileEventHandle
 
   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget);
   uint32_t argCount;
   const char **argNames;
   nsContentUtils::GetEventArgNames(aElement->GetNameSpaceID(),
                                    typeAtom, win,
                                    &argCount, &argNames);
 
-  JSAddonId *addonId = MapURIToAddonID(uri);
-
   // Wrap the event target, so that we can use it as the scope for the event
   // handler. Note that mTarget is different from aElement in the <body> case,
   // where mTarget is a Window.
   //
   // The wrapScope doesn't really matter here, because the target will create
   // its reflector in the proper scope, and then we'll enter that compartment.
   JS::Rooted<JSObject*> wrapScope(cx, global->GetGlobalJSObject());
   JS::Rooted<JS::Value> v(cx);
@@ -1001,30 +998,16 @@ EventListenerManager::CompileEventHandle
     JSAutoCompartment ac(cx, wrapScope);
     nsresult rv = nsContentUtils::WrapNative(cx, mTarget, &v,
                                              /* aAllowWrapping = */ false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
-  if (addonId) {
-    JS::Rooted<JSObject*> vObj(cx, &v.toObject());
-    JS::Rooted<JSObject*> addonScope(cx, xpc::GetAddonScope(cx, vObj, addonId));
-    if (!addonScope) {
-      return NS_ERROR_FAILURE;
-    }
-    JSAutoCompartment ac(cx, addonScope);
-
-    // Wrap our event target into the addon scope, since that's where we want to
-    // do all our work.
-    if (!JS_WrapValue(cx, &v)) {
-      return NS_ERROR_FAILURE;
-    }
-  }
   JS::Rooted<JSObject*> target(cx, &v.toObject());
   JSAutoCompartment ac(cx, target);
 
   // Now that we've entered the compartment we actually care about, create our
   // scope chain.  Note that we start with |element|, not aElement, because
   // mTarget is different from aElement in the <body> case, where mTarget is a
   // Window, and in that case we do not want the scope chain to include the body
   // or the document.
--- a/dom/events/PointerEventHandler.h
+++ b/dom/events/PointerEventHandler.h
@@ -133,16 +133,17 @@ public:
    * We add mPreventMouseEventByContent flag in PointerInfo to represent the
    * active pointer won't firing compatible mouse events. It's set to true when
    * content preventDefault on pointerdown
    */
   static void PostHandlePointerEventsPreventDefault(
                 WidgetPointerEvent* aPointerEvent,
                 WidgetGUIEvent* aMouseOrTouchEvent);
 
+  MOZ_CAN_RUN_SCRIPT
   static void DispatchPointerFromMouseOrTouch(PresShell* aShell,
                                               nsIFrame* aFrame,
                                               nsIContent* aContent,
                                               WidgetGUIEvent* aEvent,
                                               bool aDontRetargetEvents,
                                               nsEventStatus* aStatus,
                                               nsIContent** aTargetContent);
 
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -202,27 +202,22 @@ function verifyView(view1, view2)
 {
   is(view1.byteLength, view2.byteLength, "Correct byteLength");
   verifyBuffers(view1, view2);
   continueToNextStep();
 }
 
 function verifyWasmModule(module1, module2)
 {
-  let getGlobalForObject = SpecialPowers.Cu.getGlobalForObject;
-  let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
-  let wasmExtractCode = SpecialPowers.unwrap(testingFunctions.wasmExtractCode);
-  let exp1 = wasmExtractCode(module1, "ion");
-  let exp2 = wasmExtractCode(module2, "ion");
-  let code1 = exp1.code;
-  let code2 = exp2.code;
-  ok(code1 instanceof getGlobalForObject(code1).Uint8Array, "Instance of Uint8Array");
-  ok(code2 instanceof getGlobalForObject(code1).Uint8Array, "Instance of Uint8Array");
-  ok(code1.length == code2.length, "Correct length");
-  verifyBuffers(code1, code2);
+  // We assume the given modules have no imports and export a single function
+  // named 'run'.
+  var instance1 = new WebAssembly.Instance(module1);
+  var instance2 = new WebAssembly.Instance(module2);
+  is(instance1.exports.run(), instance2.exports.run(), "same run() result");
+
   continueToNextStep();
 }
 
 function grabFileUsageAndContinueHandler(request)
 {
   testGenerator.next(request.result.fileUsage);
 }
 
--- a/dom/indexedDB/test/unit/test_wasm_getAll.js
+++ b/dom/indexedDB/test/unit/test_wasm_getAll.js
@@ -18,45 +18,45 @@ function* testSteps()
     { key: 3, value: [null, null, null, null, null] }
   ];
 
   if (!isWasmSupported()) {
     finishTest();
     return;
   }
 
-  getWasmBinary("(module (func (result i32) (i32.const 1)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 1)))`);
   let binary = yield undefined;
   wasmData[1].value[0] = getWasmModule(binary);
 
-  getWasmBinary("(module (func (result i32) (i32.const 2)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 2)))`);
   binary = yield undefined;
   wasmData[1].value[1] = getWasmModule(binary);
 
-  getWasmBinary("(module (func (result i32) (i32.const 3)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 3)))`);
   binary = yield undefined;
   wasmData[1].value[2] = getWasmModule(binary);
 
-  getWasmBinary("(module (func (result i32) (i32.const 4)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 4)))`);
   binary = yield undefined;
   wasmData[2].value[0] = getWasmModule(binary);
 
-  getWasmBinary("(module (func (result i32) (i32.const 5)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 5)))`);
   binary = yield undefined;
   wasmData[2].value[1] = getWasmModule(binary);
 
-  getWasmBinary("(module (func (result i32) (i32.const 6)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 6)))`);
   binary = yield undefined;
   wasmData[2].value[2] = getWasmModule(binary);
 
-  getWasmBinary("(module (func (result i32) (i32.const 7)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 7)))`);
   binary = yield undefined;
   wasmData[2].value[3] = getWasmModule(binary);
 
-  getWasmBinary("(module (func (result i32) (i32.const 8)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 8)))`);
   binary = yield undefined;
   wasmData[2].value[4] = getWasmModule(binary);
 
   let request = indexedDB.open(name, 1);
   request.onerror = errorHandler;
   request.onupgradeneeded = continueToNextStepSync;
   request.onsuccess = unexpectedSuccessHandler;
   yield undefined;
--- a/dom/indexedDB/test/unit/test_wasm_put_get_values.js
+++ b/dom/indexedDB/test/unit/test_wasm_put_get_values.js
@@ -14,17 +14,17 @@ function* testSteps()
 
   const wasmData = { key: 1, value: null };
 
   if (!isWasmSupported()) {
     finishTest();
     return;
   }
 
-  getWasmBinary("(module (func (nop)))");
+  getWasmBinary(`(module (func (export "run") (result i32) (i32.const 13)))`);
   let binary = yield undefined;
   wasmData.value = getWasmModule(binary);
 
   info("Opening database");
 
   let request = indexedDB.open(name);
   request.onerror = errorHandler;
   request.onupgradeneeded = continueToNextStepSync;
--- a/dom/indexedDB/test/unit/test_wasm_recompile.js
+++ b/dom/indexedDB/test/unit/test_wasm_recompile.js
@@ -16,27 +16,27 @@ function* testSteps()
   // The goal of this test is to prove that wasm is recompiled and the on-disk
   // copy updated.
 
   if (!isWasmSupported()) {
     finishTest();
     yield undefined;
   }
 
-  getWasmBinary("(module (func (nop)))");
+  getWasmBinary('(module (func $f (result i32) (i32.const 42)) (func (export "run") (result i32) (call $f)))');
   let binary = yield undefined;
 
   wasmData.wasm = getWasmModule(binary);
 
   info("Installing profile");
 
   clearAllDatabases(continueToNextStepSync);
   yield undefined;
 
-  // The profile was created by an older build (buildId: 20161116145318,
+  // The profile was created with a mythical build (buildId: 20180309213541,
   // cpuId: X64=0x2). It contains one stored wasm module (file id 1 - bytecode
   // and file id 2 - compiled/machine code). The file create_db.js in the
   // package was run locally (specifically it was temporarily added to
   // xpcshell-parent-process.ini and then executed:
   // mach xpcshell-test dom/indexedDB/test/unit/create_db.js
   installPackagedProfile("wasm_recompile_profile");
 
   let filesDir = getChromeFilesDir();
index 8f9d67868e5db71b52e0fa3a996afac5dc5f1be7..916f7414d4192ead38b82cabf216f0a0cc0d6ae7
GIT binary patch
literal 5596
zc$}?R2|QHm8y?pdQ^-|FkwM9tU1ZO`%f60f#yVpiOV;eN6E3opsBA;FBJ@uv22mK2
zEZHT?m_ags(!H14t=xN?`F-d2eKT{O=Q;2DooC+nXsHqs(EtE|Lx81fdo{EOK#k-V
z0KkX{05}Xd39xp9Sb9J#Y^-=3-1T(H0E7yVJY&V}f$#<b2#Bx*0Kn(7{V%t}U!SLX
zG{;#j8>FRhTF73L=Zc*}ZoS~S5x@l!!G}rdD!1Dd9fTGey_5%H=P&Z4R^1q&?<_4e
zB3YEDJgp{W*jp^YPD-6mJ(Ne}{1|yOAY8AAh)b<Cg(vDhwjswLrR-V#6=}=bPCJ7W
zuXX*Ov=NnT-4g2cS#M~A>ZMA!02#CJ;U~CpEl;K}4H&ezzF*sYF}u-}?h1PeUsidU
zPZD;+%!$k1S8x$^3!Mr}=2eEnbvMN36QPLsU@^LA1Mwd2(K`vxEL^%~=8p!9o{w0m
z(7h2t0Rz4c)e|c7YLj2)$JCc!2Xc}}762UbQ%v3_WKB!ylZ2Io=CbwBw;2w#NFLch
zkL%dONj=-dSmdG~kEM);UgD~Kp|i!rLk`B6#PLX(C!iy(9z<;<yv|)2i)0oxlDrpv
zOH^IM7*nQV<<V$caHy;?fF4f;wOv$PZdP#MQ^<8}TApL9>N%n`R{WsJ?_!MD@j%jR
zK^g2x=v-6N)bJ6mPR@q|%qnupHTH`$>sgKiw<IowHk6z8#GU2_F`pwvdOT)u56i5i
zX_twXiv!B$x`$F^=-legGmWc?YEk9WJ$CX?gZ)IwByYM;#|B=jv4A&HCu@F=6|J07
z`~FzV!?c;Xrn$3+#EmzuZ{F5-J2&t@bXRtDkYtcHE+xS;?V59|Dn6#XV~ap*doPg#
zc3!aUy#(0vI<&o)+&!G#ENvmYpZAfvO`h>t+pqS~w-KoKAh<x>V3u$Q+~Z$j(f=)$
zwVj(Y?BB{e^*u;?8><7tLLTggmHiQ{fFK{gh>)nz1rK+KgFDamz3Sv;Z|UL=gE?DR
zyYWEnognVJ+!VIo<lepicP?p}j`Z$@?UnNOkozgzeBZlpYbCBuhz%GFc7oa2fx&8E
zaIr0%gfE?r4t+xAFbUSPjK*Eto{^BH-=@q4XxO41&G3W@JVNrFM5z80)eg=GH@Kyf
z`w!E$8@ipeaa+W;R}lgLQNRAI(DDC~H;S*x-|MQ|(J0fDrn6@9vFHnJ<wihoT4$ND
zPm95xpOnL#ro+je+VDFB#7GHPg|iCSC>#R)hE5K<DZ$k~>`Ccs_##A>Dv^B_s+{T_
zNd>WV1~DfdV?oL24)re8&&;A<p0T0`21|LHA%_k0J`~~1S8GBO5V^1Agv8~lZq~jR
zsuFLwN5AqbKQM#z6Wti$8!gLN+{BtHJu@9#!tZe7L>*h}N2aJ&m7z8nQcVi34ud40
zgfYdq_L8XJ!cWgHI|L##E@o(1J7}KC?!4W5^Hn(}%G)C6getbEp0IpP>tY`|7j!rK
z<a7rY_g%@OQq)Bnr|4rSZ3-`kJhxu*xMBh_qh>qQCS7wi{I)aghOm)fcRyvub&-wX
zt4G>byUc1<M`LeW4;oxsC&(mj<++Q3H>Q*Wah=Hj38e(}hI{}`v%Mgv6+Tn6o>o+-
z=Usr|eo%HA>?yLq&D-4Y*n1@Ns<an}N;x3=oPWG2+W2wqjMA^ut}}I@)&g8gmSI+{
z{2+ot3LZ_x+4yuqYP?K4A_~Pv6GxJh8o6Xa-=R-UG;I(Y8fjMt<%x49)~pc~yijqm
zls=lEeqjxIrOzUCHb-4MquEdZZ_Z0Yp22sF9qtw3%Ylu)Ye$=itu9;FMEjjFZkl`q
zMNP>QQI`1kI4!tlds1k)qn1W^x|!VqU>LFvI8l!9@+`GSzNwbDHfl>$L#$3d4RGR?
zt=l=t1j@{#ogUVu#XcCu4lB927S)^~=MelHG~~GO%Ep@r9tB>DH2(Wdfn*hq#E&+;
z0(+Ra=8elKns~{L7qRbV#}$k!)?d<%Tv@Q=&?bwMt{A8_qM00?tT3c()!}<{UN_91
zZ($8%3d*MkBKax;!2;qw@w86q{vK6_MbwCIFyCR&QDW?3xzC_~3^^vTlp!g~Sgr89
z@3a#F^HO}xI*=^;v}bFSa5o1wD)m!0wz|)sd+-@ZGESjzXv9ZHuym0$)itrpxaEW2
z6aIh+>(nIyd<TE$5)(H|`;x!*grKH2TNCBw{P-FzwwAejJ<W2uQH#iX)RQqB6BlEg
zZ6zCJ%`3afGTxBWzUUz4PMeUE4@RAN=CuF7DicmbPi>==!2J6p#T{lt{?cs(tZ0k7
z$>=J5GPJ*M9eaw~1YcFU!JEH%S!wMpI`%h=3!Kn`d5M->(3d_FDJL=|85Yy-hureF
zn+(ZZlghXrXnuk<+j}hP?C!y@MQ4>{zu7*j!>rG27g~VF|J~@_U7hSbAb+^k&iJcg
z45@1}DAJKGn#I%$hXxfIYb1k?$lk4fCu^r6SfU%!5AHR(6MgiBh+{eF{d*SE3u4?C
zdMPeoOe*hWb5!NzKEx1W1{sTnU(31Mvx(K2XZj0>@<s-4Nez?@`arSiwoq4nnc_e#
zts^R)nZ{;(&$!{&80bfbSwhDjQ2EBYx1K@!zLFH~TA5!}$9<G$hHtGhq2hkMDeAR~
zE2=?m3U7_0SJ8@3lAkdpBAedE2QX};3lVGvR=&MK1s}SmDE>0MVBx(s%%G&(&9SkN
zu5w<q3KX55q@>~&fY7_HEKT$Lok}re9Nu@BOGW?i^J5SYRKG9Mbci+6@zy0)S9kNg
zx)f-UWrEjp_4{0<lWa-HfS|dw<Y=#238OMD>Z&%YYhm+`jO*1eoqIjp02+FRQV@TQ
zg=C83?3>vu)ULaw^i8|U#vRwhhI~XPmnB;!yM&UUn$=JoVaC160a;4T)QQ66#J(DH
zPQRs4m(RV*^ynGjgf-tOeu%Id?;B#|CPsCb&5urcj{P#BB(*Y?b2eJAe<jRugpLJ*
zTtSZ@^clo@V{D7U>f+6!A64?S<-eT5`?(9U1W#fu)s&u&`-xk!iwikar+-*7UrwJ0
zM%NQ3IpL=Alk7StN^dkKC)PawIOdsw`H*Ao$a_=Qmy?54`1o39(%{`5UXvrME63|9
zeTGV!2=iMsUS%B1hvwj#V+PXS<rhDY52t@poXZ=R?|iDLSJ2f{xvp<Q;0jpe&b-Mm
z{TvrI&oMZ`&~St)t)zCnbV~fFyWXq*8?5!4evnE5P<z<e{qfsbHE=<p6GI&W0v`aS
z_tIhZQ?(o9sVbSi+9;&T!X!;%^GVK>N>Hh95<g24H1tl<S%gJ_jGVFjGNLkgz<5H{
zu{k!$C;nZ<doPfz6(anDnhDvB2L^Erd8PiIvn1k8S*s3)N+{G~Ji^iTl*RO#lFR%2
zw6Z7?SmH|@S^y5h>sVYj>-DkLRYG+xN4Po~o&0nv;%NU9Q6%4`bA+=W-h^KfIn6oA
z&k$y=g|EnEg{Sm99Zb%4HC3e+eUt2X!9}PTv8X?roRDB>`i}Bmg-%@aN)8!mZ^y$S
zn->vXGY}X%!Xc%_Y<9W9YG@_fYs-*=u5h@Jo&!cVC?lQcPw7D`)7!4nZijV_u_`|e
zWmUugb?YQVK&+FKYn`FUhR*Tst3szt)j4gew7c!HNc?hfBEucbZ5gwsQ(;drf`ROY
zJ{cd~6uUpZl`Gx6Vw)Uy^$oCNtK_!uBLhEaAv2h;2CA}PnxxL3qeQ>n>8{h_<&czc
z9dU1^h?we#zTSwl#J+Iqxlw;K@0Vi8g*modL~0$_YX18N+9;qZvKiE!AcM%;47=6e
zexgKh?xRC&=i7cxTqQKiZB$~kE-*RAO|#fycIqsC5)J%vDo-*U)8s8z_~q`o$rULP
z#4s7b?iY`ZX1BKR$dkUmufqgrqw1fq4QFr6bcM+;FPZd<@}T0k5Kn<K&kPh5>l>$R
zCGq2U{FmSJh+M=I?oLeuythbqrw=w4Hz~h}UQZ9i2ih#36Iu6I&ROXs{-VgdfQo6%
z>gG}G#3O+(SV0vyru`;M94)za{Bwa00D!({vOF+|hoz0BhvoN7)EcaAYq9l_l$MZ?
z(8NtaI{?l>4g5<DeT2?(f_8hwu|3!h#K`T*e;`s8LJqKMCwp6$y1W&^UsxR>LrUj&
zLa^PvQ~b$#fIkKx1?D-IvYt{qZ<{)o_IW7S3T$KJqNTN6mV-mBhJvDkE-E!<qe#pn
z2er>1+TkVmg^}=E&kX23=V2!uL05NX`=1~X?><5Js*v76{8r~k_hm)}crT;2&GTm;
zNxXYa{{W48A6ncVw7os$KgXrthdcPUxPSDQ{~Z3*K6q}z@4)Z&nm?xay3^cC5&9#F
z1NNQ7yZy`G>iAaIN%x1Q+gAZZKSKxKzlpi(zJOH!6d`-s%I^vKR#Uk*GUCKPLlFN#
zQ?$QU-75q}_TPm3ZcslC$k%qhS4R)UcXaGA_k;25H}SnZmnaXy^V!l5Mz!C$_fpmV
YN%g}p5tHnkb7cE{eS2r{Q|+w&51g|f`~Uy|
--- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
+++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js
@@ -486,24 +486,22 @@ function verifyView(view1, view2)
 {
   is(view1.byteLength, view2.byteLength, "Correct byteLength");
   verifyBuffers(view1, view2);
   continueToNextStep();
 }
 
 function verifyWasmModule(module1, module2)
 {
-  let testingFunctions = Cu.getJSTestingFunctions();
-  let exp1 = testingFunctions.wasmExtractCode(module1, "ion");
-  let exp2 = testingFunctions.wasmExtractCode(module2, "ion");
-  let code1 = exp1.code;
-  let code2 = exp2.code;
-  ok(code1 instanceof Uint8Array, "Instance of Uint8Array");
-  ok(code1.length == code2.length, "Correct length");
-  verifyBuffers(code1, code2);
+  // We assume the given modules have no imports and export a single function
+  // named 'run'.
+  var instance1 = new WebAssembly.Instance(module1);
+  var instance2 = new WebAssembly.Instance(module2);
+  is(instance1.exports.run(), instance2.exports.run(), "same run() result");
+
   continueToNextStep();
 }
 
 function grabFileUsageAndContinueHandler(request)
 {
   testGenerator.next(request.result.fileUsage);
 }
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -351,16 +351,17 @@ public:
   RecvUpdateDimensions(const mozilla::dom::DimensionInfo& aDimensionInfo) override;
   virtual mozilla::ipc::IPCResult
   RecvSizeModeChanged(const nsSizeMode& aSizeMode) override;
 
   mozilla::ipc::IPCResult RecvActivate();
 
   mozilla::ipc::IPCResult RecvDeactivate();
 
+  MOZ_CAN_RUN_SCRIPT
   virtual mozilla::ipc::IPCResult RecvMouseEvent(const nsString& aType,
                                                  const float& aX,
                                                  const float& aY,
                                                  const int32_t& aButton,
                                                  const int32_t& aClickCount,
                                                  const int32_t& aModifiers,
                                                  const bool& aIgnoreRootScrollFrame) override;
 
@@ -646,22 +647,24 @@ public:
                   PRenderFrameChild* aRenderFrame,
                   const ShowInfo& aShowInfo);
 
   void ContentReceivedInputBlock(const ScrollableLayerGuid& aGuid,
                                  uint64_t aInputBlockId,
                                  bool aPreventDefault) const;
   void SetTargetAPZC(uint64_t aInputBlockId,
                     const nsTArray<ScrollableLayerGuid>& aTargets) const;
+  MOZ_CAN_RUN_SCRIPT
   mozilla::ipc::IPCResult RecvHandleTap(const layers::GeckoContentController::TapType& aType,
                                         const LayoutDevicePoint& aPoint,
                                         const Modifiers& aModifiers,
                                         const ScrollableLayerGuid& aGuid,
                                         const uint64_t& aInputBlockId) override;
 
+  MOZ_CAN_RUN_SCRIPT
   mozilla::ipc::IPCResult
   RecvNormalPriorityHandleTap(const layers::GeckoContentController::TapType& aType,
                               const LayoutDevicePoint& aPoint,
                               const Modifiers& aModifiers,
                               const ScrollableLayerGuid& aGuid,
                               const uint64_t& aInputBlockId) override;
 
   void SetAllowedTouchBehavior(uint64_t aInputBlockId,
--- a/dom/script/ScriptSettings.cpp
+++ b/dom/script/ScriptSettings.cpp
@@ -209,25 +209,16 @@ GetEntryGlobal()
 }
 
 nsIDocument*
 GetEntryDocument()
 {
   nsIGlobalObject* global = GetEntryGlobal();
   nsCOMPtr<nsPIDOMWindowInner> entryWin = do_QueryInterface(global);
 
-  // If our entry global isn't a window, see if it's an addon scope associated
-  // with a window. If it is, the caller almost certainly wants that rather
-  // than null.
-  if (!entryWin && global) {
-    if (auto* win = xpc::AddonWindowOrNull(global->GetGlobalJSObject())) {
-      entryWin = win->AsInner();
-    }
-  }
-
   return entryWin ? entryWin->GetExtantDoc() : nullptr;
 }
 
 nsIGlobalObject*
 GetIncumbentGlobal()
 {
   // We need the current JSContext in order to check the JS for
   // scripted frames that may have appeared since anyone last
@@ -548,22 +539,16 @@ WarningOnlyErrorReporter(JSContext* aCx,
     MOZ_ASSERT(worker);
 
     worker->ReportError(aCx, JS::ConstUTF8CharsZ(), aRep);
     return;
   }
 
   RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
   nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aCx);
-  if (!win) {
-    // We run addons in a separate privileged compartment, but if we're in an
-    // addon compartment we should log warnings to the console of the associated
-    // DOM Window.
-    win = xpc::AddonWindowOrNull(JS::CurrentGlobalOrNull(aCx));
-  }
   xpcReport->Init(aRep, nullptr, nsContentUtils::IsSystemCaller(aCx),
                   win ? win->AsInner()->WindowID() : 0);
   xpcReport->LogToConsole();
 }
 
 void
 AutoJSAPI::ReportException()
 {
@@ -588,21 +573,16 @@ AutoJSAPI::ReportException()
   JS::Rooted<JS::Value> exn(cx());
   js::ErrorReport jsReport(cx());
   if (StealException(&exn) &&
       jsReport.init(cx(), exn, js::ErrorReport::WithSideEffects)) {
     if (mIsMainThread) {
       RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
 
       RefPtr<nsGlobalWindowInner> win = xpc::WindowGlobalOrNull(errorGlobal);
-      if (!win) {
-        // We run addons in a separate privileged compartment, but they still
-        // expect to trigger the onerror handler of their associated DOM Window.
-        win = xpc::AddonWindowOrNull(errorGlobal);
-      }
       nsPIDOMWindowInner* inner = win ? win->AsInner() : nullptr;
       bool isChrome = nsContentUtils::IsSystemPrincipal(
         nsContentUtils::ObjectPrincipal(errorGlobal));
       xpcReport->Init(jsReport.report(), jsReport.toStringResult().c_str(),
                       isChrome,
                       inner ? inner->WindowID() : 0);
       if (inner && jsReport.report()->errorNumber != JSMSG_OUT_OF_MEMORY) {
         JS::RootingContext* rcx = JS::RootingContext::get(cx());
--- a/dom/webidl/DOMTokenList.webidl
+++ b/dom/webidl/DOMTokenList.webidl
@@ -14,17 +14,17 @@ interface DOMTokenList {
   readonly attribute unsigned long length;
   getter DOMString? item(unsigned long index);
   boolean contains(DOMString token);
   [CEReactions, Throws]
   void add(DOMString... tokens);
   [CEReactions, Throws]
   void remove(DOMString... tokens);
   [CEReactions, Throws]
-  void replace(DOMString token, DOMString newToken);
+  boolean replace(DOMString token, DOMString newToken);
   [CEReactions, Throws]
   boolean toggle(DOMString token, optional boolean force);
   [Throws]
   boolean supports(DOMString token);
   [CEReactions, SetterThrows]
   attribute DOMString value;
   stringifier DOMString ();
   iterable<DOMString?>;
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WorkerPrivate.h"
 
-#include "amIAddonManager.h"
 #include "js/MemoryMetrics.h"
 #include "MessageEventRunnable.h"
 #include "mozilla/dom/ClientManager.h"
 #include "mozilla/dom/ClientSource.h"
 #include "mozilla/dom/ClientState.h"
 #include "mozilla/dom/Console.h"
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/dom/ErrorEvent.h"
@@ -1128,22 +1127,20 @@ public:
 class WorkerPrivate::MemoryReporter final : public nsIMemoryReporter
 {
   NS_DECL_THREADSAFE_ISUPPORTS
 
   friend class WorkerPrivate;
 
   SharedMutex mMutex;
   WorkerPrivate* mWorkerPrivate;
-  bool mAlreadyMappedToAddon;
 
 public:
   explicit MemoryReporter(WorkerPrivate* aWorkerPrivate)
-  : mMutex(aWorkerPrivate->mMutex), mWorkerPrivate(aWorkerPrivate),
-    mAlreadyMappedToAddon(false)
+  : mMutex(aWorkerPrivate->mMutex), mWorkerPrivate(aWorkerPrivate)
   {
     aWorkerPrivate->AssertIsOnWorkerThread();
   }
 
   NS_IMETHOD
   CollectReports(nsIHandleReportCallback* aHandleReport,
                  nsISupports* aData, bool aAnonymize) override;
 
@@ -1231,20 +1228,16 @@ private:
   Disable()
   {
     // Called from WorkerPrivate::DisableMemoryReporter.
     mMutex.AssertCurrentThreadOwns();
 
     NS_ASSERTION(mWorkerPrivate, "Disabled more than once!");
     mWorkerPrivate = nullptr;
   }
-
-  // Only call this from the main thread and under mMutex lock.
-  void
-  TryToMapAddon(nsACString &path);
 };
 
 NS_IMPL_ISUPPORTS(WorkerPrivate::MemoryReporter, nsIMemoryReporter)
 
 NS_IMETHODIMP
 WorkerPrivate::MemoryReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
                                               nsISupports* aData,
                                               bool aAnonymize)
@@ -1280,69 +1273,27 @@ WorkerPrivate::MemoryReporter::CollectRe
       path.Append(escapedDomain);
       path.AppendLiteral(")/worker(");
       NS_ConvertUTF16toUTF8 escapedURL(mWorkerPrivate->ScriptURL());
       escapedURL.ReplaceChar('/', '\\');
       path.Append(escapedURL);
     }
     path.AppendPrintf(", 0x%p)/", static_cast<void*>(mWorkerPrivate));
 
-    TryToMapAddon(path);
-
     runnable =
       new CollectReportsRunnable(mWorkerPrivate, aHandleReport, aData, aAnonymize, path);
   }
 
   if (!runnable->Dispatch()) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
-void
-WorkerPrivate::MemoryReporter::TryToMapAddon(nsACString &path)
-{
-  AssertIsOnMainThread();
-  mMutex.AssertCurrentThreadOwns();
-
-  if (mAlreadyMappedToAddon || !mWorkerPrivate) {
-    return;
-  }
-
-  nsCOMPtr<nsIURI> scriptURI;
-  if (NS_FAILED(NS_NewURI(getter_AddRefs(scriptURI),
-                          mWorkerPrivate->ScriptURL()))) {
-    return;
-  }
-
-  mAlreadyMappedToAddon = true;
-
-  if (!XRE_IsParentProcess()) {
-    // Only try to access the service from the main process.
-    return;
-  }
-
-  nsAutoCString addonId;
-  bool ok;
-  nsCOMPtr<amIAddonManager> addonManager =
-    do_GetService("@mozilla.org/addons/integration;1");
-
-  if (!addonManager ||
-      NS_FAILED(addonManager->MapURIToAddonID(scriptURI, addonId, &ok)) ||
-      !ok) {
-    return;
-  }
-
-  static const size_t explicitLength = strlen("explicit/");
-  addonId.InsertLiteral("add-ons/", 0);
-  addonId += "/";
-  path.Insert(addonId, explicitLength);
-}
-
 WorkerPrivate::MemoryReporter::CollectReportsRunnable::CollectReportsRunnable(
   WorkerPrivate* aWorkerPrivate,
   nsIHandleReportCallback* aHandleReport,
   nsISupports* aHandlerData,
   bool aAnonymize,
   const nsACString& aPath)
   : MainThreadWorkerControlRunnable(aWorkerPrivate),
     mFinishCollectRunnable(
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -1110,17 +1110,16 @@ nsXBLBinding::LookupMember(JSContext* aC
   // never get here. But on the off-chance that someone adds new callsites to
   // LookupMember, we do a release-mode assertion as belt-and-braces.
   // We do a release-mode assertion here to be extra safe.
   //
   // This code is only called for content XBL, so we don't have to worry about
   // add-on scopes here.
   JS::Rooted<JSObject*> boundScope(aCx,
     js::GetGlobalForObjectCrossCompartment(mBoundElement->GetWrapper()));
-  MOZ_RELEASE_ASSERT(!xpc::IsInAddonScope(boundScope));
   MOZ_RELEASE_ASSERT(!xpc::IsInContentXBLScope(boundScope));
   JS::Rooted<JSObject*> xblScope(aCx, xpc::GetXBLScope(aCx, boundScope));
   NS_ENSURE_TRUE(xblScope, false);
   MOZ_ASSERT(boundScope != xblScope);
 
   // Enter the xbl scope and invoke the internal version.
   {
     JSAutoCompartment ac(aCx, xblScope);
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -11,17 +11,16 @@
 #include "nsIDocument.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMNode.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLProtoImplProperty.h"
 #include "nsIURI.h"
-#include "mozilla/AddonPathService.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/XULElementBinding.h"
 #include "xpcpublic.h"
 #include "js/CharacterEncoding.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using js::GetGlobalForObjectCrossCompartment;
@@ -78,20 +77,19 @@ nsXBLProtoImpl::InstallImplementation(ns
   // using a separate XBL scope, we want to define them there first (so that
   // they'll be available for Xray lookups, among other things), and then copy
   // the properties to the content-side prototype as needed. We don't need to
   // bother about the field accessors here, since we don't use/support those
   // for in-content bindings.
 
   // First, start by entering the compartment of the XBL scope. This may or may
   // not be the same compartment as globalObject.
-  JSAddonId* addonId = MapURIToAddonID(aPrototypeBinding->BindingURI());
   JS::Rooted<JSObject*> globalObject(cx,
     GetGlobalForObjectCrossCompartment(targetClassObject));
-  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
+  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
   MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(scopeObject) == scopeObject);
   JSAutoCompartment ac(cx, scopeObject);
 
   // Determine the appropriate property holder.
   //
   // Note: If |targetIsNew| is false, we'll early-return above. However, that only
   // tells us if the content-side object is new, which may be the case even if
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -12,17 +12,16 @@
 #include "js/CharacterEncoding.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsXBLProtoImplField.h"
 #include "nsIScriptContext.h"
 #include "nsIURI.h"
 #include "nsXBLSerialize.h"
 #include "nsXBLPrototypeBinding.h"
-#include "mozilla/AddonPathService.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ElementBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsGlobalWindow.h"
 #include "xpcpublic.h"
 #include "WrapperFactory.h"
 
 using namespace mozilla;
@@ -397,40 +396,38 @@ nsXBLProtoImplField::InstallField(JS::Ha
 
   nsIGlobalObject* globalObject = xpc::WindowGlobalOrNull(aBoundNode);
   if (!globalObject) {
     return NS_OK;
   }
 
   // We are going to run script via EvaluateString, so we need a script entry
   // point, but as this is XBL related it does not appear in the HTML spec.
-  // We need an actual JSContext to do GetScopeForXBLExecution, and it needs to
+  // We need an actual JSContext to do GetXBLScopeOrGlobal, and it needs to
   // be in the compartment of globalObject.  But we want our XBL execution scope
   // to be our entry global.
   AutoJSAPI jsapi;
   if (!jsapi.Init(globalObject)) {
     return NS_ERROR_UNEXPECTED;
   }
   MOZ_ASSERT(!::JS_IsExceptionPending(jsapi.cx()),
              "Shouldn't get here when an exception is pending!");
 
-  JSAddonId* addonId = MapURIToAddonID(aBindingDocURI);
-
   // Note: the UNWRAP_OBJECT may mutate boundNode; don't use it after that call.
   JS::Rooted<JSObject*> boundNode(jsapi.cx(), aBoundNode);
   Element* boundElement = nullptr;
   rv = UNWRAP_OBJECT(Element, &boundNode, boundElement);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   // First, enter the xbl scope, build the element's scope chain, and use
   // that as the scope chain for the evaluation.
   JS::Rooted<JSObject*> scopeObject(jsapi.cx(),
-    xpc::GetScopeForXBLExecution(jsapi.cx(), aBoundNode, addonId));
+    xpc::GetXBLScopeOrGlobal(jsapi.cx(), aBoundNode));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   AutoEntryScript aes(scopeObject, "XBL <field> initialization", true);
   JSContext* cx = aes.cx();
 
   JS::Rooted<JS::Value> result(cx);
   JS::CompileOptions options(cx);
   options.setFileAndLine(uriSpec.get(), mLineNumber);
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -98,17 +98,16 @@ nsXBLProtoImplMethod::InstallMember(JSCo
   NS_PRECONDITION(IsCompiled(),
                   "Should not be installing an uncompiled method");
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
 
 #ifdef DEBUG
   {
     JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
     MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
-               xpc::IsInAddonScope(globalObject) ||
                globalObject == xpc::GetXBLScope(aCx, globalObject));
     MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
   }
 #endif
 
   JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
   if (jsMethodObject) {
     nsDependentString name(mName);
@@ -255,17 +254,17 @@ nsXBLProtoImplMethod::Write(nsIObjectOut
     JS::Rooted<JSObject*> method(RootingCx(), GetCompiledMethod());
     return XBL_SerializeFunction(aStream, method);
   }
 
   return NS_OK;
 }
 
 nsresult
-nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAddonId)
+nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
 {
   MOZ_ASSERT(aBoundElement->IsElement());
   NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
 
   if (!GetCompiledMethod()) {
     // Nothing to do here
     return NS_OK;
   }
@@ -279,28 +278,26 @@ nsXBLProtoImplAnonymousMethod::Execute(n
   if (!global) {
     return NS_OK;
   }
 
   nsAutoMicroTask mt;
 
   // We are going to run script via JS::Call, so we need a script entry point,
   // but as this is XBL related it does not appear in the HTML spec.
-  // We need an actual JSContext to do GetScopeForXBLExecution, and it needs to
+  // We need an actual JSContext to do GetXBLScopeOrGlobal, and it needs to
   // be in the compartment of globalObject.  But we want our XBL execution scope
   // to be our entry global.
   AutoJSAPI jsapi;
   if (!jsapi.Init(global)) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  JS::Rooted<JSObject*> globalObject(jsapi.cx(), global->GetGlobalJSObject());
-
   JS::Rooted<JSObject*> scopeObject(jsapi.cx(),
-    xpc::GetScopeForXBLExecution(jsapi.cx(), globalObject, aAddonId));
+    xpc::GetXBLScopeOrGlobal(jsapi.cx(), global->GetGlobalJSObject()));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   dom::AutoEntryScript aes(scopeObject,
                            "XBL <constructor>/<destructor> invocation",
                            true);
   JSContext* cx = aes.cx();
   JS::AutoObjectVector scopeChain(cx);
   if (!nsJSUtils::GetScopeChainForElement(cx, aBoundElement->AsElement(),
--- a/dom/xbl/nsXBLProtoImplMethod.h
+++ b/dom/xbl/nsXBLProtoImplMethod.h
@@ -133,17 +133,17 @@ protected:
 };
 
 class nsXBLProtoImplAnonymousMethod : public nsXBLProtoImplMethod {
 public:
   explicit nsXBLProtoImplAnonymousMethod(const char16_t* aName) :
     nsXBLProtoImplMethod(aName)
   {}
 
-  nsresult Execute(nsIContent* aBoundElement, JSAddonId* aAddonId);
+  nsresult Execute(nsIContent* aBoundElement);
 
   // Override InstallMember; these methods never get installed as members on
   // binding instantiations (though they may hang out in mMembers on the
   // prototype implementation).
   virtual nsresult InstallMember(JSContext* aCx,
                                  JS::Handle<JSObject*> aTargetClassObject) override {
     return NS_OK;
   }
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -129,17 +129,16 @@ nsXBLProtoImplProperty::InstallMember(JS
                   "Should not be installing an uncompiled property");
   MOZ_ASSERT(mGetter.IsCompiled() && mSetter.IsCompiled());
   MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
 
 #ifdef DEBUG
   {
     JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
     MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
-               xpc::IsInAddonScope(globalObject) ||
                globalObject == xpc::GetXBLScope(aCx, globalObject));
     MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == globalObject);
   }
 #endif
 
   JS::Rooted<JSObject*> getter(aCx, mGetter.GetJSFunction());
   JS::Rooted<JSObject*> setter(aCx, mSetter.GetJSFunction());
   if (getter || setter) {
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -38,17 +38,16 @@
 #include "nsTextNode.h"
 #include "nsIInterfaceInfo.h"
 #include "nsIScriptError.h"
 
 #ifdef MOZ_OLD_STYLE
 #include "nsCSSRuleProcessor.h"
 #endif
 #include "nsXBLResourceLoader.h"
-#include "mozilla/AddonPathService.h"
 #include "mozilla/dom/CDATASection.h"
 #include "mozilla/dom/Comment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 
 #ifdef MOZ_XUL
 #include "nsXULElement.h"
@@ -278,26 +277,26 @@ nsXBLPrototypeBinding::FlushSkinSheets()
   return NS_OK;
 }
 
 nsresult
 nsXBLPrototypeBinding::BindingAttached(nsIContent* aBoundElement)
 {
   if (mImplementation && mImplementation->CompiledMembers() &&
       mImplementation->mConstructor)
-    return mImplementation->mConstructor->Execute(aBoundElement, MapURIToAddonID(mBindingURI));
+    return mImplementation->mConstructor->Execute(aBoundElement);
   return NS_OK;
 }
 
 nsresult
 nsXBLPrototypeBinding::BindingDetached(nsIContent* aBoundElement)
 {
   if (mImplementation && mImplementation->CompiledMembers() &&
       mImplementation->mDestructor)
-    return mImplementation->mDestructor->Execute(aBoundElement, MapURIToAddonID(mBindingURI));
+    return mImplementation->mDestructor->Execute(aBoundElement);
   return NS_OK;
 }
 
 nsXBLProtoImplAnonymousMethod*
 nsXBLPrototypeBinding::GetConstructor()
 {
   if (mImplementation)
     return mImplementation->mConstructor;
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -29,17 +29,16 @@
 #include "nsPIWindowRoot.h"
 #include "nsIDOMWindow.h"
 #include "nsIServiceManager.h"
 #include "nsIScriptError.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsGkAtoms.h"
 #include "nsIXPConnect.h"
-#include "mozilla/AddonPathService.h"
 #include "nsDOMCID.h"
 #include "nsUnicharUtils.h"
 #include "nsCRT.h"
 #include "nsXBLEventHandler.h"
 #include "nsXBLSerialize.h"
 #include "nsJSUtils.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/JSEventHandler.h"
@@ -343,20 +342,17 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
     return NS_OK;
   }
   JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> handler(cx);
 
   rv = EnsureEventHandler(jsapi, onEventAtom, &handler);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  JSAddonId* addonId = MapURIToAddonID(mPrototypeBinding->DocURI());
-
-  JS::Rooted<JSObject*> globalObject(cx, boundGlobal->GetGlobalJSObject());
-  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
+  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, boundGlobal->GetGlobalJSObject()));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   // Bind it to the bound element. Note that if we're using a separate XBL scope,
   // we'll actually be binding the event handler to a cross-compartment wrapper
   // to the bound element's reflector.
 
   // First, enter our XBL scope. This is where the generic handler should have
   // been compiled, above.
@@ -413,19 +409,17 @@ nsXBLPrototypeHandler::EnsureEventHandle
       return NS_OK;
     }
   }
 
   // Ensure that we have something to compile
   nsDependentString handlerText(mHandlerText);
   NS_ENSURE_TRUE(!handlerText.IsEmpty(), NS_ERROR_FAILURE);
 
-  JSAddonId* addonId = MapURIToAddonID(mPrototypeBinding->DocURI());
-
-  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
+  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   nsAutoCString bindingURI;
   nsresult rv = mPrototypeBinding->DocURI()->GetSpec(bindingURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t argCount;
   const char **argNames;
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -73,17 +73,16 @@
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIObserverService.h"
 #include "nsNodeUtils.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIXULWindow.h"
 #include "nsXULPopupManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsURILoader.h"
-#include "mozilla/AddonPathService.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/NodeInfoInlines.h"
 #include "mozilla/dom/ProcessingInstruction.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/XULDocumentBinding.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/LoadInfo.h"
@@ -3174,22 +3173,18 @@ XULDocument::ExecuteScript(nsXULPrototyp
     // We're about to run script via JS::CloneAndExecuteScript, so we need an
     // AutoEntryScript. This is Gecko specific and not in any spec.
     AutoEntryScript aes(mScriptGlobalObject, "precompiled XUL <script> element");
     JSContext* cx = aes.cx();
 
     JS::Rooted<JSScript*> scriptObject(cx, aScript->GetScriptObject());
     NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
 
-    JS::Rooted<JSObject*> baseGlobal(cx, JS::CurrentGlobalOrNull(cx));
-    NS_ENSURE_TRUE(xpc::Scriptability::Get(baseGlobal).Allowed(), NS_OK);
-
-    JSAddonId* addonId = mCurrentPrototype ? MapURIToAddonID(mCurrentPrototype->GetURI()) : nullptr;
-    JS::Rooted<JSObject*> global(cx, xpc::GetAddonScope(cx, baseGlobal, addonId));
-    NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
+    JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
+    NS_ENSURE_TRUE(xpc::Scriptability::Get(global).Allowed(), NS_OK);
 
     JS::ExposeObjectToActiveJS(global);
     JSAutoCompartment ac(cx, global);
 
     // The script is in the compilation scope. Clone it into the target scope
     // and execute it. On failure, ~AutoScriptEntry will handle exceptions, so
     // there is no need to manually check the return value.
     JS::RootedValue rval(cx);
--- a/gfx/angle/checkout/out/gen/angle/id/commit.h
+++ b/gfx/angle/checkout/out/gen/angle/id/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "7edc21933ef1"
+#define ANGLE_COMMIT_HASH "27cef491162b"
 #define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2018-03-01 22:15:11 -0800"
+#define ANGLE_COMMIT_DATE "2018-03-14 13:28:50 -0700"
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -246,19 +246,19 @@ StateManager11::SRVCache *StateManager11
     }
 }
 
 // ShaderConstants11 implementation
 ShaderConstants11::ShaderConstants11()
     : mVertexDirty(true),
       mPixelDirty(true),
       mComputeDirty(true),
-      mSamplerMetadataVSDirty(true),
-      mSamplerMetadataPSDirty(true),
-      mSamplerMetadataCSDirty(true)
+      mNumActiveVSSamplers(0),
+      mNumActivePSSamplers(0),
+      mNumActiveCSSamplers(0)
 {
 }
 
 ShaderConstants11::~ShaderConstants11()
 {
 }
 
 void ShaderConstants11::init(const gl::Caps &caps)
@@ -281,22 +281,22 @@ size_t ShaderConstants11::getRequiredBuf
         default:
             UNREACHABLE();
             return 0;
     }
 }
 
 void ShaderConstants11::markDirty()
 {
-    mVertexDirty            = true;
-    mPixelDirty             = true;
-    mComputeDirty           = true;
-    mSamplerMetadataVSDirty = true;
-    mSamplerMetadataPSDirty = true;
-    mSamplerMetadataCSDirty = true;
+    mVertexDirty         = true;
+    mPixelDirty          = true;
+    mComputeDirty        = true;
+    mNumActiveVSSamplers = 0;
+    mNumActivePSSamplers = 0;
+    mNumActiveCSSamplers = 0;
 }
 
 bool ShaderConstants11::updateSamplerMetadata(SamplerMetadata *data, const gl::Texture &texture)
 {
     bool dirty             = false;
     unsigned int baseLevel = texture.getTextureState().getEffectiveBaseLevel();
     GLenum sizedFormat =
         texture.getFormat(texture.getTarget(), baseLevel).info->sizedInternalFormat;
@@ -455,29 +455,29 @@ void ShaderConstants11::onSamplerChange(
                                         unsigned int samplerIndex,
                                         const gl::Texture &texture)
 {
     switch (shaderType)
     {
         case gl::SHADER_VERTEX:
             if (updateSamplerMetadata(&mSamplerMetadataVS[samplerIndex], texture))
             {
-                mSamplerMetadataVSDirty = true;
+                mNumActiveVSSamplers = 0;
             }
             break;
         case gl::SHADER_FRAGMENT:
             if (updateSamplerMetadata(&mSamplerMetadataPS[samplerIndex], texture))
             {
-                mSamplerMetadataPSDirty = true;
+                mNumActivePSSamplers = 0;
             }
             break;
         case gl::SHADER_COMPUTE:
             if (updateSamplerMetadata(&mSamplerMetadataCS[samplerIndex], texture))
             {
-                mSamplerMetadataCSDirty = true;
+                mNumActiveCSSamplers = 0;
             }
             break;
         default:
             UNREACHABLE();
             break;
     }
 }
 
@@ -486,41 +486,45 @@ gl::Error ShaderConstants11::updateBuffe
                                           const ProgramD3D &programD3D,
                                           const d3d11::Buffer &driverConstantBuffer)
 {
     bool dirty                 = false;
     size_t dataSize            = 0;
     const uint8_t *data        = nullptr;
     const uint8_t *samplerData = nullptr;
 
+    // Re-upload the sampler meta-data if the current program uses more samplers
+    // than we previously uploaded.
+    int numSamplers = programD3D.getUsedSamplerRange(shaderType);
+
     switch (shaderType)
     {
         case gl::SHADER_VERTEX:
-            dirty                   = mVertexDirty || mSamplerMetadataVSDirty;
+            dirty                   = mVertexDirty || (mNumActiveVSSamplers < numSamplers);
             dataSize                = sizeof(Vertex);
             data                    = reinterpret_cast<const uint8_t *>(&mVertex);
             samplerData             = reinterpret_cast<const uint8_t *>(mSamplerMetadataVS.data());
             mVertexDirty            = false;
-            mSamplerMetadataVSDirty = false;
+            mNumActiveVSSamplers    = numSamplers;
             break;
         case gl::SHADER_FRAGMENT:
-            dirty                   = mPixelDirty || mSamplerMetadataPSDirty;
+            dirty                   = mPixelDirty || (mNumActivePSSamplers < numSamplers);
             dataSize                = sizeof(Pixel);
             data                    = reinterpret_cast<const uint8_t *>(&mPixel);
             samplerData             = reinterpret_cast<const uint8_t *>(mSamplerMetadataPS.data());
             mPixelDirty             = false;
-            mSamplerMetadataPSDirty = false;
+            mNumActivePSSamplers    = numSamplers;
             break;
         case gl::SHADER_COMPUTE:
-            dirty                   = mComputeDirty || mSamplerMetadataCSDirty;
+            dirty                   = mComputeDirty || (mNumActiveCSSamplers < numSamplers);
             dataSize                = sizeof(Compute);
             data                    = reinterpret_cast<const uint8_t *>(&mCompute);
             samplerData             = reinterpret_cast<const uint8_t *>(mSamplerMetadataCS.data());
             mComputeDirty           = false;
-            mSamplerMetadataCSDirty = false;
+            mNumActiveCSSamplers    = numSamplers;
             break;
         default:
             UNREACHABLE();
             break;
     }
 
     ASSERT(driverConstantBuffer.valid());
 
@@ -529,20 +533,20 @@ gl::Error ShaderConstants11::updateBuffe
         return gl::NoError();
     }
 
     // Previous buffer contents are discarded, so we need to refresh the whole buffer.
     D3D11_MAPPED_SUBRESOURCE mapping = {0};
     ANGLE_TRY(
         renderer->mapResource(driverConstantBuffer.get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mapping));
 
-    size_t samplerDataBytes = sizeof(SamplerMetadata) * programD3D.getUsedSamplerRange(shaderType);
-
     memcpy(mapping.pData, data, dataSize);
-    memcpy(reinterpret_cast<uint8_t *>(mapping.pData) + dataSize, samplerData, samplerDataBytes);
+    memcpy(reinterpret_cast<uint8_t *>(mapping.pData) + dataSize,
+           samplerData,
+           sizeof(SamplerMetadata) * numSamplers);
 
     renderer->getDeviceContext()->Unmap(driverConstantBuffer.get(), 0);
 
     return gl::NoError();
 }
 
 static const GLenum QueryTypes[] = {GL_ANY_SAMPLES_PASSED, GL_ANY_SAMPLES_PASSED_CONSERVATIVE,
                                     GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_TIME_ELAPSED_EXT,
@@ -1006,16 +1010,17 @@ void StateManager11::syncState(const gl:
             case gl::State::DIRTY_BIT_PROGRAM_EXECUTABLE:
             {
                 mInternalDirtyBits.set(DIRTY_BIT_SHADERS);
                 invalidateVertexBuffer();
                 invalidateRenderTarget();
                 invalidateTexturesAndSamplers();
                 invalidateProgramUniforms();
                 invalidateProgramUniformBuffers();
+                invalidateDriverUniforms();
                 gl::VertexArray *vao = state.getVertexArray();
                 if (mIsMultiviewEnabled && vao != nullptr)
                 {
                     // If ANGLE_multiview is enabled, the attribute divisor has to be updated for
                     // each binding.
                     VertexArray11 *vao11       = GetImplAs<VertexArray11>(vao);
                     const gl::Program *program = state.getProgram();
                     int numViews               = 1;
--- a/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
+++ b/gfx/angle/checkout/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
@@ -129,21 +129,21 @@ class ShaderConstants11 : angle::NonCopy
     Vertex mVertex;
     bool mVertexDirty;
     Pixel mPixel;
     bool mPixelDirty;
     Compute mCompute;
     bool mComputeDirty;
 
     std::vector<SamplerMetadata> mSamplerMetadataVS;
-    bool mSamplerMetadataVSDirty;
+    int mNumActiveVSSamplers;
     std::vector<SamplerMetadata> mSamplerMetadataPS;
-    bool mSamplerMetadataPSDirty;
+    int mNumActivePSSamplers;
     std::vector<SamplerMetadata> mSamplerMetadataCS;
-    bool mSamplerMetadataCSDirty;
+    int mNumActiveCSSamplers;
 };
 
 class DrawCallVertexParams final : angle::NonCopyable
 {
   public:
     // Use when in a drawArrays call.
     DrawCallVertexParams(GLint firstVertex, GLsizei vertexCount, GLsizei instances);
 
--- a/gfx/angle/cherries.log
+++ b/gfx/angle/cherries.log
@@ -1,8 +1,24 @@
+commit 27cef491162bfa5d5d69cf65758bd9b85033d339
+Author: Dzmitry Malyshau <kvark@mozilla.com>
+Date:   Fri Mar 9 16:37:22 2018 -0500
+
+    Update driver constants on program change. Comes with a new SamplerMetadataUpdateOnSetProgram test.
+    
+    This is a fix for a graphics problem we've been seeing for a while with WebRender+Angle on Nvidia/Windows. The sampler metadata doesn't get updated properly for some of the draw calls, since it's not invalidated on program change (this is what the CL is fixing). Extra entries get filled with garbage data because the constant buffer is updated with `MAP_WRITE_DISCARD`, and only those samplers are updated that the current program has. This may generally occur undetected, if not for our `textureSize` calls that appear to go the NV-specific Angle workaround path that ignores our `baseLevel = 0` and instead picks the one from the driver constants (which contains garbage), leading to either zeroes returned or even crashing the driver sometimes...
+    
+    BUG=angleproject:2399
+    
+    Change-Id: Ie2bef32184e2305c7255299933b899eb3fffb7ab
+    Reviewed-on: https://chromium-review.googlesource.com/949412
+    Reviewed-by: Jamie Madill <jmadill@chromium.org>
+    Reviewed-by: Geoff Lang <geofflang@chromium.org>
+    Commit-Queue: Geoff Lang <geofflang@chromium.org>
+
 commit 7edc21933ef15d10e5790e6bfb7f9fd62f13be58
 Author: Frank Henigman <fjhenigman@chromium.org>
 Date:   Wed Feb 28 15:47:13 2018 -0500
 
     Add missing #include.
     
     Would not compile locally on Linux without adding #include <algorithm>.
     
--- a/gfx/layers/LayersTypes.h
+++ b/gfx/layers/LayersTypes.h
@@ -328,42 +328,16 @@ public:
   }
   uint64_t Value() const {
     return mHandle;
   }
 private:
   uint64_t mHandle;
 };
 
-class ReadLockHandle
-{
-  friend struct IPC::ParamTraits<mozilla::layers::ReadLockHandle>;
-public:
-  ReadLockHandle() : mHandle(0)
-  {}
-  ReadLockHandle(const ReadLockHandle& aOther) : mHandle(aOther.mHandle)
-  {}
-  explicit ReadLockHandle(uint64_t aHandle) : mHandle(aHandle)
-  {}
-  bool IsValid() const {
-    return mHandle != 0;
-  }
-  explicit operator bool() const {
-    return IsValid();
-  }
-  bool operator ==(const ReadLockHandle& aOther) const {
-    return mHandle == aOther.mHandle;
-  }
-  uint64_t Value() const {
-    return mHandle;
-  }
-private:
-  uint64_t mHandle;
-};
-
 MOZ_DEFINE_ENUM_CLASS_WITH_BASE(ScrollDirection, uint32_t, (
   eVertical,
   eHorizontal
 ));
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/TextureDIB.cpp
+++ b/gfx/layers/TextureDIB.cpp
@@ -2,18 +2,19 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "TextureDIB.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h" // For BufferSizeFromDimensions
+#include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
-#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/TextureForwarder.h" // For LayersIPCChannel
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 /**
--- a/gfx/layers/apz/test/mochitest/helper_bug1414336.html
+++ b/gfx/layers/apz/test/mochitest/helper_bug1414336.html
@@ -67,26 +67,32 @@ waitUntilApzStable().then(() => {
     target0.addEventListener(elem, (event) => {
       is(event.type, target0_events[0], "receive " + event.type + " on target0");
       target0_events.shift();
     }, { once: true });
   });
 
   target0.addEventListener("pointercancel", (event) => {
     ok(false, "Shouldn't receive pointercancel when content prevents default on touchstart");
-    subtestDone();
+    // Wait until the event is done processing before we end the subtest,
+    // otherwise on Android the pointer events pref is flipped back to false
+    // and debug builds will assert.
+    setTimeout(subtestDone, 0);
   }, { once: true });
 
   target0.addEventListener("touchstart", (event) => {
     event.preventDefault();
   }, { once: true });
 
   target0.addEventListener("pointerup", (event) => {
     ok(target0_events.length == 0, " should receive " + target0_events + " on target0");
-    subtestDone();
+    // Wait until the event is done processing before we end the subtest,
+    // otherwise on Android the pointer events pref is flipped back to false
+    // and debug builds will assert.
+    setTimeout(subtestDone, 0);
   }, { once: true });
 
   synthesizeNativeTouchDrag(target0, 2, 2, 0, 80);
 });
 
 </script>
 </body>
 </html>
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -109,16 +109,17 @@ public:
                                                        uint64_t aTime,
                                                        const LayoutDevicePoint& aRefPoint,
                                                        Modifiers aModifiers,
                                                        int32_t aClickCount,
                                                        nsIWidget* aWidget);
 
     /* Dispatch a mouse event with the given parameters.
      * Return whether or not any listeners have called preventDefault on the event. */
+    MOZ_CAN_RUN_SCRIPT
     static bool DispatchMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell,
                                    const nsString& aType,
                                    const CSSPoint& aPoint,
                                    int32_t aButton,
                                    int32_t aClickCount,
                                    int32_t aModifiers,
                                    bool aIgnoreRootScrollFrame,
                                    unsigned short aInputSourceArg,
--- a/gfx/layers/apz/util/APZEventState.h
+++ b/gfx/layers/apz/util/APZEventState.h
@@ -49,22 +49,24 @@ public:
 
   NS_INLINE_DECL_REFCOUNTING(APZEventState);
 
   void ProcessSingleTap(const CSSPoint& aPoint,
                         const CSSToLayoutDeviceScale& aScale,
                         Modifiers aModifiers,
                         const ScrollableLayerGuid& aGuid,
                         int32_t aClickCount);
+  MOZ_CAN_RUN_SCRIPT
   void ProcessLongTap(const nsCOMPtr<nsIPresShell>& aUtils,
                       const CSSPoint& aPoint,
                       const CSSToLayoutDeviceScale& aScale,
                       Modifiers aModifiers,
                       const ScrollableLayerGuid& aGuid,
                       uint64_t aInputBlockId);
+  MOZ_CAN_RUN_SCRIPT
   void ProcessLongTapUp(const nsCOMPtr<nsIPresShell>& aPresShell,
                         const CSSPoint& aPoint,
                         const CSSToLayoutDeviceScale& aScale,
                         Modifiers aModifiers);
   void ProcessTouchEvent(const WidgetTouchEvent& aEvent,
                          const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId,
                          nsEventStatus aApzResponse,
@@ -77,16 +79,17 @@ public:
                          uint64_t aInputBlockId);
   void ProcessAPZStateChange(ViewID aViewId,
                              APZStateChange aChange,
                              int aArg);
   void ProcessClusterHit();
 private:
   ~APZEventState();
   bool SendPendingTouchPreventedResponse(bool aPreventDefault);
+  MOZ_CAN_RUN_SCRIPT
   bool FireContextmenuEvents(const nsCOMPtr<nsIPresShell>& aPresShell,
                              const CSSPoint& aPoint,
                              const CSSToLayoutDeviceScale& aScale,
                              Modifiers aModifiers,
                              const nsCOMPtr<nsIWidget>& aWidget);
   already_AddRefed<nsIWidget> GetWidget() const;
   already_AddRefed<nsIContent> GetTouchRollup() const;
 private:
--- a/gfx/layers/apz/util/ChromeProcessController.h
+++ b/gfx/layers/apz/util/ChromeProcessController.h
@@ -44,16 +44,17 @@ public:
   ~ChromeProcessController();
   virtual void Destroy() override;
 
   // GeckoContentController interface
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
   virtual void PostDelayedTask(already_AddRefed<Runnable> aTask, int aDelayMs) override;
   virtual bool IsRepaintThread() override;
   virtual void DispatchToRepaintThread(already_AddRefed<Runnable> aTask) override;
+  MOZ_CAN_RUN_SCRIPT
   virtual void HandleTap(TapType aType,
                          const mozilla::LayoutDevicePoint& aPoint,
                          Modifiers aModifiers,
                          const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId) override;
   virtual void NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
                                   const ScrollableLayerGuid& aGuid,
                                   LayoutDeviceCoord aSpanChange,
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -281,20 +281,20 @@ ClientSingleTiledLayerBuffer::PaintThebe
 
   if (dtOnWhite) {
     dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite);
     dtOnWhite = nullptr;
   }
 
   if (asyncPaint) {
     // Create a capture draw target
-    RefPtr<DrawTargetCapture> captureDT =
-      Factory::CreateCaptureDrawTarget(dt->GetBackendType(),
-                                       dt->GetSize(),
-                                       dt->GetFormat());
+    RefPtr<gfx::DrawTargetCapture> captureDT =
+      gfx::Factory::CreateCaptureDrawTarget(dt->GetBackendType(),
+                                            dt->GetSize(),
+                                            dt->GetFormat());
 
     RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(captureDT);
     if (!ctx) {
       gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt);
       return;
     }
     ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
     aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -286,34 +286,11 @@ CompositableParentManager::ReleaseCompos
   }
 
   RefPtr<CompositableHost> host = iter->second;
   mCompositables.erase(iter);
 
   host->Detach(nullptr, CompositableHost::FORCE_DETACH);
 }
 
-bool
-CompositableParentManager::AddReadLocks(ReadLockArray&& aReadLocks)
-{
-  for (ReadLockInit& r : aReadLocks) {
-    if (mReadLocks.find(r.handle().Value()) != mReadLocks.end()) {
-      NS_ERROR("Duplicate read lock handle!");
-      return false;
-    }
-    mReadLocks[r.handle().Value()] = TextureReadLock::Deserialize(r.sharedLock(), this);
-  }
-  return true;
-}
-
-TextureReadLock*
-CompositableParentManager::FindReadLock(const ReadLockHandle& aHandle)
-{
-  auto iter = mReadLocks.find(aHandle.Value());
-  if (iter == mReadLocks.end()) {
-    return nullptr;
-  }
-  return iter->second.get();
-}
-
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/ipc/CompositableTransactionParent.h
+++ b/gfx/layers/ipc/CompositableTransactionParent.h
@@ -19,17 +19,16 @@ namespace layers {
 
 // Since PCompositble has two potential manager protocols, we can't just call
 // the Manager() method usually generated when there's one manager protocol,
 // so both manager protocols implement this and we keep a reference to them
 // through this interface.
 class CompositableParentManager : public HostIPCAllocator
 {
 public:
-  typedef InfallibleTArray<ReadLockInit> ReadLockArray;
 
   CompositableParentManager() {}
 
   void DestroyActor(const OpDestroy& aOp);
 
   void UpdateFwdTransactionId(uint64_t aTransactionId)
   {
     MOZ_ASSERT(mFwdTransactionId < aTransactionId);
@@ -39,47 +38,29 @@ public:
   uint64_t GetFwdTransactionId() { return mFwdTransactionId; }
 
   RefPtr<CompositableHost> AddCompositable(
     const CompositableHandle& aHandle,
     const TextureInfo& aInfo,
     bool aUseWebRender);
   RefPtr<CompositableHost> FindCompositable(const CompositableHandle& aHandle);
 
-  bool AddReadLocks(ReadLockArray&& aReadLocks);
-  TextureReadLock* FindReadLock(const ReadLockHandle& aLockHandle);
-
 protected:
   /**
    * Handle the IPDL messages that affect PCompositable actors.
    */
   bool ReceiveCompositableUpdate(const CompositableOperation& aEdit);
 
   void ReleaseCompositable(const CompositableHandle& aHandle);
 
   uint64_t mFwdTransactionId = 0;
 
   /**
    * Mapping form IDs to CompositableHosts.
    */
   std::map<uint64_t, RefPtr<CompositableHost>> mCompositables;
-  std::map<uint64_t, RefPtr<TextureReadLock>> mReadLocks;
 
 };
 
-struct AutoClearReadLocks {
-  explicit AutoClearReadLocks(std::map<uint64_t, RefPtr<TextureReadLock>>& aReadLocks)
-    : mReadLocks(aReadLocks)
-
-  {}
-
-  ~AutoClearReadLocks()
-  {
-    mReadLocks.clear();
-  }
-
-  std::map<uint64_t, RefPtr<TextureReadLock>>& mReadLocks;
-};
-
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -54,70 +54,53 @@ namespace layers {
 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;
-typedef nsTArray<ReadLockInit> ReadLockVector;
 
 struct CompositableTransaction
 {
   CompositableTransaction()
-  : mReadLockSequenceNumber(0)
-  , mFinished(true)
+  : mFinished(true)
   {}
   ~CompositableTransaction()
   {
     End();
   }
   bool Finished() const
   {
     return mFinished;
   }
   void Begin()
   {
     MOZ_ASSERT(mFinished);
     mFinished = false;
-    mReadLockSequenceNumber = 0;
-    mReadLocks.AppendElement();
   }
   void End()
   {
     mFinished = true;
     mOperations.clear();
     mDestroyedActors.Clear();
-    mReadLocks.Clear();
   }
   bool IsEmpty() const
   {
     return mOperations.empty() && mDestroyedActors.IsEmpty();
   }
   void AddNoSwapEdit(const CompositableOperation& op)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mOperations.push_back(op);
   }
 
-  ReadLockHandle AddReadLock(const ReadLockDescriptor& aReadLock)
-  {
-    ReadLockHandle handle(++mReadLockSequenceNumber);
-    if (mReadLocks.LastElement().Length() >= CompositableForwarder::GetMaxFileDescriptorsPerMessage()) {
-      mReadLocks.AppendElement();
-    }
-    mReadLocks.LastElement().AppendElement(ReadLockInit(aReadLock, handle));
-    return handle;
-  }
-
   OpVector mOperations;
   OpDestroyVector mDestroyedActors;
-  nsTArray<ReadLockVector> mReadLocks;
-  uint64_t mReadLockSequenceNumber;
 
   bool mFinished;
 };
 
 struct AutoEndTransaction {
   explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
   ~AutoEndTransaction() { mTxn->End(); }
   CompositableTransaction* mTxn;
@@ -502,25 +485,16 @@ ImageBridgeChild::EndTransaction()
   if (!mTxn->mOperations.empty()) {
     cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
   }
 
   if (!IsSameProcess()) {
     ShadowLayerForwarder::PlatformSyncBeforeUpdate();
   }
 
-  for (ReadLockVector& locks : mTxn->mReadLocks) {
-    if (locks.Length()) {
-      if (!SendInitReadLocks(locks)) {
-        NS_WARNING("[LayersForwarder] WARNING: sending read locks failed!");
-        return;
-      }
-    }
-  }
-
   if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
     NS_WARNING("could not send async texture transaction");
     return;
   }
 }
 
 void
 ImageBridgeChild::SendImageBridgeThreadId()
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -197,33 +197,23 @@ public:
     }
   }
 private:
   ImageBridgeParent* mImageBridge;
   InfallibleTArray<OpDestroy>* mToDestroy;
 };
 
 mozilla::ipc::IPCResult
-ImageBridgeParent::RecvInitReadLocks(ReadLockArray&& aReadLocks)
-{
-  if (!AddReadLocks(Move(aReadLocks))) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 ImageBridgeParent::RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
                               const uint64_t& aFwdTransactionId)
 {
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return from RecvUpdate without doing so.
   AutoImageBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
   UpdateFwdTransactionId(aFwdTransactionId);
-  AutoClearReadLocks clearLocks(mReadLocks);
 
   for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) {
     if (!ReceiveCompositableUpdate(aEdits[i])) {
       return IPC_FAIL_NO_REASON(this);
     }
   }
 
   if (!IsSameProcess()) {
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -72,17 +72,16 @@ public:
 
   virtual base::ProcessId GetChildProcessId() override
   {
     return OtherPid();
   }
 
   // PImageBridge
   virtual mozilla::ipc::IPCResult RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
-  virtual mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override;
   virtual mozilla::ipc::IPCResult RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
                                           const uint64_t& aFwdTransactionId) override;
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const ReadLockDescriptor& aReadLock,
                                               const LayersBackend& aLayersBackend,
                                               const TextureFlags& aFlags,
                                               const uint64_t& aSerial,
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -152,36 +152,26 @@ mozilla::ipc::IPCResult
 LayerTransactionParent::RecvPaintTime(const uint64_t& aTransactionId,
                                       const TimeDuration& aPaintTime)
 {
   mCompositorBridge->UpdatePaintTime(this, aPaintTime);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-LayerTransactionParent::RecvInitReadLocks(ReadLockArray&& aReadLocks)
-{
-  if (!AddReadLocks(Move(aReadLocks))) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
 LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
 {
   AUTO_PROFILER_TRACING("Paint", "LayerTransaction");
   AUTO_PROFILER_LABEL("LayerTransactionParent::RecvUpdate", GRAPHICS);
 
   TimeStamp updateStart = TimeStamp::Now();
 
   MOZ_LAYERS_LOG(("[ParentSide] received txn with %zu edits", aInfo.cset().Length()));
 
   UpdateFwdTransactionId(aInfo.fwdTransactionId());
-  AutoClearReadLocks clearLocks(mReadLocks);
 
   if (mDestroyed || !mLayerManager || mLayerManager->IsDestroyed()) {
     for (const auto& op : aInfo.toDestroy()) {
       DestroyActor(op);
     }
     return IPC_OK();
   }
 
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -38,17 +38,16 @@ class CompositorBridgeParentBase;
 class LayerTransactionParent final : public PLayerTransactionParent,
                                      public CompositableParentManager,
                                      public ShmemAllocator
 {
   typedef mozilla::layout::RenderFrameParent RenderFrameParent;
   typedef InfallibleTArray<Edit> EditArray;
   typedef InfallibleTArray<OpDestroy> OpDestroyArray;
   typedef InfallibleTArray<PluginWindowData> PluginsArray;
-  typedef InfallibleTArray<ReadLockInit> ReadLockArray;
 
 public:
   LayerTransactionParent(HostLayerManager* aManager,
                          CompositorBridgeParentBase* aBridge,
                          CompositorAnimationStorage* aAnimStorage,
                          uint64_t aId);
 
 protected:
@@ -104,17 +103,16 @@ public:
 
 protected:
   mozilla::ipc::IPCResult RecvShutdown() override;
   mozilla::ipc::IPCResult RecvShutdownSync() override;
 
   mozilla::ipc::IPCResult RecvPaintTime(const uint64_t& aTransactionId,
                                         const TimeDuration& aPaintTime) override;
 
-  mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override;
   mozilla::ipc::IPCResult RecvUpdate(const TransactionInfo& aInfo) override;
 
   mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
   mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
                                               const TextureInfo& aInfo) override;
   mozilla::ipc::IPCResult RecvReleaseLayer(const LayerHandle& aHandle) override;
   mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override;
 
--- a/gfx/layers/ipc/LayersMessageUtils.h
+++ b/gfx/layers/ipc/LayersMessageUtils.h
@@ -108,29 +108,16 @@ struct ParamTraits<mozilla::layers::Comp
   static void Write(Message* msg, const paramType& param) {
     WriteParam(msg, param.mHandle);
   }
   static bool Read(const Message* msg, PickleIterator* iter, paramType* result) {
     return ReadParam(msg, iter, &result->mHandle);
   }
 };
 
-template<>
-struct ParamTraits<mozilla::layers::ReadLockHandle>
-{
-  typedef mozilla::layers::ReadLockHandle paramType;
-
-  static void Write(Message* msg, const paramType& param) {
-    WriteParam(msg, param.mHandle);
-  }
-  static bool Read(const Message* msg, PickleIterator* iter, paramType* result) {
-    return ReadParam(msg, iter, &result->mHandle);
-  }
-};
-
 // Helper class for reading bitfields.
 // If T has bitfields members, derive ParamTraits<T> from BitfieldHelper<T>.
 template <typename ParamType>
 struct BitfieldHelper
 {
   // We need this helper because we can't get the address of a bitfield to
   // pass directly to ReadParam. So instead we read it into a temporary bool
   // and set the bitfield using a setter function
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -46,17 +46,16 @@ using mozilla::layers::FrameMetrics::Vie
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::MaybeLayerClip from "FrameMetrics.h";
 using mozilla::gfx::Glyph from "Layers.h";
 using mozilla::layers::BorderColors from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderCorners from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::BorderWidths from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::LayerHandle from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
-using mozilla::layers::ReadLockHandle from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::SimpleLayerAttributes from "mozilla/layers/LayerAttributes.h";
 using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace layers {
 
 struct TargetConfig {
@@ -374,21 +373,16 @@ struct CrossProcessSemaphoreDescriptor {
 
 union ReadLockDescriptor {
   ShmemSection;
   CrossProcessSemaphoreDescriptor;
   uintptr_t;
   null_t;
 };
 
-struct ReadLockInit {
-  ReadLockDescriptor sharedLock;
-  ReadLockHandle handle;
-};
-
 union MaybeTexture {
   PTexture;
   null_t;
 };
 
 struct TexturedTileDescriptor {
   PTexture texture;
   MaybeTexture textureOnWhite;
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -36,21 +36,16 @@ sync protocol PImageBridge
 child:
   async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
   async DidComposite(ImageCompositeNotification[] aNotifications);
 
 parent:
   async ImageBridgeThreadId(PlatformThreadId aTreahdId);
 
-  // Creates a set of mappings between TextureReadLocks and an associated
-  // ReadLockHandle that can be used in Update, and persist until the
-  // next Update call.
-  async InitReadLocks(ReadLockInit[] locks);
-
   async Update(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId);
 
   // First step of the destruction sequence. This puts ImageBridge
   // in a state in which it can't send asynchronous messages
   // so as to not race with the channel getting closed.
   // In the child side, the Closing the channel does not happen right after WillClose,
   // it is scheduled in the ImageBridgeChild's message queue in order to ensure
   // that all of the messages from the parent side have been received and processed
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -42,21 +42,16 @@ namespace layers {
  * tab, in which case the PLayerTransactionChild exists in the content process.
  * In either case, the PLayerTransactionParent exists in the GPU process (if
  * there is one) or the UI process otherwise.
  */
 sync protocol PLayerTransaction {
   manager PCompositorBridge;
 
 parent:
-  // Creates a set of mappings between TextureReadLocks and an associated
-  // ReadLockHandle that can be used in Update, and persist until the
-  // next Update call.
-  async InitReadLocks(ReadLockInit[] locks);
-
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
   async Update(TransactionInfo txn);
 
   async PaintTime(uint64_t id, TimeDuration paintTime);
 
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
 
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -37,21 +37,16 @@ namespace layers {
 sync protocol PWebRenderBridge
 {
   manager PCompositorBridge;
 
 parent:
   async NewCompositable(CompositableHandle handle, TextureInfo info);
   async ReleaseCompositable(CompositableHandle compositable);
 
-  // Creates a set of mappings between TextureReadLocks and an associated
-  // ReadLockHandle that can be used in Update, and persist until the
-  // next Update call.
-  async InitReadLocks(ReadLockInit[] locks);
-
   sync Create(IntSize aSize);
   async DeleteCompositorAnimations(uint64_t[] aIds);
   async SetDisplayList(IntSize aSize, WebRenderParentCommand[] commands, OpDestroy[] toDestroy, uint64_t fwdTransactionId, uint64_t transactionId,
                        LayoutSize aContentSize, ByteBuf aDL, BuiltDisplayListDescriptor aDLDesc,
                        WebRenderScrollData aScrollData,
                        OpUpdateResource[] aResourceUpdates, RefCountedShmem[] aSmallShmems, Shmem[] aLargeShmems,
                        IdNamespace aIdNamespace, TimeStamp txnStartTime, TimeStamp fwdTime);
   async EmptyTransaction(FocusTarget focusTarget,
--- a/gfx/layers/ipc/RefCountedShmem.cpp
+++ b/gfx/layers/ipc/RefCountedShmem.cpp
@@ -80,29 +80,29 @@ RefCountedShm::Release(const RefCountedS
   if (counter) {
       return --(*counter);
   }
 
   return 0;
 }
 
 bool
-RefCountedShm::Alloc(IProtocol* aAllocator, size_t aSize,
+RefCountedShm::Alloc(mozilla::ipc::IProtocol* aAllocator, size_t aSize,
                        RefCountedShmem& aShm)
 {
   MOZ_ASSERT(!IsValid(aShm));
   auto shmType = ipc::SharedMemory::SharedMemoryType::TYPE_BASIC;
   auto size = aSize + SHM_REFCOUNT_HEADER_SIZE;
   if (!aAllocator->AllocUnsafeShmem(size, shmType, &aShm.buffer())) {
     return false;
   }
   return true;
 }
 
 void
-RefCountedShm::Dealloc(IProtocol* aAllocator, RefCountedShmem& aShm)
+RefCountedShm::Dealloc(mozilla::ipc::IProtocol* aAllocator, RefCountedShmem& aShm)
 {
   aAllocator->DeallocShmem(aShm.buffer());
   aShm.buffer() = ipc::Shmem();
 }
 
 } //namespace
 } //namespace
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -51,24 +51,22 @@ using namespace mozilla::gl;
 using namespace mozilla::ipc;
 
 class ClientTiledLayerBuffer;
 
 typedef nsTArray<SurfaceDescriptor> BufferArray;
 typedef nsTArray<Edit> EditVector;
 typedef nsTHashtable<nsPtrHashKey<ShadowableLayer>> ShadowableLayerSet;
 typedef nsTArray<OpDestroy> OpDestroyVector;
-typedef nsTArray<ReadLockInit> ReadLockVector;
 
 class Transaction
 {
 public:
   Transaction()
-    : mReadLockSequenceNumber(0)
-    , mTargetRotation(ROTATION_0)
+    : mTargetRotation(ROTATION_0)
     , mOpen(false)
     , mRotationChanged(false)
   {}
 
   void Begin(const gfx::IntRect& aTargetBounds, ScreenRotation aRotation,
              dom::ScreenOrientationInternal aOrientation)
   {
     mOpen = true;
@@ -77,18 +75,16 @@ public:
       // the first time this is called, mRotationChanged will be false if
       // aRotation is 0, but we should be OK because for the first transaction
       // we should only compose if it is non-empty. See the caller(s) of
       // RotationChanged.
       mRotationChanged = true;
     }
     mTargetRotation = aRotation;
     mTargetOrientation = aOrientation;
-    mReadLockSequenceNumber = 0;
-    mReadLocks.AppendElement();
   }
   void AddEdit(const Edit& aEdit)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mCset.AppendElement(aEdit);
   }
   void AddEdit(const CompositableOperation& aEdit)
   {
@@ -105,33 +101,23 @@ public:
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mMutants.PutEntry(aLayer);
   }
   void AddSimpleMutant(ShadowableLayer* aLayer)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mSimpleMutants.PutEntry(aLayer);
   }
-  ReadLockHandle AddReadLock(const ReadLockDescriptor& aReadLock)
-  {
-    ReadLockHandle handle(++mReadLockSequenceNumber);
-    if (mReadLocks.LastElement().Length() >= CompositableForwarder::GetMaxFileDescriptorsPerMessage()) {
-      mReadLocks.AppendElement();
-    }
-    mReadLocks.LastElement().AppendElement(ReadLockInit(aReadLock, handle));
-    return handle;
-  }
   void End()
   {
     mCset.Clear();
     mPaints.Clear();
     mMutants.Clear();
     mSimpleMutants.Clear();
     mDestroyedActors.Clear();
-    mReadLocks.Clear();
     mOpen = false;
     mRotationChanged = false;
   }
 
   bool Empty() const {
     return mCset.IsEmpty() &&
            mPaints.IsEmpty() &&
            mMutants.IsEmpty() &&
@@ -145,18 +131,16 @@ public:
 
   bool Opened() const { return mOpen; }
 
   EditVector mCset;
   nsTArray<CompositableOperation> mPaints;
   OpDestroyVector mDestroyedActors;
   ShadowableLayerSet mMutants;
   ShadowableLayerSet mSimpleMutants;
-  nsTArray<ReadLockVector> mReadLocks;
-  uint64_t mReadLockSequenceNumber;
   gfx::IntRect mTargetBounds;
   ScreenRotation mTargetRotation;
   dom::ScreenOrientationInternal mTargetOrientation;
 
 private:
   bool mOpen;
   bool mRotationChanged;
 
@@ -777,25 +761,16 @@ ShadowLayerForwarder::EndTransaction(con
     PlatformSyncBeforeUpdate();
   }
 
   if (startTime) {
     mPaintTiming.serializeMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
     startTime = Some(TimeStamp::Now());
   }
 
-  for (ReadLockVector& locks : mTxn->mReadLocks) {
-    if (locks.Length()) {
-      if (!mShadowManager->SendInitReadLocks(locks)) {
-        MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending read locks failed!"));
-        return false;
-      }
-    }
-  }
-
   // We delay at the last possible minute, to give the paint thread a chance to
   // finish. If it does we don't have to delay messages at all.
   GetCompositorBridgeChild()->PostponeMessagesIfAsyncPainting();
 
   MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
   RenderTraceScope rendertrace3("Forward Transaction", "000093");
   if (!mShadowManager->SendUpdate(info)) {
     MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -18,18 +18,17 @@
 #include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
 WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
-  : mReadLockSequenceNumber(0)
-  , mIsInTransaction(false)
+  : mIsInTransaction(false)
   , mIsInClearCachedResources(false)
   , mIdNamespace{0}
   , mResourceId(0)
   , mPipelineId(aPipelineId)
   , mManager(nullptr)
   , mIPCOpen(false)
   , mDestroyed(false)
   , mFontKeysDeleted(0)
@@ -97,33 +96,16 @@ WebRenderBridgeChild::AddWebRenderParent
 
 void
 WebRenderBridgeChild::BeginTransaction()
 {
   MOZ_ASSERT(!mDestroyed);
 
   UpdateFwdTransactionId();
   mIsInTransaction = true;
-  mReadLockSequenceNumber = 0;
-  mReadLocks.AppendElement();
-}
-
-void
-WebRenderBridgeChild::ClearReadLocks()
-{
-  for (nsTArray<ReadLockInit>& locks : mReadLocks) {
-    if (locks.Length()) {
-      if (!SendInitReadLocks(locks)) {
-        NS_WARNING("WARNING: sending read locks failed!");
-        return;
-      }
-    }
-  }
-
-  mReadLocks.Clear();
 }
 
 void
 WebRenderBridgeChild::UpdateResources(wr::IpcResourceUpdateQueue& aResources)
 {
   if (!IPCOpen()) {
     aResources.Clear();
     return;
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -136,17 +136,16 @@ public:
                   const wr::LayerRect& aBounds, const wr::LayerRect& aClip,
                   bool aBackfaceVisible,
                   const wr::GlyphOptions* aGlyphOptions = nullptr);
 
   wr::FontInstanceKey GetFontKeyForScaledFont(gfx::ScaledFont* aScaledFont);
   wr::FontKey GetFontKeyForUnscaledFont(gfx::UnscaledFont* aUnscaledFont);
 
   void RemoveExpiredFontKeys();
-  void ClearReadLocks();
 
   void BeginClearCachedResources();
   void EndClearCachedResources();
 
   void SetWebRenderLayerManager(WebRenderLayerManager* aManager);
 
   ipc::IShmemAllocator* GetShmemAllocator();
 
@@ -213,18 +212,16 @@ private:
     Release();
   }
 
   bool AddOpDestroy(const OpDestroy& aOp);
 
   nsTArray<WebRenderParentCommand> mParentCommands;
   nsTArray<OpDestroy> mDestroyedActors;
   nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
-  nsTArray<nsTArray<ReadLockInit>> mReadLocks;
-  uint64_t mReadLockSequenceNumber;
   bool mIsInTransaction;
   bool mIsInClearCachedResources;
   wr::IdNamespace mIdNamespace;
   uint32_t mResourceId;
   wr::PipelineId mPipelineId;
   WebRenderLayerManager* mManager;
 
   bool mIPCOpen;
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -577,17 +577,16 @@ WebRenderBridgeParent::RecvSetDisplayLis
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
     return IPC_OK();
   }
 
   AUTO_PROFILER_TRACING("Paint", "SetDisplayList");
   UpdateFwdTransactionId(aFwdTransactionId);
-  AutoClearReadLocks clearLocks(mReadLocks);
 
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return from RecvDPEnd without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
   uint32_t wrEpoch = GetNextWrEpoch();
 
   mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
@@ -657,17 +656,16 @@ WebRenderBridgeParent::RecvEmptyTransact
     for (const auto& op : aToDestroy) {
       DestroyActor(op);
     }
     return IPC_OK();
   }
 
   AUTO_PROFILER_TRACING("Paint", "EmptyTransaction");
   UpdateFwdTransactionId(aFwdTransactionId);
-  AutoClearReadLocks clearLocks(mReadLocks);
 
   // This ensures that destroy operations are always processed. It is not safe
   // to early-return without doing so.
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
   if (!aCommands.IsEmpty()) {
     mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
     ProcessWebRenderParentCommands(aCommands);
@@ -1480,28 +1478,16 @@ WebRenderBridgeParent::RecvReleaseCompos
 {
   if (mDestroyed) {
     return IPC_OK();
   }
   ReleaseCompositable(aHandle);
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult
-WebRenderBridgeParent::RecvInitReadLocks(ReadLockArray&& aReadLocks)
-{
-  if (mDestroyed) {
-    return IPC_OK();
-  }
-  if (!AddReadLocks(Move(aReadLocks))) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
 TextureFactoryIdentifier
 WebRenderBridgeParent::GetTextureFactoryIdentifier()
 {
   MOZ_ASSERT(mApi);
 
   return TextureFactoryIdentifier(LayersBackend::LAYERS_WR,
                                   XRE_GetProcessType(),
                                   mApi->GetMaxTextureSize(),
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -62,18 +62,16 @@ public:
   wr::Epoch WrEpoch() { return wr::NewEpoch(mWrEpoch); }
   AsyncImagePipelineManager* AsyncImageManager() { return mAsyncImageManager; }
   CompositorVsyncScheduler* CompositorScheduler() { return mCompositorScheduler.get(); }
 
   mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
                                               const TextureInfo& aInfo) override;
   mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override;
 
-  mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override;
-
   mozilla::ipc::IPCResult RecvCreate(const gfx::IntSize& aSize) override;
   mozilla::ipc::IPCResult RecvShutdown() override;
   mozilla::ipc::IPCResult RecvShutdownSync() override;
   mozilla::ipc::IPCResult RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds) override;
   mozilla::ipc::IPCResult RecvUpdateResources(nsTArray<OpUpdateResource>&& aUpdates,
                                               nsTArray<RefCountedShmem>&& aSmallShmems,
                                               nsTArray<ipc::Shmem>&& aLargeShmems) override;
   mozilla::ipc::IPCResult RecvSetDisplayList(const gfx::IntSize& aSize,
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -206,18 +206,16 @@ WebRenderLayerManager::EndEmptyTransacti
     return true;
   }
 
   LayoutDeviceIntSize size = mWidget->GetClientSize();
   WrBridge()->BeginTransaction();
 
   mWebRenderCommandBuilder.EmptyTransaction();
 
-  WrBridge()->ClearReadLocks();
-
   mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
   TimeStamp transactionStart = mTransactionIdAllocator->GetTransactionStart();
 
   // Skip the synchronization for buffer since we also skip the painting during
   // device-reset status.
   if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
     if (WrBridge()->GetSyncObject() &&
         WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
@@ -278,18 +276,16 @@ WebRenderLayerManager::EndTransactionWit
                                                   aDisplayListBuilder,
                                                   mScrollData,
                                                   contentSize,
                                                   aFilters);
 
   mWidget->AddWindowOverlayWebRenderCommands(WrBridge(), builder, resourceUpdates);
   mWindowOverlayChanged = false;
 
-  WrBridge()->ClearReadLocks();
-
   if (AsyncPanZoomEnabled()) {
     mScrollData.SetFocusTarget(mFocusTarget);
     mFocusTarget = FocusTarget();
 
     if (mIsFirstPaint) {
       mScrollData.SetIsFirstPaint();
       mIsFirstPaint = false;
     }
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -510,24 +510,17 @@ gfxPlatform::gfxPlatform()
     mWordCacheCharLimit = UNINITIALIZED_VALUE;
     mWordCacheMaxEntries = UNINITIALIZED_VALUE;
     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
     mOpenTypeSVGEnabled = UNINITIALIZED_VALUE;
     mBidiNumeralOption = UNINITIALIZED_VALUE;
 
     mSkiaGlue = nullptr;
 
-    uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
-    uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
-#ifdef USE_SKIA
-    canvasMask |= BackendTypeBit(BackendType::SKIA);
-    contentMask |= BackendTypeBit(BackendType::SKIA);
-#endif
-    InitBackendPrefs(canvasMask, BackendType::CAIRO,
-                     contentMask, BackendType::CAIRO);
+    InitBackendPrefs(GetBackendPrefs());
 
     mTotalSystemMemory = PR_GetPhysicalMemorySize();
 
     VRManager::ManagerInit();
 }
 
 gfxPlatform*
 gfxPlatform::GetPlatform()
@@ -1793,46 +1786,62 @@ gfxPlatform::GetLayerDiagnosticTypes()
     type |= mozilla::layers::DiagnosticTypes::BIGIMAGE_BORDERS;
   }
   if (gfxPrefs::FlashLayerBorders()) {
     type |= mozilla::layers::DiagnosticTypes::FLASH_BORDERS;
   }
   return type;
 }
 
-void
-gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, BackendType aCanvasDefault,
-                              uint32_t aContentBitmask, BackendType aContentDefault)
+BackendPrefsData
+gfxPlatform::GetBackendPrefs()
 {
-    mPreferredCanvasBackend = GetCanvasBackendPref(aCanvasBitmask);
+  BackendPrefsData data;
+
+  data.mCanvasBitmask = BackendTypeBit(BackendType::CAIRO);
+  data.mContentBitmask = BackendTypeBit(BackendType::CAIRO);
+#ifdef USE_SKIA
+  data.mCanvasBitmask |= BackendTypeBit(BackendType::SKIA);
+  data.mContentBitmask |= BackendTypeBit(BackendType::SKIA);
+#endif
+  data.mCanvasDefault = BackendType::CAIRO;
+  data.mContentDefault = BackendType::CAIRO;
+
+  return mozilla::Move(data);
+}
+
+void
+gfxPlatform::InitBackendPrefs(BackendPrefsData&& aPrefsData)
+{
+    mPreferredCanvasBackend = GetCanvasBackendPref(aPrefsData.mCanvasBitmask);
     if (mPreferredCanvasBackend == BackendType::NONE) {
-        mPreferredCanvasBackend = aCanvasDefault;
+        mPreferredCanvasBackend = aPrefsData.mCanvasDefault;
     }
 
     if (mPreferredCanvasBackend == BackendType::DIRECT2D1_1) {
       // Falling back to D2D 1.0 won't help us here. When D2D 1.1 DT creation
       // fails it means the surface was too big or there's something wrong with
       // the device. D2D 1.0 will encounter a similar situation.
       mFallbackCanvasBackend =
-          GetCanvasBackendPref(aCanvasBitmask &
+          GetCanvasBackendPref(aPrefsData.mCanvasBitmask &
                                ~(BackendTypeBit(mPreferredCanvasBackend) | BackendTypeBit(BackendType::DIRECT2D)));
     } else {
       mFallbackCanvasBackend =
-          GetCanvasBackendPref(aCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
+          GetCanvasBackendPref(aPrefsData.mCanvasBitmask & ~BackendTypeBit(mPreferredCanvasBackend));
     }
 
 
-    mContentBackendBitmask = aContentBitmask;
+    mContentBackendBitmask = aPrefsData.mContentBitmask;
     mContentBackend = GetContentBackendPref(mContentBackendBitmask);
     if (mContentBackend == BackendType::NONE) {
-        mContentBackend = aContentDefault;
+        mContentBackend = aPrefsData.mContentDefault;
         // mContentBackendBitmask is our canonical reference for supported
         // backends so we need to add the default if we are using it and
         // overriding the prefs.
-        mContentBackendBitmask |= BackendTypeBit(aContentDefault);
+        mContentBackendBitmask |= BackendTypeBit(aPrefsData.mContentDefault);
     }
 
     uint32_t swBackendBits = BackendTypeBit(BackendType::SKIA) |
                              BackendTypeBit(BackendType::CAIRO);
     mSoftwareBackend = GetContentBackendPref(swBackendBits);
 
     if (XRE_IsParentProcess()) {
         gfxVars::SetContentBackend(mContentBackend);
@@ -2751,20 +2760,28 @@ gfxPlatform::GetDefaultFrameRate()
 void
 gfxPlatform::GetAzureBackendInfo(mozilla::widget::InfoObject& aObj)
 {
   if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
     aObj.DefineProperty("AzureCanvasBackend (UI Process)", GetBackendName(mPreferredCanvasBackend));
     aObj.DefineProperty("AzureFallbackCanvasBackend (UI Process)", GetBackendName(mFallbackCanvasBackend));
     aObj.DefineProperty("AzureContentBackend (UI Process)", GetBackendName(mContentBackend));
 
-    if (gfxConfig::IsEnabled(gfx::Feature::DIRECT2D)) {
-      aObj.DefineProperty("AzureCanvasBackend", "Direct2D 1.1");
-      aObj.DefineProperty("AzureContentBackend", "Direct2D 1.1");
+    // Assume content process' backend prefs.
+    BackendPrefsData data = GetBackendPrefs();
+    BackendType canvasBackend = GetCanvasBackendPref(data.mCanvasBitmask);
+    if (canvasBackend == BackendType::NONE) {
+      canvasBackend = data.mCanvasDefault;
     }
+    BackendType contentBackend = GetContentBackendPref(data.mContentBitmask);
+    if (contentBackend == BackendType::NONE) {
+      contentBackend = data.mContentDefault;
+    }
+    aObj.DefineProperty("AzureCanvasBackend", GetBackendName(canvasBackend));
+    aObj.DefineProperty("AzureContentBackend", GetBackendName(contentBackend));
   } else {
     aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend));
     aObj.DefineProperty("AzureFallbackCanvasBackend", GetBackendName(mFallbackCanvasBackend));
     aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend));
   }
 
   aObj.DefineProperty("AzureCanvasAccelerated", AllowOpenGLCanvas());
 }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -141,16 +141,24 @@ enum class DeviceResetReason
 };
 
 enum class ForcedDeviceResetReason
 {
   OPENSHAREDHANDLE = 0,
   COMPOSITOR_UPDATED,
 };
 
+struct BackendPrefsData
+{
+  uint32_t mCanvasBitmask = 0;
+  mozilla::gfx::BackendType mCanvasDefault = mozilla::gfx::BackendType::NONE;
+  uint32_t mContentBitmask = 0;
+  mozilla::gfx::BackendType mContentDefault = mozilla::gfx::BackendType::NONE;
+};
+
 class gfxPlatform {
     friend class SRGBOverrideObserver;
 
 public:
     typedef mozilla::gfx::Color Color;
     typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::gfx::IntSize IntSize;
@@ -735,24 +743,26 @@ protected:
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource();
 
     // Returns whether or not layers should be accelerated by default on this platform.
     virtual bool AccelerateLayersByDefault();
 
     // Returns a prioritized list of available compositor backends for acceleration.
     virtual void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends);
 
+    // Returns preferences of canvas and content backends.
+    virtual BackendPrefsData GetBackendPrefs();
+
     /**
      * Initialise the preferred and fallback canvas backends
      * aBackendBitmask specifies the backends which are acceptable to the caller.
      * The backend used is determined by aBackendBitmask and the order specified
      * by the gfx.canvas.azure.backends pref.
      */
-    void InitBackendPrefs(uint32_t aCanvasBitmask, mozilla::gfx::BackendType aCanvasDefault,
-                          uint32_t aContentBitmask, mozilla::gfx::BackendType aContentDefault);
+    void InitBackendPrefs(BackendPrefsData&& aPrefsData);
 
     /**
      * Content-process only. Requests device preferences from the parent process
      * and updates any cached settings.
      */
     void FetchAndImportContentDeviceData();
     virtual void ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData);
 
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -80,24 +80,17 @@ gfxPlatformGtk::gfxPlatformGtk()
       if (GDK_IS_X11_DISPLAY(gdk_display_get_default()) &&
           mozilla::Preferences::GetBool("gfx.xrender.enabled"))
       {
           gfxVars::SetUseXRender(true);
       }
     }
 #endif
 
-    uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
-    uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
-#ifdef USE_SKIA
-    canvasMask |= BackendTypeBit(BackendType::SKIA);
-    contentMask |= BackendTypeBit(BackendType::SKIA);
-#endif
-    InitBackendPrefs(canvasMask, BackendType::CAIRO,
-                     contentMask, BackendType::CAIRO);
+    InitBackendPrefs(GetBackendPrefs());
 
 #ifdef MOZ_X11
     if (gfxPlatform::IsHeadless() && GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
       mCompositorDisplay = XOpenDisplay(nullptr);
       MOZ_ASSERT(mCompositorDisplay, "Failed to create compositor display!");
     } else {
       mCompositorDisplay = nullptr;
     }
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -73,20 +73,17 @@ DisableFontActivation()
     }
 }
 
 gfxPlatformMac::gfxPlatformMac()
 {
     DisableFontActivation();
     mFontAntiAliasingThreshold = ReadAntiAliasingThreshold();
 
-    uint32_t canvasMask = BackendTypeBit(BackendType::SKIA);
-    uint32_t contentMask = BackendTypeBit(BackendType::SKIA);
-    InitBackendPrefs(canvasMask, BackendType::SKIA,
-                     contentMask, BackendType::SKIA);
+    InitBackendPrefs(GetBackendPrefs());
 
     // XXX: Bug 1036682 - we run out of fds on Mac when using tiled layers because
     // with 256x256 tiles we can easily hit the soft limit of 800 when using double
     // buffered tiles in e10s, so let's bump the soft limit to the hard limit for the OS
     // up to a new cap of OPEN_MAX.
     struct rlimit limits;
     if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
         limits.rlim_cur = std::min(rlim_t(OPEN_MAX), limits.rlim_max);
@@ -98,16 +95,29 @@ gfxPlatformMac::gfxPlatformMac()
     MacIOSurfaceLib::LoadLibrary();
 }
 
 gfxPlatformMac::~gfxPlatformMac()
 {
     gfxCoreTextShaper::Shutdown();
 }
 
+BackendPrefsData
+gfxPlatformMac::GetBackendPrefs()
+{
+  BackendPrefsData data;
+
+  data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
+  data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
+  data.mCanvasDefault = BackendType::SKIA;
+  data.mContentDefault = BackendType::SKIA;
+
+  return mozilla::Move(data);
+}
+
 bool
 gfxPlatformMac::UsesTiling() const
 {
     // The non-tiling ContentClient requires CrossProcessSemaphore which
     // isn't implemented for OSX.
     return true;
 }
 
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -78,16 +78,18 @@ public:
     virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
 
     // lower threshold on font anti-aliasing
     uint32_t GetAntiAliasingThreshold() { return mFontAntiAliasingThreshold; }
 
 protected:
     bool AccelerateLayersByDefault() override;
 
+    BackendPrefsData GetBackendPrefs() override;
+
 private:
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size) override;
 
     // read in the pref value for the lower threshold on font anti-aliasing
     static uint32_t ReadAntiAliasingThreshold();
 
     uint32_t mFontAntiAliasingThreshold;
 };
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -433,31 +433,53 @@ gfxWindowsPlatform::HandleDeviceReset()
   gfxConfig::Reset(Feature::DIRECT2D);
 
   InitializeConfig();
   InitializeDevices();
   UpdateANGLEConfig();
   return true;
 }
 
+BackendPrefsData
+gfxWindowsPlatform::GetBackendPrefs()
+{
+  BackendPrefsData data;
+
+  data.mCanvasBitmask = BackendTypeBit(BackendType::CAIRO) |
+                        BackendTypeBit(BackendType::SKIA);
+  data.mContentBitmask = BackendTypeBit(BackendType::CAIRO) |
+                         BackendTypeBit(BackendType::SKIA);
+  data.mCanvasDefault = BackendType::SKIA;
+  data.mContentDefault = BackendType::SKIA;
+
+  if (gfxConfig::IsEnabled(Feature::DIRECT2D) && !gfxVars::UseWebRender()) {
+    data.mCanvasBitmask |= BackendTypeBit(BackendType::DIRECT2D1_1);
+    data.mContentBitmask |= BackendTypeBit(BackendType::DIRECT2D1_1);
+    data.mCanvasDefault = BackendType::DIRECT2D1_1;
+    data.mContentDefault = BackendType::DIRECT2D1_1;
+  }
+  return mozilla::Move(data);
+}
+
 void
 gfxWindowsPlatform::UpdateBackendPrefs()
 {
-  uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) |
-                        BackendTypeBit(BackendType::SKIA);
-  uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) |
-                         BackendTypeBit(BackendType::SKIA);
-  BackendType defaultBackend = BackendType::SKIA;
-  if (gfxConfig::IsEnabled(Feature::DIRECT2D) &&
-      Factory::HasD2D1Device() && !gfxVars::UseWebRender()) {
-    contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
-    canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
-    defaultBackend = BackendType::DIRECT2D1_1;
+  BackendPrefsData data = GetBackendPrefs();
+  // Remove DIRECT2D1 preference if D2D1Device does not exist.
+  if (!Factory::HasD2D1Device()) {
+    data.mCanvasBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1);
+    data.mContentBitmask &= ~BackendTypeBit(BackendType::DIRECT2D1_1);
+    if (data.mCanvasDefault == BackendType::DIRECT2D1_1) {
+      data.mCanvasDefault = BackendType::SKIA;
+    }
+    if (data.mContentDefault == BackendType::DIRECT2D1_1) {
+      data.mContentDefault = BackendType::SKIA;
+    }
   }
-  InitBackendPrefs(canvasMask, defaultBackend, contentMask, defaultBackend);
+  InitBackendPrefs(mozilla::Move(data));
 }
 
 bool
 gfxWindowsPlatform::IsDirect2DBackend()
 {
   return GetDefaultContentBackend() == BackendType::DIRECT2D1_1;
 }
 
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -226,16 +226,18 @@ protected:
     }
     void GetAcceleratedCompositorBackends(nsTArray<mozilla::layers::LayersBackend>& aBackends) override;
     virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size) override;
 
     void ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData) override;
     void ImportContentDeviceData(const mozilla::gfx::ContentDeviceData& aData) override;
     void BuildContentDeviceData(mozilla::gfx::ContentDeviceData* aOut) override;
 
+    BackendPrefsData GetBackendPrefs() override;
+
 protected:
     RenderMode mRenderMode;
 
 private:
     void Init();
     void InitAcceleration() override;
     void InitWebRenderConfig() override;
 
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -175,25 +175,25 @@ VRDisplayOpenVR::UpdateStageParameters()
     state.mSittingToStandingTransform[2] = 0.0f;
     state.mSittingToStandingTransform[3] = 0.0f;
 
     state.mSittingToStandingTransform[4] = 0.0f;
     state.mSittingToStandingTransform[5] = 1.0f;
     state.mSittingToStandingTransform[6] = 0.0f;
     state.mSittingToStandingTransform[7] = 0.0f;
 
+    state.mSittingToStandingTransform[8] = 0.0f;
     state.mSittingToStandingTransform[9] = 0.0f;
-    state.mSittingToStandingTransform[10] = 0.0f;
-    state.mSittingToStandingTransform[11] = 1.0f;
-    state.mSittingToStandingTransform[12] = 0.0f;
+    state.mSittingToStandingTransform[10] = 1.0f;
+    state.mSittingToStandingTransform[11] = 0.0f;
 
-    state.mSittingToStandingTransform[13] = 0.0f;
-    state.mSittingToStandingTransform[14] = 0.75f;
-    state.mSittingToStandingTransform[15] = 0.0f;
-    state.mSittingToStandingTransform[16] = 1.0f;
+    state.mSittingToStandingTransform[12] = 0.0f;
+    state.mSittingToStandingTransform[13] = 0.75f;
+    state.mSittingToStandingTransform[14] = 0.0f;
+    state.mSittingToStandingTransform[15] = 1.0f;
   }
 }
 
 void
 VRDisplayOpenVR::ZeroSensor()
 {
   mVRSystem->ResetSeatedZeroPose();
   UpdateStageParameters();
--- a/ipc/ipdl/message-metadata.ini
+++ b/ipc/ipdl/message-metadata.ini
@@ -33,12 +33,10 @@ segment_capacity = 12288
 # Small-size messages.
 #------------------------------------------------------------
 [PCompositorBridge::DidComposite]
 segment_capacity = 128
 [PBrowser::RealMouseMoveEvent]
 segment_capacity = 192
 [PCompositorBridge::PTextureConstructor]
 segment_capacity = 192
-[PLayerTransaction::InitReadLocks]
-segment_capacity = 256
 [PHttpBackgroundChannel::OnStopRequest]
 segment_capacity = 192
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -53,89 +53,39 @@ ForbidUnsafeBrowserCPOWs()
     static bool cached = false;
     if (!cached) {
         cached = true;
         Preferences::AddBoolVarCache(&result, "dom.ipc.cpows.forbid-unsafe-from-browser", false);
     }
     return result;
 }
 
-// Should we allow CPOWs in aAddonId, even though it's marked as multiprocess
-// compatible? This is controlled by two prefs:
-//   If dom.ipc.cpows.forbid-cpows-in-compat-addons is false, then we allow the CPOW.
-//   If dom.ipc.cpows.forbid-cpows-in-compat-addons is true:
-//     We check if aAddonId is listed in dom.ipc.cpows.allow-cpows-in-compat-addons
-//     (which should be a comma-separated string). If it's present there, we allow
-//     the CPOW. Otherwise we forbid the CPOW.
-static bool
-ForbidCPOWsInCompatibleAddon(const nsACString& aAddonId)
-{
-    bool forbid = Preferences::GetBool("dom.ipc.cpows.forbid-cpows-in-compat-addons", false);
-    if (!forbid) {
-        return false;
-    }
-
-    nsAutoCString allow;
-    allow.Assign(',');
-    nsAutoCString pref;
-    Preferences::GetCString("dom.ipc.cpows.allow-cpows-in-compat-addons", pref);
-    allow.Append(pref);
-    allow.Append(',');
-
-    nsCString searchString(",");
-    searchString.Append(aAddonId);
-    searchString.Append(',');
-    return allow.Find(searchString) == kNotFound;
-}
-
 bool
 JavaScriptParent::allowMessage(JSContext* cx)
 {
     // If we're running browser code, then we allow all safe CPOWs and forbid
     // unsafe CPOWs based on a pref (which defaults to forbidden). We also allow
     // CPOWs unconditionally in selected globals (based on
     // Cu.permitCPOWsInScope).
-    //
-    // If we're running add-on code, then we check if the add-on is multiprocess
-    // compatible (which eventually translates to a given setting of allowCPOWs
-    // on the scopw). If it's not compatible, then we allow the CPOW but
-    // warn. If it is marked as compatible, then we check the
-    // ForbidCPOWsInCompatibleAddon; see the comment there.
 
     MessageChannel* channel = GetIPCChannel();
     bool isSafe = channel->IsInTransaction();
 
     bool warn = !isSafe;
     nsIGlobalObject* global = dom::GetIncumbentGlobal();
     JS::Rooted<JSObject*> jsGlobal(cx, global ? global->GetGlobalJSObject() : nullptr);
     if (jsGlobal) {
         JSAutoCompartment ac(cx, jsGlobal);
-        JSAddonId* addonId = JS::AddonIdOfObject(jsGlobal);
 
         if (!xpc::CompartmentPrivate::Get(jsGlobal)->allowCPOWs) {
-            if (!addonId && ForbidUnsafeBrowserCPOWs() && !isSafe) {
+            if (ForbidUnsafeBrowserCPOWs() && !isSafe) {
                 Telemetry::Accumulate(Telemetry::BROWSER_SHIM_USAGE_BLOCKED, 1);
                 JS_ReportErrorASCII(cx, "unsafe CPOW usage forbidden");
                 return false;
             }
-
-            if (addonId) {
-                JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId));
-                nsString addonIdString;
-                AssignJSFlatString(addonIdString, flat);
-                NS_ConvertUTF16toUTF8 addonIdCString(addonIdString);
-                Telemetry::Accumulate(Telemetry::ADDON_FORBIDDEN_CPOW_USAGE, addonIdCString);
-
-                if (ForbidCPOWsInCompatibleAddon(addonIdCString)) {
-                    JS_ReportErrorASCII(cx, "CPOW usage forbidden in this add-on");
-                    return false;
-                }
-
-                warn = true;
-            }
         }
     }
 
     if (!warn)
         return true;
 
     static bool disableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS");
     if (!disableUnsafeCPOWWarnings) {
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -517,17 +517,18 @@ struct RuntimeSizes
     macro(_, MallocHeap, contexts) \
     macro(_, MallocHeap, temporary) \
     macro(_, MallocHeap, interpreterStack) \
     macro(_, MallocHeap, mathCache) \
     macro(_, MallocHeap, sharedImmutableStringsCache) \
     macro(_, MallocHeap, sharedIntlData) \
     macro(_, MallocHeap, uncompressedSourceCache) \
     macro(_, MallocHeap, scriptData) \
-    macro(_, MallocHeap, tracelogger)
+    macro(_, MallocHeap, tracelogger) \
+    macro(_, MallocHeap, wasmRuntime)
 
     RuntimeSizes()
       : FOR_EACH_SIZE(ZERO_SIZE)
         scriptSourceInfo(),
         code(),
         gc(),
         notableScriptSources()
     {
--- a/js/public/TypeDecls.h
+++ b/js/public/TypeDecls.h
@@ -27,17 +27,16 @@ typedef uint8_t jsbytecode;
 class JSAtom;
 struct JSCompartment;
 struct JSContext;
 class JSFunction;
 class JSObject;
 struct JSRuntime;
 class JSScript;
 class JSString;
-class JSAddonId;
 struct JSFreeOp;
 
 struct jsid;
 
 namespace JS {
 
 typedef unsigned char Latin1Char;
 
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -18,17 +18,16 @@
 #include "vm/RegExpStatics.h"
 #include "vm/SelfHosting.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/UnboxedObject-inl.h"
 
 using namespace js;
-using namespace js::unicode;
 
 using mozilla::CheckedInt;
 
 /*
  * ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2
  * steps 3, 16-25.
  */
 bool
--- a/js/src/builtin/String.cpp
+++ b/js/src/builtin/String.cpp
@@ -1137,17 +1137,17 @@ LengthUpperCaseSpecialCasing(Latin1Char 
     MOZ_ASSERT(charCode == unicode::LATIN_SMALL_LETTER_SHARP_S);
 
     return 2;
 }
 
 static inline size_t
 LengthUpperCaseSpecialCasing(char16_t charCode)
 {
-    MOZ_ASSERT(CanUpperCaseSpecialCasing(charCode));
+    MOZ_ASSERT(::CanUpperCaseSpecialCasing(charCode));
 
     return unicode::LengthUpperCaseSpecialCasing(charCode);
 }
 
 static inline void
 AppendUpperCaseSpecialCasing(char16_t charCode, Latin1Char* elements, size_t* index)
 {
     // U+00DF LATIN SMALL LETTER SHARP S is uppercased to two 'S'.
@@ -1186,22 +1186,22 @@ ToUpperCaseImpl(DestChar* destChars, con
                     destChars[j++] = c;
                     destChars[j++] = trail;
                     i++;
                     continue;
                 }
             }
         }
 
-        if (MOZ_UNLIKELY(c > 0x7f && CanUpperCaseSpecialCasing(static_cast<SrcChar>(c)))) {
+        if (MOZ_UNLIKELY(c > 0x7f && ::CanUpperCaseSpecialCasing(static_cast<SrcChar>(c)))) {
             // Return if the output buffer is too small.
             if (srcLength == destLength)
                 return i;
 
-            AppendUpperCaseSpecialCasing(c, destChars, &j);
+            ::AppendUpperCaseSpecialCasing(c, destChars, &j);
             continue;
         }
 
         c = unicode::ToUpperCase(c);
         MOZ_ASSERT_IF((IsSame<DestChar, Latin1Char>::value), c <= JSString::MAX_LATIN1_CHAR);
         destChars[j++] = c;
     }
 
@@ -1221,18 +1221,18 @@ ToUpperCaseImpl(Latin1Char* destChars, c
 template <typename CharT>
 static size_t
 ToUpperCaseLength(const CharT* chars, size_t startIndex, size_t length)
 {
     size_t upperLength = length;
     for (size_t i = startIndex; i < length; i++) {
         char16_t c = chars[i];
 
-        if (c > 0x7f && CanUpperCaseSpecialCasing(static_cast<CharT>(c)))
-            upperLength += LengthUpperCaseSpecialCasing(static_cast<CharT>(c)) - 1;
+        if (c > 0x7f && ::CanUpperCaseSpecialCasing(static_cast<CharT>(c)))
+            upperLength += ::LengthUpperCaseSpecialCasing(static_cast<CharT>(c)) - 1;
     }
     return upperLength;
 }
 
 template <typename DestChar, typename SrcChar>
 static inline void
 CopyChars(DestChar* destChars, const SrcChar* srcChars, size_t length)
 {
@@ -1302,17 +1302,17 @@ ToUpperCase(JSContext* cx, JSLinearStrin
                     char16_t upper = unicode::ToUpperCase(c);
                     MOZ_ASSERT(upper <= JSString::MAX_LATIN1_CHAR);
                     MOZ_ASSERT(StaticStrings::hasUnit(upper));
 
                     return cx->staticStrings().getUnit(upper);
                 }
 
                 MOZ_ASSERT(unicode::ToUpperCase(c) > JSString::MAX_LATIN1_CHAR ||
-                           CanUpperCaseSpecialCasing(c));
+                           ::CanUpperCaseSpecialCasing(c));
             }
         }
 
         // Look for the first character that changes when uppercased.
         size_t i = 0;
         for (; i < length; i++) {
             CharT c = chars[i];
             if (!IsSame<CharT, Latin1Char>::value) {
@@ -1324,17 +1324,17 @@ ToUpperCase(JSContext* cx, JSLinearStrin
 
                         i++;
                         continue;
                     }
                 }
             }
             if (unicode::CanUpperCase(c))
                 break;
-            if (MOZ_UNLIKELY(c > 0x7f && CanUpperCaseSpecialCasing(c)))
+            if (MOZ_UNLIKELY(c > 0x7f && ::CanUpperCaseSpecialCasing(c)))
                 break;
         }
 
         // If no character needs to change, return the input string.
         if (i == length)
             return str;
 
         // The string changes when uppercased, so we must create a new string.
--- a/js/src/gc/GC.cpp
+++ b/js/src/gc/GC.cpp
@@ -7960,19 +7960,16 @@ gc::MergeCompartments(JSCompartment* sou
 void
 GCRuntime::mergeCompartments(JSCompartment* source, JSCompartment* target)
 {
     // The source compartment must be specifically flagged as mergable.  This
     // also implies that the compartment is not visible to the debugger.
     MOZ_ASSERT(source->creationOptions_.mergeable());
     MOZ_ASSERT(source->creationOptions_.invisibleToDebugger());
 
-    MOZ_ASSERT(source->creationOptions().addonIdOrNull() ==
-               target->creationOptions().addonIdOrNull());
-
     MOZ_ASSERT(!source->hasBeenEntered());
     MOZ_ASSERT(source->zone()->compartments().length() == 1);
     MOZ_ASSERT(source->zone()->group()->zones().length() == 1);
 
     JSContext* cx = rt->activeContextFromOwnThread();
 
     MOZ_ASSERT(!source->zone()->wasGCStarted());
     JS::AutoAssertNoGC nogc(cx);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -9840,19 +9840,24 @@ CodeGenerator::visitRest(LRest* lir)
 }
 
 bool
 CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::BytecodeOffset trapOffset,
                             wasm::FuncOffsets* offsets)
 {
     JitSpew(JitSpew_Codegen, "# Emitting wasm code");
 
-    wasm::IsLeaf isLeaf = !gen->needsOverrecursedCheck();
-
-    wasm::GenerateFunctionPrologue(masm, frameSize(), isLeaf, sigId, trapOffset, offsets);
+    wasm::GenerateFunctionPrologue(masm, sigId, mozilla::Nothing(), offsets);
+
+    if (omitOverRecursedCheck())
+        masm.reserveStack(frameSize());
+    else
+        masm.wasmReserveStackChecked(frameSize(), trapOffset);
+
+    MOZ_ASSERT(masm.framePushed() == frameSize());
 
     if (!generateBody())
         return false;
 
     masm.bind(&returnLabel_);
     wasm::GenerateFunctionEpilogue(masm, frameSize(), offsets);
 
 #if defined(JS_ION_PERF)
@@ -12715,16 +12720,24 @@ CodeGenerator::visitInterruptCheck(LInte
     const void* contextAddr = gen->compartment->zone()->addressOfJSContext();
     masm.loadPtr(AbsoluteAddress(contextAddr), temp);
     masm.branch32(Assembler::NotEqual, Address(temp, offsetof(JSContext, interrupt_)),
                   Imm32(0), ool->entry());
     masm.bind(ool->rejoin());
 }
 
 void
+CodeGenerator::visitWasmInterruptCheck(LWasmInterruptCheck* lir)
+{
+    MOZ_ASSERT(gen->compilingWasm());
+
+    masm.wasmInterruptCheck(ToRegister(lir->tlsPtr()), lir->mir()->bytecodeOffset());
+}
+
+void
 CodeGenerator::visitWasmTrap(LWasmTrap* lir)
 {
     MOZ_ASSERT(gen->compilingWasm());
     const MWasmTrap* mir = lir->mir();
 
     masm.wasmTrap(mir->trap(), mir->bytecodeOffset());
 }
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -459,16 +459,17 @@ class CodeGenerator final : public CodeG
 
 #ifdef DEBUG
     void emitAssertResultV(const ValueOperand output, const TemporaryTypeSet* typeset);
     void emitAssertObjectOrStringResult(Register input, MIRType type, const TemporaryTypeSet* typeset);
 #endif
 
     void visitInterruptCheck(LInterruptCheck* lir);
     void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
+    void visitWasmInterruptCheck(LWasmInterruptCheck* lir);
     void visitWasmTrap(LWasmTrap* lir);
     void visitWasmLoadTls(LWasmLoadTls* ins);
     void visitWasmBoundsCheck(LWasmBoundsCheck* ins);
     void visitWasmAlignmentCheck(LWasmAlignmentCheck* ins);
     void visitRecompileCheck(LRecompileCheck* ins);
     void visitRotate(LRotate* ins);
 
     void visitRandom(LRandom* ins);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -42,16 +42,17 @@
 #include "jit/PerfSpewer.h"
 #include "jit/RangeAnalysis.h"
 #include "jit/ScalarReplacement.h"
 #include "jit/Sink.h"
 #include "jit/StupidAllocator.h"
 #include "jit/ValueNumbering.h"
 #include "jit/WasmBCE.h"
 #include "js/Printf.h"
+#include "util/Windows.h"
 #include "vm/Debugger.h"
 #include "vm/HelperThreads.h"
 #include "vm/JSCompartment.h"
 #include "vm/TraceLogging.h"
 #include "vtune/VTuneWrapper.h"
 
 #include "gc/PrivateIterators-inl.h"
 #include "jit/JitFrames-inl.h"
@@ -59,16 +60,20 @@
 #include "jit/shared/Lowering-shared-inl.h"
 #include "vm/Debugger-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 #include "vm/JSCompartment-inl.h"
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/Stack-inl.h"
 
+#if defined(ANDROID)
+# include <sys/system_properties.h>
+#endif
+
 using namespace js;
 using namespace js::jit;
 
 // Assert that JitCode is gc::Cell aligned.
 JS_STATIC_ASSERT(sizeof(JitCode) % gc::CellAlignBytes == 0);
 
 static MOZ_THREAD_LOCAL(JitContext*) TlsJitContext;
 
@@ -387,17 +392,17 @@ void
 JitZoneGroup::patchIonBackedges(JSContext* cx, BackedgeTarget target)
 {
     if (target == BackedgeLoopHeader) {
         // We must be on the active thread. The caller must use
         // AutoPreventBackedgePatching to ensure we don't reenter.
         MOZ_ASSERT(cx->runtime()->jitRuntime()->preventBackedgePatching());
         MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
     } else {
-        // We must be called from InterruptRunningJitCode, or a signal handler
+        // We must be called from jit::InterruptRunningCode, or a signal handler
         // triggered there. rt->handlingJitInterrupt() ensures we can't reenter
         // this code.
         MOZ_ASSERT(!cx->runtime()->jitRuntime()->preventBackedgePatching());
         MOZ_ASSERT(cx->handlingJitInterrupt());
     }
 
     // Do nothing if we know all backedges are already jumping to `target`.
     if (backedgeTarget_ == target)
@@ -3347,8 +3352,174 @@ jit::JitSupportsAtomics()
 #else
     return true;
 #endif
 }
 
 // If you change these, please also change the comment in TempAllocator.
 /* static */ const size_t TempAllocator::BallastSize            = 16 * 1024;
 /* static */ const size_t TempAllocator::PreferredLifoChunkSize = 32 * 1024;
+
+static void
+RedirectIonBackedgesToInterruptCheck(JSContext* cx)
+{
+    // Jitcode may only be modified on the runtime's active thread.
+    if (cx != cx->runtime()->activeContext())
+        return;
+
+    // The faulting thread is suspended so we can access cx fields that can
+    // normally only be accessed by the cx's active thread.
+    AutoNoteSingleThreadedRegion anstr;
+
+    Zone* zone = cx->zoneRaw();
+    if (zone && !zone->isAtomsZone()) {
+        jit::JitRuntime* jitRuntime = cx->runtime()->jitRuntime();
+        if (!jitRuntime)
+            return;
+
+        // If the backedge list is being mutated, the pc must be in C++ code and
+        // thus not in a JIT iloop. We assume that the interrupt flag will be
+        // checked at least once before entering JIT code (if not, no big deal;
+        // the browser will just request another interrupt in a second).
+        if (!jitRuntime->preventBackedgePatching()) {
+            jit::JitZoneGroup* jzg = zone->group()->jitZoneGroup;
+            jzg->patchIonBackedges(cx, jit::JitZoneGroup::BackedgeInterruptCheck);
+        }
+    }
+}
+
+#if !defined(XP_WIN)
+// For the interrupt signal, pick a signal number that:
+//  - is not otherwise used by mozilla or standard libraries
+//  - defaults to nostop and noprint on gdb/lldb so that noone is bothered
+// SIGVTALRM a relative of SIGALRM, so intended for user code, but, unlike
+// SIGALRM, not used anywhere else in Mozilla.
+static const int sJitAsyncInterruptSignal = SIGVTALRM;
+
+static void
+JitAsyncInterruptHandler(int signum, siginfo_t*, void*)
+{
+    MOZ_RELEASE_ASSERT(signum == sJitAsyncInterruptSignal);
+
+    JSContext* cx = TlsContext.get();
+    if (!cx)
+        return;
+
+#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
+    SimulatorProcess::ICacheCheckingDisableCount++;
+#endif
+
+    RedirectIonBackedgesToInterruptCheck(cx);
+
+#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
+    SimulatorProcess::cacheInvalidatedBySignalHandler_ = true;
+    SimulatorProcess::ICacheCheckingDisableCount--;
+#endif
+
+    cx->finishHandlingJitInterrupt();
+}
+#endif
+
+static bool sTriedInstallAsyncInterrupt = false;
+static bool sHaveAsyncInterrupt = false;
+
+void
+jit::EnsureAsyncInterrupt(JSContext* cx)
+{
+    // We assume that there are no races creating the first JSRuntime of the process.
+    if (sTriedInstallAsyncInterrupt)
+        return;
+    sTriedInstallAsyncInterrupt = true;
+
+#if defined(ANDROID) && !defined(__aarch64__)
+    // Before Android 4.4 (SDK version 19), there is a bug
+    //   https://android-review.googlesource.com/#/c/52333
+    // in Bionic's pthread_join which causes pthread_join to return early when
+    // pthread_kill is used (on any thread). Nobody expects the pthread_cond_wait
+    // EINTRquisition.
+    char version_string[PROP_VALUE_MAX];
+    mozilla::PodArrayZero(version_string);
+    if (__system_property_get("ro.build.version.sdk", version_string) > 0) {
+        if (atol(version_string) < 19)
+            return;
+    }
+#endif
+
+#if defined(XP_WIN)
+    // Windows uses SuspendThread to stop the active thread from another thread.
+#else
+    struct sigaction interruptHandler;
+    interruptHandler.sa_flags = SA_SIGINFO;
+    interruptHandler.sa_sigaction = &JitAsyncInterruptHandler;
+    sigemptyset(&interruptHandler.sa_mask);
+    struct sigaction prev;
+    if (sigaction(sJitAsyncInterruptSignal, &interruptHandler, &prev))
+        MOZ_CRASH("unable to install interrupt handler");
+
+    // There shouldn't be any other handlers installed for
+    // sJitAsyncInterruptSignal. If there are, we could always forward, but we
+    // need to understand what we're doing to avoid problematic interference.
+    if ((prev.sa_flags & SA_SIGINFO && prev.sa_sigaction) ||
+        (prev.sa_handler != SIG_DFL && prev.sa_handler != SIG_IGN))
+    {
+        MOZ_CRASH("contention for interrupt signal");
+    }
+#endif // defined(XP_WIN)
+
+    sHaveAsyncInterrupt = true;
+}
+
+bool
+jit::HaveAsyncInterrupt()
+{
+    MOZ_ASSERT(sTriedInstallAsyncInterrupt);
+    return sHaveAsyncInterrupt;
+}
+
+// JSRuntime::requestInterrupt sets interrupt_ (which is checked frequently by
+// C++ code at every Baseline JIT loop backedge) and jitStackLimit_ (which is
+// checked at every Baseline and Ion JIT function prologue). The remaining
+// sources of potential iloops (Ion loop backedges) are handled by this
+// function: Ion loop backedges are patched to instead point to a stub that
+// handles the interrupt;
+void
+jit::InterruptRunningCode(JSContext* cx)
+{
+    // If signal handlers weren't installed, then Ion emit normal interrupt
+    // checks and don't need asynchronous interruption.
+    MOZ_ASSERT(sTriedInstallAsyncInterrupt);
+    if (!sHaveAsyncInterrupt)
+        return;
+
+    // Do nothing if we're already handling an interrupt here, to avoid races
+    // below and in JitRuntime::patchIonBackedges.
+    if (!cx->startHandlingJitInterrupt())
+        return;
+
+    // If we are on context's thread, then we can patch Ion backedges without
+    // any special synchronization.
+    if (cx == TlsContext.get()) {
+        RedirectIonBackedgesToInterruptCheck(cx);
+        cx->finishHandlingJitInterrupt();
+        return;
+    }
+
+    // We are not on the runtime's active thread, so we need to halt the
+    // runtime's active thread first.
+#if defined(XP_WIN)
+    // On Windows, we can simply suspend the active thread. SuspendThread can
+    // sporadically fail if the thread is in the middle of a syscall. Rather
+    // than retrying in a loop, just wait for the next request for interrupt.
+    HANDLE thread = (HANDLE)cx->threadNative();
+    if (SuspendThread(thread) != (DWORD)-1) {
+        RedirectIonBackedgesToInterruptCheck(cx);
+        ResumeThread(thread);
+    }
+    cx->finishHandlingJitInterrupt();
+#else
+    // On Unix, we instead deliver an async signal to the active thread which
+    // halts the thread and callers our JitAsyncInterruptHandler (which has
+    // already been installed by EnsureSignalHandlersInstalled).
+    pthread_t thread = (pthread_t)cx->threadNative();
+    pthread_kill(thread, sJitAsyncInterruptSignal);
+#endif
+}
+
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -731,12 +731,26 @@ class MOZ_STACK_CLASS MaybeAutoWritableJ
             awjc_.emplace(addr, size);
     }
     MaybeAutoWritableJitCode(JitCode* code, ReprotectCode reprotect) {
         if (reprotect)
             awjc_.emplace(code);
     }
 };
 
+// Ensure the given JSRuntime is set up to use async interrupts. Failure to
+// enable signal handlers indicates some catastrophic failure and creation of
+// the runtime must fail.
+void
+EnsureAsyncInterrupt(JSContext* cx);
+
+// Return whether the async interrupt can be used to interrupt Ion code.
+bool
+HaveAsyncInterrupt();
+
+// Force any currently-executing JIT code to call HandleExecutionInterrupt.
+extern void
+InterruptRunningCode(JSContext* cx);
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_JitCompartment_h */
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -182,20 +182,16 @@ DefaultJitOptions::DefaultJitOptions()
 
     // The bytecode length limit for small function.
     SET_DEFAULT(smallFunctionMaxBytecodeLength_, 130);
 
     // An artificial testing limit for the maximum supported offset of
     // pc-relative jump and call instructions.
     SET_DEFAULT(jumpThreshold, UINT32_MAX);
 
-    // Whether the (ARM) simulators should always interrupt before executing any
-    // instruction.
-    SET_DEFAULT(simulatorAlwaysInterrupt, false);
-
     // Branch pruning heuristic is based on a scoring system, which is look at
     // different metrics and provide a score. The score is computed as a
     // projection where each factor defines the weight of each metric. Then this
     // score is compared against a threshold to prevent a branch from being
     // removed.
     SET_DEFAULT(branchPruningHitCountFactor, 1);
     SET_DEFAULT(branchPruningInstFactor, 10);
     SET_DEFAULT(branchPruningBlockSpanFactor, 100);
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -71,17 +71,16 @@ struct DefaultJitOptions
     bool forceInlineCaches;
     bool fullDebugChecks;
     bool limitScriptSize;
     bool osr;
     bool asmJSAtomicsEnable;
     bool wasmFoldOffsets;
     bool wasmDelayTier2;
     bool ionInterruptWithoutSignals;
-    bool simulatorAlwaysInterrupt;
     uint32_t baselineWarmUpThreshold;
     uint32_t exceptionBailoutThreshold;
     uint32_t frequentBailoutThreshold;
     uint32_t maxStackArgs;
     uint32_t osrPcMismatchesBeforeRecompile;
     uint32_t smallFunctionMaxBytecodeLength_;
     uint32_t jumpThreshold;
     uint32_t branchPruningHitCountFactor;
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -10,17 +10,16 @@
 #include "mozilla/EndianUtils.h"
 
 #include <type_traits>
 
 #include "jit/JitSpewer.h"
 #include "jit/LIR.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
-#include "wasm/WasmSignalHandlers.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 #include "vm/BytecodeUtil-inl.h"
 #include "vm/JSObject-inl.h"
 
 using namespace js;
 using namespace jit;
 
@@ -90,18 +89,18 @@ void
 LIRGenerator::visitIsConstructing(MIsConstructing* ins)
 {
     define(new(alloc()) LIsConstructing(), ins);
 }
 
 static void
 TryToUseImplicitInterruptCheck(MIRGraph& graph, MBasicBlock* backedge)
 {
-    // Implicit interrupt checks require wasm signal handlers to be installed.
-    if (!wasm::HaveSignalHandlers() || JitOptions.ionInterruptWithoutSignals)
+    // Implicit interrupt checks require JIT async interrupt support.
+    if (!jit::HaveAsyncInterrupt() || JitOptions.ionInterruptWithoutSignals)
         return;
 
     // To avoid triggering expensive interrupts (backedge patching) in
     // requestMajorGC and requestMinorGC, use an implicit interrupt check only
     // if the loop body can not trigger GC or affect GC state like the store
     // buffer. We do this by checking there are no safepoints attached to LIR
     // instructions inside the loop.
 
@@ -2735,16 +2734,23 @@ void
 LIRGenerator::visitInterruptCheck(MInterruptCheck* ins)
 {
     LInstruction* lir = new(alloc()) LInterruptCheck(temp());
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
+LIRGenerator::visitWasmInterruptCheck(MWasmInterruptCheck* ins)
+{
+    auto* lir = new(alloc()) LWasmInterruptCheck(useRegisterAtStart(ins->tlsPtr()));
+    add(lir, ins);
+}
+
+void
 LIRGenerator::visitWasmTrap(MWasmTrap* ins)
 {
     add(new(alloc()) LWasmTrap, ins);
 }
 
 void
 LIRGenerator::visitWasmReinterpret(MWasmReinterpret* ins)
 {
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -207,16 +207,17 @@ class LIRGenerator final : public LIRGen
     void visitMaybeToDoubleElement(MMaybeToDoubleElement* ins);
     void visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins);
     void visitLoadSlot(MLoadSlot* ins);
     void visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins);
     void visitFunctionEnvironment(MFunctionEnvironment* ins);
     void visitHomeObject(MHomeObject* ins);
     void visitHomeObjectSuperBase(MHomeObjectSuperBase* ins);
     void visitInterruptCheck(MInterruptCheck* ins);
+    void visitWasmInterruptCheck(MWasmInterruptCheck* ins);
     void visitWasmTrap(MWasmTrap* ins);
     void visitWasmReinterpret(MWasmReinterpret* ins);
     void visitStoreSlot(MStoreSlot* ins);
     void visitFilterTypeSet(MFilterTypeSet* ins);
     void visitTypeBarrier(MTypeBarrier* ins);
     void visitPostWriteBarrier(MPostWriteBarrier* ins);
     void visitPostWriteElementBarrier(MPostWriteElementBarrier* ins);
     void visitArrayLength(MArrayLength* ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -8346,16 +8346,43 @@ class MInterruptCheck : public MNullaryI
     INSTRUCTION_HEADER(InterruptCheck)
     TRIVIAL_NEW_WRAPPERS
 
     AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
+// Check whether we need to fire the interrupt handler (in wasm code).
+class MWasmInterruptCheck
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
+{
+    wasm::BytecodeOffset bytecodeOffset_;
+
+    MWasmInterruptCheck(MDefinition* tlsPointer, wasm::BytecodeOffset bytecodeOffset)
+      : MUnaryInstruction(classOpcode, tlsPointer),
+        bytecodeOffset_(bytecodeOffset)
+    {
+        setGuard();
+    }
+
+  public:
+    INSTRUCTION_HEADER(WasmInterruptCheck)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, tlsPtr))
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    wasm::BytecodeOffset bytecodeOffset() const {
+        return bytecodeOffset_;
+    }
+};
+
 // Directly jumps to the indicated trap, leaving Wasm code and reporting a
 // runtime error.
 
 class MWasmTrap
   : public MAryControlInstruction<0, 0>,
     public NoTypePolicy::Data
 {
     wasm::Trap trap_;
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -3371,17 +3371,60 @@ MacroAssembler::maybeBranchTestType(MIRT
             MOZ_CRASH("Unsupported type");
         }
     }
 }
 
 void
 MacroAssembler::wasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset)
 {
-    append(trap, wasm::TrapSite(wasmTrapInstruction().offset(), bytecodeOffset));
+    uint32_t trapOffset = wasmTrapInstruction().offset();
+    MOZ_ASSERT_IF(!oom(), currentOffset() - trapOffset == WasmTrapInstructionLength);
+
+    append(trap, wasm::TrapSite(trapOffset, bytecodeOffset));
+}
+
+void
+MacroAssembler::wasmInterruptCheck(Register tls, wasm::BytecodeOffset bytecodeOffset)
+{
+    Label ok;
+    branch32(Assembler::Equal, Address(tls, offsetof(wasm::TlsData, interrupt)), Imm32(0), &ok);
+    wasmTrap(wasm::Trap::CheckInterrupt, bytecodeOffset);
+    bind(&ok);
+}
+
+void
+MacroAssembler::wasmReserveStackChecked(uint32_t amount, wasm::BytecodeOffset trapOffset)
+{
+    if (!amount)
+        return;
+
+    // If the frame is large, don't bump sp until after the stack limit check so
+    // that the trap handler isn't called with a wild sp.
+
+    if (amount > MAX_UNCHECKED_LEAF_FRAME_SIZE) {
+        Label ok;
+        Register scratch = ABINonArgReg0;
+        moveStackPtrTo(scratch);
+        subPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, stackLimit)), scratch);
+        branchPtr(Assembler::GreaterThan, scratch, Imm32(amount), &ok);
+        wasmTrap(wasm::Trap::StackOverflow, trapOffset);
+        bind(&ok);
+    }
+
+    reserveStack(amount);
+
+    if (amount <= MAX_UNCHECKED_LEAF_FRAME_SIZE) {
+        Label ok;
+        branchStackPtrRhs(Assembler::Below,
+                          Address(WasmTlsReg, offsetof(wasm::TlsData, stackLimit)),
+                          &ok);
+        wasmTrap(wasm::Trap::StackOverflow, trapOffset);
+        bind(&ok);
+    }
 }
 
 void
 MacroAssembler::wasmCallImport(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee)
 {
     // Load the callee, before the caller's registers are clobbered.
     uint32_t globalDataOffset = callee.importGlobalDataOffset();
     loadWasmGlobalPtr(globalDataOffset + offsetof(wasm::FuncImportTls, code), ABINonArgReg0);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1523,16 +1523,18 @@ class MacroAssembler : public MacroAssem
 
   public:
     // ========================================================================
     // wasm support
 
     CodeOffset wasmTrapInstruction() PER_SHARED_ARCH;
 
     void wasmTrap(wasm::Trap trap, wasm::BytecodeOffset bytecodeOffset);
+    void wasmInterruptCheck(Register tls, wasm::BytecodeOffset bytecodeOffset);
+    void wasmReserveStackChecked(uint32_t amount, wasm::BytecodeOffset trapOffset);
 
     // Emit a bounds check against the wasm heap limit, jumping to 'label' if
     // 'cond' holds. Required when WASM_HUGE_MEMORY is not defined. If
     // JitOptions.spectreMaskIndex is true, in speculative executions 'index' is
     // saturated in-place to 'boundsCheckLimit'.
     template <class L>
     inline void wasmBoundsCheck(Condition cond, Register index, Register boundsCheckLimit, L label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86);
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -123,16 +123,17 @@ static constexpr Register ABINonArgReg2 
 // This register may be volatile or nonvolatile. Avoid d15 which is the
 // ScratchDoubleReg.
 static constexpr FloatRegister ABINonArgDoubleReg { FloatRegisters::d8, VFPRegister::Double };
 
 // These registers may be volatile or nonvolatile.
 // Note: these three registers are all guaranteed to be different
 static constexpr Register ABINonArgReturnReg0 = r4;
 static constexpr Register ABINonArgReturnReg1 = r5;
+static constexpr Register ABINonVolatileReg = r6;
 
 // This register is guaranteed to be clobberable during the prologue and
 // epilogue of an ABI call which must preserve both ABI argument, return
 // and non-volatile registers.
 static constexpr Register ABINonArgReturnVolatileReg = lr;
 
 // TLS pointer argument register for WebAssembly functions. This must not alias
 // any other register used for passing function arguments or return values.
@@ -230,16 +231,17 @@ static_assert(CodeAlignment % SimdMemory
   "the constant sections of the code buffer.  Thus it should be larger than the "
   "alignment for SIMD constants.");
 
 static_assert(JitStackAlignment % SimdMemoryAlignment == 0,
   "Stack alignment should be larger than any of the alignments which are used for "
   "spilled values.  Thus it should be larger than the alignment for SIMD accesses.");
 
 static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
+static const uint32_t WasmTrapInstructionLength = 4;
 
 // Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
 static constexpr bool SupportsUint32x4FloatConversions = false;
 
 // Does this architecture support comparisons of unsigned integer vectors?
 static constexpr bool SupportsUint8x16Compares = false;
 static constexpr bool SupportsUint16x8Compares = false;
 static constexpr bool SupportsUint32x4Compares = false;
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -1155,17 +1155,16 @@ Simulator::Simulator(JSContext* cx)
 
     // Note, allocation and anything that depends on allocated memory is
     // deferred until init(), in order to handle OOM properly.
 
     stack_ = nullptr;
     stackLimit_ = 0;
     pc_modified_ = false;
     icount_ = 0L;
-    wasm_interrupt_ = false;
     break_pc_ = nullptr;
     break_instr_ = 0;
     single_stepping_ = false;
     single_step_callback_ = nullptr;
     single_step_callback_arg_ = nullptr;
     skipCalleeSavedRegsCheck = false;
 
     // Set up architecture state.
@@ -1589,39 +1588,16 @@ Simulator::registerState()
     wasm::RegisterState state;
     state.pc = (void*) get_pc();
     state.fp = (void*) get_register(fp);
     state.sp = (void*) get_register(sp);
     state.lr = (void*) get_register(lr);
     return state;
 }
 
-// The signal handler only redirects the PC to the interrupt stub when the PC is
-// in function code. However, this guard is racy for the ARM simulator since the
-// signal handler samples PC in the middle of simulating an instruction and thus
-// the current PC may have advanced once since the signal handler's guard. So we
-// re-check here.
-void
-Simulator::handleWasmInterrupt()
-{
-    if (!wasm::CodeExists)
-        return;
-
-    uint8_t* pc = (uint8_t*)get_pc();
-
-    const wasm::ModuleSegment* ms = nullptr;
-    if (!wasm::InInterruptibleCode(cx_, pc, &ms))
-        return;
-
-    if (!cx_->activation()->asJit()->startWasmInterrupt(registerState()))
-        return;
-
-    set_pc(int32_t(ms->interruptCode()));
-}
-
 static inline JitActivation*
 GetJitActivation(JSContext* cx)
 {
     if (!wasm::CodeExists)
         return nullptr;
     if (!cx->activation() || !cx->activation()->isJit())
         return nullptr;
     return cx->activation()->asJit();
@@ -1654,19 +1630,17 @@ Simulator::handleWasmSegFault(int32_t ad
 
     MOZ_RELEASE_ASSERT(&instance->code() == &moduleSegment->code());
 
     if (!instance->memoryAccessInGuardRegion((uint8_t*)addr, numBytes))
         return false;
 
     const wasm::MemoryAccess* memoryAccess = instance->code().lookupMemoryAccess(pc);
     if (!memoryAccess) {
-        MOZ_ALWAYS_TRUE(act->asJit()->startWasmInterrupt(registerState()));
-        if (!instance->code().containsCodePC(pc))
-            MOZ_CRASH("Cannot map PC to trap handler");
+        act->asJit()->startWasmTrap(wasm::Trap::OutOfBounds, 0, registerState());
         set_pc(int32_t(moduleSegment->outOfBoundsCode()));
         return true;
     }
 
     MOZ_ASSERT(memoryAccess->hasTrapOutOfLineCode());
     set_pc(int32_t(memoryAccess->trapOutOfLineCode(moduleSegment->base())));
     return true;
 }
@@ -4920,29 +4894,16 @@ Simulator::disable_single_stepping()
     if (!single_stepping_)
         return;
     single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
     single_stepping_ = false;
     single_step_callback_ = nullptr;
     single_step_callback_arg_ = nullptr;
 }
 
-static void
-FakeInterruptHandler()
-{
-    JSContext* cx = TlsContext.get();
-    uint8_t* pc = cx->simulator()->get_pc_as<uint8_t*>();
-
-    const wasm::ModuleSegment* ms= nullptr;
-    if (!wasm::InInterruptibleCode(cx, pc, &ms))
-        return;
-
-    cx->simulator()->trigger_wasm_interrupt();
-}
-
 template<bool EnableStopSimAt>
 void
 Simulator::execute()
 {
     if (single_stepping_)
         single_step_callback_(single_step_callback_arg_, this, nullptr);
 
     // Get the PC to simulate. Cannot use the accessor here as we need the raw
@@ -4952,26 +4913,19 @@ Simulator::execute()
     while (program_counter != end_sim_pc) {
         if (EnableStopSimAt && (icount_ == Simulator::StopSimAt)) {
             fprintf(stderr, "\nStopped simulation at icount %lld\n", icount_);
             ArmDebugger dbg(this);
             dbg.debug();
         } else {
             if (single_stepping_)
                 single_step_callback_(single_step_callback_arg_, this, (void*)program_counter);
-            if (MOZ_UNLIKELY(JitOptions.simulatorAlwaysInterrupt))
-                FakeInterruptHandler();
             SimInstruction* instr = reinterpret_cast<SimInstruction*>(program_counter);
             instructionDecode(instr);
             icount_++;
-
-            if (MOZ_UNLIKELY(wasm_interrupt_)) {
-                handleWasmInterrupt();
-                wasm_interrupt_ = false;
-            }
         }
         program_counter = get_pc();
     }
 
     if (single_stepping_)
         single_step_callback_(single_step_callback_arg_, this, nullptr);
 }
 
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -192,23 +192,16 @@ class Simulator
 
     // Special case of set_register and get_register to access the raw PC value.
     void set_pc(int32_t value);
     int32_t get_pc() const;
 
     template <typename T>
     T get_pc_as() const { return reinterpret_cast<T>(get_pc()); }
 
-    void trigger_wasm_interrupt() {
-        // This can be called several times if a single interrupt isn't caught
-        // and handled by the simulator, but this is fine; once the current
-        // instruction is done executing, the interrupt will be handled anyhow.
-        wasm_interrupt_ = true;
-    }
-
     void enable_single_stepping(SingleStepCallback cb, void* arg);
     void disable_single_stepping();
 
     uintptr_t stackLimit() const;
     bool overRecursed(uintptr_t newsp = 0) const;
     bool overRecursedWithExtra(uint32_t extra) const;
 
     // Executes ARM instructions until the PC reaches end_sim_pc.
@@ -288,17 +281,16 @@ class Simulator
     inline bool isWatchedStop(uint32_t bkpt_code);
     inline bool isEnabledStop(uint32_t bkpt_code);
     inline void enableStop(uint32_t bkpt_code);
     inline void disableStop(uint32_t bkpt_code);
     inline void increaseStopCounter(uint32_t bkpt_code);
     void printStopInfo(uint32_t code);
 
     // Handle a wasm interrupt triggered by an async signal handler.
-    void handleWasmInterrupt();
     JS::ProfilingFrameIterator::RegisterState registerState();
 
     // Handle any wasm faults, returning true if the fault was handled.
     bool handleWasmSegFault(int32_t addr, unsigned numBytes);
     bool handleWasmIllFault();
 
     // Read and write memory.
     inline uint8_t readBU(int32_t addr);
@@ -421,19 +413,16 @@ class Simulator
     bool inexact_vfp_flag_;
 
     // Simulator support.
     char* stack_;
     uintptr_t stackLimit_;
     bool pc_modified_;
     int64_t icount_;
 
-    // wasm async interrupt / fault support
-    bool wasm_interrupt_;
-
     // Debugger input.
     char* lastDebuggerInput_;
 
     // Registered breakpoints.
     SimInstruction* break_pc_;
     Instr break_instr_;
 
     // Single-stepping support
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -153,16 +153,17 @@ static constexpr bool SupportsSimd = fal
 static constexpr uint32_t SimdMemoryAlignment = 16;
 
 static_assert(CodeAlignment % SimdMemoryAlignment == 0,
   "Code alignment should be larger than any of the alignments which are used for "
   "the constant sections of the code buffer.  Thus it should be larger than the "
   "alignment for SIMD constants.");
 
 static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
+static const uint32_t WasmTrapInstructionLength = 4;
 
 // Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
 static constexpr bool SupportsUint32x4FloatConversions = false;
 
 // Does this architecture support comparisons of unsigned integer vectors?
 static constexpr bool SupportsUint8x16Compares = false;
 static constexpr bool SupportsUint16x8Compares = false;
 static constexpr bool SupportsUint32x4Compares = false;
@@ -438,16 +439,17 @@ static constexpr Register ABINonArgReg2 
 // This register may be volatile or nonvolatile. Avoid d31 which is the
 // ScratchDoubleReg.
 static constexpr FloatRegister ABINonArgDoubleReg = { FloatRegisters::s16, FloatRegisters::Single };
 
 // These registers may be volatile or nonvolatile.
 // Note: these three registers are all guaranteed to be different
 static constexpr Register ABINonArgReturnReg0 = r8;
 static constexpr Register ABINonArgReturnReg1 = r9;
+static constexpr Register ABINonVolatileReg { Registers::x19 };
 
 // This register is guaranteed to be clobberable during the prologue and
 // epilogue of an ABI call which must preserve both ABI argument, return
 // and non-volatile registers.
 static constexpr Register ABINonArgReturnVolatileReg = lr;
 
 // TLS pointer argument register for WebAssembly functions. This must not alias
 // any other register used for passing function arguments or return values.
--- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
@@ -81,17 +81,16 @@ Simulator::~Simulator() {
 void Simulator::ResetState() {
   // Reset the system registers.
   nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
   fpcr_ = SimSystemRegister::DefaultValueFor(FPCR);
 
   // Reset registers to 0.
   pc_ = nullptr;
   pc_modified_ = false;
-  wasm_interrupt_ = false;
   for (unsigned i = 0; i < kNumberOfRegisters; i++) {
     set_xreg(i, 0xbadbeef);
   }
   // Set FP registers to a value that is a NaN in both 32-bit and 64-bit FP.
   uint64_t nan_bits = UINT64_C(0x7ff0dead7f8beef1);
   VIXL_ASSERT(IsSignallingNaN(rawbits_to_double(nan_bits & kDRegMask)));
   VIXL_ASSERT(IsSignallingNaN(rawbits_to_float(nan_bits & kSRegMask)));
   for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
@@ -190,25 +189,16 @@ void Simulator::Destroy(Simulator* sim) 
 }
 
 
 void Simulator::ExecuteInstruction() {
   // The program counter should always be aligned.
   VIXL_ASSERT(IsWordAligned(pc_));
   decoder_->Decode(pc_);
   increment_pc();
-
-  if (MOZ_UNLIKELY(wasm_interrupt_)) {
-    handle_wasm_interrupt();
-    // Just calling set_pc turns the pc_modified_ flag on, which means it doesn't
-    // auto-step after executing the next instruction.  Force that to off so it
-    // will auto-step after executing the first instruction of the handler.
-    pc_modified_ = false;
-    wasm_interrupt_ = false;
-  }
 }
 
 
 uintptr_t Simulator::stackLimit() const {
   return reinterpret_cast<uintptr_t>(stack_limit_);
 }
 
 
@@ -225,22 +215,16 @@ bool Simulator::overRecursed(uintptr_t n
 
 
 bool Simulator::overRecursedWithExtra(uint32_t extra) const {
   uintptr_t newsp = get_sp() - extra;
   return newsp <= stackLimit();
 }
 
 
-void Simulator::trigger_wasm_interrupt() {
-  MOZ_ASSERT(!wasm_interrupt_);
-  wasm_interrupt_ = true;
-}
-
-
 static inline JitActivation*
 GetJitActivation(JSContext* cx)
 {
     if (!js::wasm::CodeExists)
         return nullptr;
     if (!cx->activation() || !cx->activation()->isJit())
         return nullptr;
     return cx->activation()->asJit();
@@ -252,42 +236,16 @@ Simulator::registerState()
   JS::ProfilingFrameIterator::RegisterState state;
   state.pc = (uint8_t*) get_pc();
   state.fp = (uint8_t*) get_fp();
   state.lr = (uint8_t*) get_lr();
   state.sp = (uint8_t*) get_sp();
   return state;
 }
 
-// The signal handler only redirects the PC to the interrupt stub when the PC is
-// in function code. However, this guard is racy for the ARM simulator since the
-// signal handler samples PC in the middle of simulating an instruction and thus
-// the current PC may have advanced once since the signal handler's guard. So we
-// re-check here.
-void Simulator::handle_wasm_interrupt()
-{
-  if (!js::wasm::CodeExists)
-    return;
-
-  uint8_t* pc = (uint8_t*)get_pc();
-
-  const js::wasm::ModuleSegment* ms = nullptr;
-  if (!js::wasm::InInterruptibleCode(cx_, pc, &ms))
-      return;
-
-  JitActivation* act = GetJitActivation(cx_);
-  if (!act)
-      return;
-
-  if (!act->startWasmInterrupt(registerState()))
-      return;
-
-  set_pc((Instruction*)ms->interruptCode());
-}
-
 bool
 Simulator::handle_wasm_seg_fault(uintptr_t addr, unsigned numBytes)
 {
     JitActivation* act = GetJitActivation(cx_);
     if (!act)
         return false;
 
     uint8_t* pc = (uint8_t*)get_pc();
@@ -304,20 +262,17 @@ Simulator::handle_wasm_seg_fault(uintptr
 
     MOZ_RELEASE_ASSERT(&instance->code() == &moduleSegment->code());
 
     if (!instance->memoryAccessInGuardRegion((uint8_t*)addr, numBytes))
         return false;
 
     const js::wasm::MemoryAccess* memoryAccess = instance->code().lookupMemoryAccess(pc);
     if (!memoryAccess) {
-        if (!act->startWasmInterrupt(registerState()))
-	    MOZ_CRASH("Cannot start interrupt");
-        if (!instance->code().containsCodePC(pc))
-            MOZ_CRASH("Cannot map PC to trap handler");
+        act->startWasmTrap(js::wasm::Trap::OutOfBounds, 0, registerState());
         set_pc((Instruction*)moduleSegment->outOfBoundsCode());
         return true;
     }
 
     MOZ_ASSERT(memoryAccess->hasTrapOutOfLineCode());
     set_pc((Instruction*)memoryAccess->trapOutOfLineCode(moduleSegment->base()));
     return true;
 }
--- a/js/src/jit/arm64/vixl/Simulator-vixl.h
+++ b/js/src/jit/arm64/vixl/Simulator-vixl.h
@@ -741,18 +741,16 @@ class Simulator : public DecoderVisitor 
   template <typename T>
   T get_pc_as() const { return reinterpret_cast<T>(const_cast<Instruction*>(pc())); }
 
   void set_pc(const Instruction* new_pc) {
     pc_ = Memory::AddressUntag(new_pc);
     pc_modified_ = true;
   }
 
-  void trigger_wasm_interrupt();
-  void handle_wasm_interrupt();
   bool handle_wasm_ill_fault();
   bool handle_wasm_seg_fault(uintptr_t addr, unsigned numBytes);
 
   void increment_pc() {
     if (!pc_modified_) {
       pc_ = pc_->NextInstruction();
     }
 
@@ -2578,17 +2576,16 @@ class Simulator : public DecoderVisitor 
   static const int stack_size_ = (2 * MBytes) + (2 * stack_protection_size_);
   byte* stack_limit_;
 
   Decoder* decoder_;
   // Indicates if the pc has been modified by the instruction and should not be
   // automatically incremented.
   bool pc_modified_;
   const Instruction* pc_;
-  bool wasm_interrupt_;
 
   static const char* xreg_names[];
   static const char* wreg_names[];
   static const char* sreg_names[];
   static const char* dreg_names[];
   static const char* vreg_names[];
 
   static const Instruction* kEndOfSimAddress;
--- a/js/src/jit/mips32/Assembler-mips32.h
+++ b/js/src/jit/mips32/Assembler-mips32.h
@@ -124,16 +124,17 @@ static constexpr uint32_t JitStackValueA
 static_assert(JitStackAlignment % sizeof(Value) == 0 && JitStackValueAlignment >= 1,
   "Stack alignment should be a non-zero multiple of sizeof(Value)");
 
 // TODO this is just a filler to prevent a build failure. The MIPS SIMD
 // alignment requirements still need to be explored.
 // TODO Copy the static_asserts from x64/x86 assembler files.
 static constexpr uint32_t SimdMemoryAlignment = 8;
 static constexpr uint32_t WasmStackAlignment = SimdMemoryAlignment;
+static const uint32_t WasmTrapInstructionLength = 4;
 
 // Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
 static constexpr bool SupportsUint32x4FloatConversions = false;
 
 // Does this architecture support comparisons of unsigned integer vectors?
 static constexpr bool SupportsUint8x16Compares = false;
 static constexpr bool SupportsUint16x8Compares = false;
 static constexpr bool SupportsUint32x4Compares = false;
--- a/js/src/jit/mips32/Simulator-mips32.cpp
+++ b/js/src/jit/mips32/Simulator-mips32.cpp
@@ -1264,17 +1264,16 @@ Simulator::Simulator()
     // Note, allocation and anything that depends on allocated memory is
     // deferred until init(), in order to handle OOM properly.
 
     stack_ = nullptr;
     stackLimit_ = 0;
     pc_modified_ = false;
     icount_ = 0;
     break_count_ = 0;
-    wasm_interrupt_ = false;
     break_pc_ = nullptr;
     break_instr_ = 0;
 
     // Set up architecture state.
     // All registers are initialized to zero to start with.
     for (int i = 0; i < Register::kNumSimuRegisters; i++) {
         registers_[i] = 0;
     }
@@ -1637,42 +1636,16 @@ Simulator::registerState()
     wasm::RegisterState state;
     state.pc = (void*) get_pc();
     state.fp = (void*) getRegister(fp);
     state.sp = (void*) getRegister(sp);
     state.lr = (void*) getRegister(ra);
     return state;
 }
 
-// The signal handler only redirects the PC to the interrupt stub when the PC is
-// in function code. However, this guard is racy for the simulator since the
-// signal handler samples PC in the middle of simulating an instruction and thus
-// the current PC may have advanced once since the signal handler's guard. So we
-// re-check here.
-void
-Simulator::handleWasmInterrupt()
-{
-    if (!wasm::CodeExists)
-        return;
-
-    void* pc = (void*)get_pc();
-    void* fp = (void*)getRegister(Register::fp);
-
-    JitActivation* activation = TlsContext.get()->activation()->asJit();
-    const wasm::CodeSegment* segment = wasm::LookupCodeSegment(pc);
-    if (!segment || !segment->isModule() || !segment->containsCodePC(pc))
-        return;
-
-    if (!activation->startWasmInterrupt(registerState()))
-         return;
-
-    set_pc(int32_t(segment->asModule()->interruptCode()));
-}
-
-
 // WebAssembly memories contain an extra region of guard pages (see
 // WasmArrayRawBuffer comment). The guard pages catch out-of-bounds accesses
 // using a signal handler that redirects PC to a stub that safely reports an
 // error. However, if the handler is hit by the simulator, the PC is in C++ code
 // and cannot be redirected. Therefore, we must avoid hitting the handler by
 // redirecting in the simulator before the real handler would have been hit.
 bool
 Simulator::handleWasmFault(int32_t addr, unsigned numBytes)
@@ -1701,19 +1674,17 @@ Simulator::handleWasmFault(int32_t addr,
 
     if (!instance->memoryAccessInGuardRegion((uint8_t*)addr, numBytes))
          return false;
 
     LLBit_ = false;
 
     const wasm::MemoryAccess* memoryAccess = instance->code().lookupMemoryAccess(pc);
     if (!memoryAccess) {
-        MOZ_ALWAYS_TRUE(act->startWasmInterrupt(registerState()));
-        if (!instance->code().containsCodePC(pc))
-            MOZ_CRASH("Cannot map PC to trap handler");
+        act->startWasmTrap(wasm::Trap::OutOfBounds, 0, registerState());
         set_pc(int32_t(moduleSegment->outOfBoundsCode()));
         return true;
     }
 
     MOZ_ASSERT(memoryAccess->hasTrapOutOfLineCode());
     set_pc(int32_t(memoryAccess->trapOutOfLineCode(moduleSegment->base())));
     return true;
 }
@@ -3668,52 +3639,32 @@ Simulator::branchDelayInstructionDecode(
     }
 
     if (instr->isForbiddenInBranchDelay()) {
         MOZ_CRASH("Eror:Unexpected opcode in a branch delay slot.");
     }
     instructionDecode(instr);
 }
 
-static void
-FakeInterruptHandler()
-{
-    JSContext* cx = TlsContext.get();
-    uint8_t* pc = cx->simulator()->get_pc_as<uint8_t*>();
-
-    const wasm::ModuleSegment* ms = nullptr;
-    if (!wasm::InInterruptibleCode(cx, pc, &ms))
-        return;
-
-    cx->simulator()->trigger_wasm_interrupt();
-}
-
 template<bool enableStopSimAt>
 void
 Simulator::execute()
 {
     // Get the PC to simulate. Cannot use the accessor here as we need the
     // raw PC value and not the one used as input to arithmetic instructions.
     int program_counter = get_pc();
 
     while (program_counter != end_sim_pc) {
         if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
             MipsDebugger dbg(this);
             dbg.debug();
         } else {
-            if (MOZ_UNLIKELY(JitOptions.simulatorAlwaysInterrupt))
-                FakeInterruptHandler();
             SimInstruction* instr = reinterpret_cast<SimInstruction*>(program_counter);
             instructionDecode(instr);
             icount_++;
-
-            if (MOZ_UNLIKELY(wasm_interrupt_)) {
-                handleWasmInterrupt();
-                wasm_interrupt_ = false;
-            }
         }
         program_counter = get_pc();
     }
 }
 
 void
 Simulator::callInternal(uint8_t* entry)
 {
--- a/js/src/jit/mips32/Simulator-mips32.h
+++ b/js/src/jit/mips32/Simulator-mips32.h
@@ -197,23 +197,16 @@ class Simulator {
 
     // Special case of set_register and get_register to access the raw PC value.
     void set_pc(int32_t value);
     int32_t get_pc() const;
 
     template <typename T>
     T get_pc_as() const { return reinterpret_cast<T>(get_pc()); }
 
-    void trigger_wasm_interrupt() {
-        // This can be called several times if a single interrupt isn't caught
-        // and handled by the simulator, but this is fine; once the current
-        // instruction is done executing, the interrupt will be handled anyhow.
-        wasm_interrupt_ = true;
-    }
-
     // Accessor to the internal simulator stack area.
     uintptr_t stackLimit() const;
     bool overRecursed(uintptr_t newsp = 0) const;
     bool overRecursedWithExtra(uint32_t extra) const;
 
     // Executes MIPS instructions until the PC reaches end_sim_pc.
     template<bool enableStopSimAt>
     void execute();
@@ -299,18 +292,16 @@ class Simulator {
     void handleStop(uint32_t code, SimInstruction* instr);
     bool isStopInstruction(SimInstruction* instr);
     bool isEnabledStop(uint32_t code);
     void enableStop(uint32_t code);
     void disableStop(uint32_t code);
     void increaseStopCounter(uint32_t code);
     void printStopInfo(uint32_t code);
 
-    // Handle a wasm interrupt triggered by an async signal handler.
-    void handleWasmInterrupt();
     JS::ProfilingFrameIterator::RegisterState registerState();
 
     // Handle any wasm faults, returning true if the fault was handled.
     bool handleWasmFault(int32_t addr, unsigned numBytes);
     bool handleWasmTrapFault();
 
     // Executes one instruction.
     void instructionDecode(SimInstruction* instr);
@@ -360,19 +351,16 @@ class Simulator {
 
     // Simulator support.
     char* stack_;
     uintptr_t stackLimit_;
     bool pc_modified_;
     int icount_;
     int break_count_;
 
-    // wasm async interrupt / fault support
-    bool wasm_interrupt_;
-
     // Debugger input.
     char* lastDebuggerInput_;
 
     // Registered breakpoints.
     SimInstruction* break_pc_;
     Instr break_instr_;
 
     // A stop is watched if its code is less than kNumOfWatchedStops.
--- a/js/src/jit/mips64/Assembler-mips64.h
+++ b/js/src/jit/mips64/Assembler-mips64.h
@@ -135,16 +135,17 @@ static_assert(JitStackAlignment % sizeof
   "Stack alignment should be a non-zero multiple of sizeof(Value)");
 
 // TODO this is just a filler to prevent a build failure. The MIPS SIMD
 // alignment requirements still need to be explored.
 // TODO Copy the static_asserts from x64/x86 assembler files.
 static constexpr uint32_t SimdMemoryAlignment = 16;
 
 static constexpr uint32_t WasmStackAlignment = SimdMemoryAlignment;
+static const uint32_t WasmTrapInstructionLength = 4;
 
 // Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
 static constexpr bool SupportsUint32x4FloatConversions = false;
 
 // Does this architecture support comparisons of unsigned integer vectors?
 static constexpr bool SupportsUint8x16Compares = false;
 static constexpr bool SupportsUint16x8Compares = false;
 static constexpr bool SupportsUint32x4Compares = false;
--- a/js/src/jit/mips64/Simulator-mips64.cpp
+++ b/js/src/jit/mips64/Simulator-mips64.cpp
@@ -1273,17 +1273,16 @@ Simulator::Simulator()
     // Note, allocation and anything that depends on allocated memory is
     // deferred until init(), in order to handle OOM properly.
 
     stack_ = nullptr;
     stackLimit_ = 0;
     pc_modified_ = false;
     icount_ = 0;
     break_count_ = 0;
-    wasm_interrupt_ = false;
     break_pc_ = nullptr;
     break_instr_ = 0;
     single_stepping_ = false;
     single_step_callback_ = nullptr;
     single_step_callback_arg_ = nullptr;
 
     // Set up architecture state.
     // All registers are initialized to zero to start with.
@@ -1640,45 +1639,16 @@ Simulator::registerState()
     wasm::RegisterState state;
     state.pc = (void*) get_pc();
     state.fp = (void*) getRegister(fp);
     state.sp = (void*) getRegister(sp);
     state.lr = (void*) getRegister(ra);
     return state;
 }
 
-// The signal handler only redirects the PC to the interrupt stub when the PC is
-// in function code. However, this guard is racy for the simulator since the
-// signal handler samples PC in the middle of simulating an instruction and thus
-// the current PC may have advanced once since the signal handler's guard. So we
-// re-check here.
-void
-Simulator::handleWasmInterrupt()
-{
-    if (!wasm::CodeExists)
-        return;
-
-    void* pc = (void*)get_pc();
-    void* fp = (void*)getRegister(Register::fp);
-
-    JitActivation* activation = TlsContext.get()->activation()->asJit();
-    const wasm::CodeSegment* segment = wasm::LookupCodeSegment(pc);
-    if (!segment || !segment->isModule() || !segment->containsCodePC(pc))
-        return;
-
-    // fp can be null during the prologue/epilogue of the entry function.
-    if (!fp)
-        return;
-
-    if (!activation->startWasmInterrupt(registerState()))
-         return;
-
-    set_pc(int64_t(segment->asModule()->interruptCode()));
-}
-
 // WebAssembly memories contain an extra region of guard pages (see
 // WasmArrayRawBuffer comment). The guard pages catch out-of-bounds accesses
 // using a signal handler that redirects PC to a stub that safely reports an
 // error. However, if the handler is hit by the simulator, the PC is in C++ code
 // and cannot be redirected. Therefore, we must avoid hitting the handler by
 // redirecting in the simulator before the real handler would have been hit.
 bool
 Simulator::handleWasmFault(uint64_t addr, unsigned numBytes)
@@ -1707,19 +1677,17 @@ Simulator::handleWasmFault(uint64_t addr
 
     if (!instance->memoryAccessInGuardRegion((uint8_t*)addr, numBytes))
          return false;
 
     LLBit_ = false;
 
     const wasm::MemoryAccess* memoryAccess = instance->code().lookupMemoryAccess(pc);
     if (!memoryAccess) {
-        MOZ_ALWAYS_TRUE(act->startWasmInterrupt(registerState()));
-        if (!instance->code().containsCodePC(pc))
-            MOZ_CRASH("Cannot map PC to trap handler");
+        act->startWasmTrap(wasm::Trap::OutOfBounds, 0, registerState());
         set_pc(int64_t(moduleSegment->outOfBoundsCode()));
         return true;
     }
 
     MOZ_ASSERT(memoryAccess->hasTrapOutOfLineCode());
     set_pc(int64_t(memoryAccess->trapOutOfLineCode(moduleSegment->base())));
     return true;
 }
@@ -4057,29 +4025,16 @@ Simulator::disable_single_stepping()
     if (!single_stepping_)
         return;
     single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
     single_stepping_ = false;
     single_step_callback_ = nullptr;
     single_step_callback_arg_ = nullptr;
 }
 
-static void
-FakeInterruptHandler()
-{
-    JSContext* cx = TlsContext.get();
-    uint8_t* pc = cx->simulator()->get_pc_as<uint8_t*>();
-
-    const wasm::ModuleSegment* ms = nullptr;
-    if (!wasm::InInterruptibleCode(cx, pc, &ms))
-        return;
-
-    cx->simulator()->trigger_wasm_interrupt();
-}
-
 template<bool enableStopSimAt>
 void
 Simulator::execute()
 {
     if (single_stepping_)
         single_step_callback_(single_step_callback_arg_, this, nullptr);
 
     // Get the PC to simulate. Cannot use the accessor here as we need the
@@ -4088,26 +4043,19 @@ Simulator::execute()
 
     while (program_counter != end_sim_pc) {
         if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
             MipsDebugger dbg(this);
             dbg.debug();
         } else {
             if (single_stepping_)
                 single_step_callback_(single_step_callback_arg_, this, (void*)program_counter);
-            if (MOZ_UNLIKELY(JitOptions.simulatorAlwaysInterrupt))
-                FakeInterruptHandler();
             SimInstruction* instr = reinterpret_cast<SimInstruction *>(program_counter);
             instructionDecode(instr);
             icount_++;
-
-            if (MOZ_UNLIKELY(wasm_interrupt_)) {
-                handleWasmInterrupt();
-                wasm_interrupt_ = false;
-            }
         }
         program_counter = get_pc();
     }
 
     if (single_stepping_)
         single_step_callback_(single_step_callback_arg_, this, nullptr);
 }
 
--- a/js/src/jit/mips64/Simulator-mips64.h
+++ b/js/src/jit/mips64/Simulator-mips64.h
@@ -201,23 +201,16 @@ class Simulator {
 
     // Special case of set_register and get_register to access the raw PC value.
     void set_pc(int64_t value);
     int64_t get_pc() const;
 
     template <typename T>
     T get_pc_as() const { return reinterpret_cast<T>(get_pc()); }
 
-    void trigger_wasm_interrupt() {
-        // This can be called several times if a single interrupt isn't caught
-        // and handled by the simulator, but this is fine; once the current
-        // instruction is done executing, the interrupt will be handled anyhow.
-        wasm_interrupt_ = true;
-    }
-
     void enable_single_stepping(SingleStepCallback cb, void* arg);
     void disable_single_stepping();
 
     // Accessor to the internal simulator stack area.
     uintptr_t stackLimit() const;
     bool overRecursed(uintptr_t newsp = 0) const;
     bool overRecursedWithExtra(uint32_t extra) const;
 
@@ -314,18 +307,16 @@ class Simulator {
     void handleStop(uint32_t code, SimInstruction* instr);
     bool isStopInstruction(SimInstruction* instr);
     bool isEnabledStop(uint32_t code);
     void enableStop(uint32_t code);
     void disableStop(uint32_t code);
     void increaseStopCounter(uint32_t code);
     void printStopInfo(uint32_t code);
 
-    // Handle a wasm interrupt triggered by an async signal handler.
-    void handleWasmInterrupt();
     JS::ProfilingFrameIterator::RegisterState registerState();
 
     // Handle any wasm faults, returning true if the fault was handled.
     bool handleWasmFault(uint64_t addr, unsigned numBytes);
     bool handleWasmTrapFault();
 
     // Executes one instruction.
     void instructionDecode(SimInstruction* instr);
@@ -373,19 +364,16 @@ class Simulator {
 
     // Simulator support.
     char* stack_;
     uintptr_t stackLimit_;
     bool pc_modified_;
     int64_t icount_;
     int64_t break_count_;
 
-    // wasm async interrupt support
-    bool wasm_interrupt_;
-
     // Debugger input.
     char* lastDebuggerInput_;
 
     // Registered breakpoints.
     SimInstruction* break_pc_;
     Instr break_instr_;
 
     // Single-stepping support
--- a/js/src/jit/none/Architecture-none.h
+++ b/js/src/jit/none/Architecture-none.h
@@ -14,16 +14,17 @@
 #include "jit/shared/Architecture-shared.h"
 
 namespace js {
 namespace jit {
 
 static const bool SupportsSimd = false;
 static const uint32_t SimdMemoryAlignment = 4; // Make it 4 to avoid a bunch of div-by-zero warnings
 static const uint32_t WasmStackAlignment = 8;
+static const uint32_t WasmTrapInstructionLength = 0;
 
 // Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
 static constexpr bool SupportsUint32x4FloatConversions = false;
 
 // Does this architecture support comparisons of unsigned integer vectors?
 static constexpr bool SupportsUint8x16Compares = false;
 static constexpr bool SupportsUint16x8Compares = false;
 static constexpr bool SupportsUint32x4Compares = false;
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -65,16 +65,17 @@ static constexpr Register64 ReturnReg64(
 #error "Bad architecture"
 #endif
 
 static constexpr Register ABINonArgReg0 { Registers::invalid_reg };
 static constexpr Register ABINonArgReg1 { Registers::invalid_reg };
 static constexpr Register ABINonArgReg2 { Registers::invalid_reg };
 static constexpr Register ABINonArgReturnReg0 { Registers::invalid_reg };
 static constexpr Register ABINonArgReturnReg1 { Registers::invalid_reg };
+static constexpr Register ABINonVolatileReg { Registers::invalid_reg };
 static constexpr Register ABINonArgReturnVolatileReg { Registers::invalid_reg };
 
 static constexpr FloatRegister ABINonArgDoubleReg = { FloatRegisters::invalid_reg };
 
 static constexpr Register WasmTableCallScratchReg { Registers::invalid_reg };
 static constexpr Register WasmTableCallSigReg { Registers::invalid_reg };
 static constexpr Register WasmTableCallIndexReg { Registers::invalid_reg };
 static constexpr Register WasmTlsReg { Registers::invalid_reg };
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1658,16 +1658,34 @@ class LInterruptCheck : public LInstruct
         return implicit_;
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 };
 
+class LWasmInterruptCheck : public LInstructionHelper<0, 1, 0>
+{
+  public:
+    LIR_HEADER(WasmInterruptCheck)
+
+    explicit LWasmInterruptCheck(const LAllocation& tlsData)
+      : LInstructionHelper(classOpcode)
+    {
+        setOperand(0, tlsData);
+    }
+    MWasmInterruptCheck* mir() const {
+        return mir_->toWasmInterruptCheck();
+    }
+    const LAllocation* tlsPtr() {
+        return getOperand(0);
+    }
+};
+
 class LDefVar : public LCallInstructionHelper<0, 1, 0>
 {
   public:
     LIR_HEADER(DefVar)
 
     explicit LDefVar(const LAllocation& envChain)
       : LCallInstructionHelper(classOpcode)
     {
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -232,16 +232,17 @@ static_assert(CodeAlignment % SimdMemory
   "the constant sections of the code buffer.  Thus it should be larger than the "
   "alignment for SIMD constants.");
 
 static_assert(JitStackAlignment % SimdMemoryAlignment == 0,
   "Stack alignment should be larger than any of the alignments which are used for "
   "spilled values.  Thus it should be larger than the alignment for SIMD accesses.");
 
 static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
+static const uint32_t WasmTrapInstructionLength = 2;
 
 static const Scale ScalePointer = TimesEight;
 
 } // namespace jit
 } // namespace js
 
 #include "jit/x86-shared/Assembler-x86-shared.h"
 
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -149,16 +149,17 @@ static_assert(CodeAlignment % SimdMemory
   "the constant sections of the code buffer.  Thus it should be larger than the "
   "alignment for SIMD constants.");
 
 static_assert(JitStackAlignment % SimdMemoryAlignment == 0,
   "Stack alignment should be larger than any of the alignments which are used for "
   "spilled values.  Thus it should be larger than the alignment for SIMD accesses.");
 
 static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
+static const uint32_t WasmTrapInstructionLength = 2;
 
 struct ImmTag : public Imm32
 {
     explicit ImmTag(JSValueTag mask)
       : Imm32(int32_t(mask))
     { }
 };
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -775,34 +775,16 @@ JS_MarkCrossZoneId(JSContext* cx, jsid i
 }
 
 JS_PUBLIC_API(void)
 JS_MarkCrossZoneIdValue(JSContext* cx, const Value& value)
 {
     cx->markAtomValue(value);
 }
 
-JS_PUBLIC_API(JSAddonId*)
-JS::NewAddonId(JSContext* cx, HandleString str)
-{
-    return static_cast<JSAddonId*>(JS_AtomizeAndPinJSString(cx, str));
-}
-
-JS_PUBLIC_API(JSString*)
-JS::StringOfAddonId(JSAddonId* id)
-{
-    return id;
-}
-
-JS_PUBLIC_API(JSAddonId*)
-JS::AddonIdOfObject(JSObject* obj)
-{
-    return obj->compartment()->creationOptions().addonIdOrNull();
-}
-
 JS_PUBLIC_API(void)
 JS_SetZoneUserData(JS::Zone* zone, void* data)
 {
     zone->data = data;
 }
 
 JS_PUBLIC_API(void*)
 JS_GetZoneUserData(JS::Zone* zone)
@@ -3988,17 +3970,17 @@ JS::TransitiveCompileOptions::copyPODTra
     asmJSOption = rhs.asmJSOption;
     throwOnAsmJSValidationFailureOption = rhs.throwOnAsmJSValidationFailureOption;
     forceAsync = rhs.forceAsync;
     sourceIsLazy = rhs.sourceIsLazy;
     introductionType = rhs.introductionType;
     introductionLineno = rhs.introductionLineno;
     introductionOffset = rhs.introductionOffset;
     hasIntroductionInfo = rhs.hasIntroductionInfo;
-    isProbablySystemOrAddonCode = rhs.isProbablySystemOrAddonCode;
+    isProbablySystemCode = rhs.isProbablySystemCode;
     hideScriptFromDebugger = rhs.hideScriptFromDebugger;
 };
 
 void
 JS::ReadOnlyCompileOptions::copyPODOptions(const ReadOnlyCompileOptions& rhs)
 {
     copyPODTransitiveOptions(rhs);
     lineno = rhs.lineno;
@@ -4102,17 +4084,17 @@ JS::OwningCompileOptions::setIntroducerF
 
 JS::CompileOptions::CompileOptions(JSContext* cx)
     : ReadOnlyCompileOptions(), elementRoot(cx), elementAttributeNameRoot(cx),
       introductionScriptRoot(cx)
 {
     strictOption = cx->options().strictMode();
     extraWarningsOption = cx->compartment()->behaviors().extraWarnings(cx);
     expressionClosuresOption = cx->options().expressionClosures();
-    isProbablySystemOrAddonCode = cx->compartment()->isProbablySystemOrAddonCode();
+    isProbablySystemCode = cx->compartment()->isProbablySystemCode();
     werrorOption = cx->options().werror();
     if (!cx->options().asmJS())
         asmJSOption = AsmJSOption::Disabled;
     else if (cx->compartment()->debuggerObservesAsmJS())
         asmJSOption = AsmJSOption::DisabledByDebugger;
     else
         asmJSOption = AsmJSOption::Enabled;
     throwOnAsmJSValidationFailureOption = cx->options().throwOnAsmJSValidationFailure();
@@ -7267,19 +7249,16 @@ JS_SetGlobalJitCompilerOption(JSContext*
         break;
       case JSJITCOMPILER_JUMP_THRESHOLD:
         if (value == uint32_t(-1)) {
             jit::DefaultJitOptions defaultValues;
             value = defaultValues.jumpThreshold;
         }
         jit::JitOptions.jumpThreshold = value;
         break;
-      case JSJITCOMPILER_SIMULATOR_ALWAYS_INTERRUPT:
-        jit::JitOptions.simulatorAlwaysInterrupt = !!value;
-        break;
       case JSJITCOMPILER_SPECTRE_INDEX_MASKING:
         jit::JitOptions.spectreIndexMasking = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_BARRIERS:
         jit::JitOptions.spectreObjectMitigationsBarriers = !!value;
         break;
       case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS_MISC:
         jit::JitOptions.spectreObjectMitigationsMisc = !!value;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1981,37 +1981,28 @@ enum ZoneSpecifier {
  *
  * Access to these options on an existing compartment is read-only: if you
  * need particular selections, make them before you create the compartment.
  */
 class JS_PUBLIC_API(CompartmentCreationOptions)
 {
   public:
     CompartmentCreationOptions()
-      : addonId_(nullptr),
-        traceGlobal_(nullptr),
+      : traceGlobal_(nullptr),
         zoneSpec_(NewZoneInSystemZoneGroup),
         zonePointer_(nullptr),
         invisibleToDebugger_(false),
         mergeable_(false),
         preserveJitCode_(false),
         cloneSingletons_(false),
         sharedMemoryAndAtomics_(false),
         secureContext_(false),
         clampAndJitterTime_(true)
     {}
 
-    // A null add-on ID means that the compartment is not associated with an
-    // add-on.
-    JSAddonId* addonIdOrNull() const { return addonId_; }
-    CompartmentCreationOptions& setAddonId(JSAddonId* id) {
-        addonId_ = id;
-        return *this;
-    }
-
     JSTraceOp getTrace() const {
         return traceGlobal_;
     }
     CompartmentCreationOptions& setTrace(JSTraceOp op) {
         traceGlobal_ = op;
         return *this;
     }
 
@@ -2074,17 +2065,16 @@ class JS_PUBLIC_API(CompartmentCreationO
 
     bool clampAndJitterTime() const { return clampAndJitterTime_; }
     CompartmentCreationOptions& setClampAndJitterTime(bool flag) {
         clampAndJitterTime_ = flag;
         return *this;
     }
 
   private:
-    JSAddonId* addonId_;
     JSTraceOp traceGlobal_;
     ZoneSpecifier zoneSpec_;
     void* zonePointer_; // Per zoneSpec_, either a Zone, ZoneGroup, or null.
     bool invisibleToDebugger_;
     bool mergeable_;
     bool preserveJitCode_;
     bool cloneSingletons_;
     bool sharedMemoryAndAtomics_;
@@ -3603,17 +3593,17 @@ class JS_FRIEND_API(TransitiveCompileOpt
         extraWarningsOption(false),
         expressionClosuresOption(false),
         werrorOption(false),
         asmJSOption(AsmJSOption::Disabled),
         throwOnAsmJSValidationFailureOption(false),
         forceAsync(false),
         sourceIsLazy(false),
         allowHTMLComments(true),
-        isProbablySystemOrAddonCode(false),
+        isProbablySystemCode(false),
         hideScriptFromDebugger(false),
         introductionType(nullptr),
         introductionLineno(0),
         introductionOffset(0),
         hasIntroductionInfo(false)
     { }
 
     // Set all POD options (those not requiring reference counts, copies,
@@ -3639,17 +3629,17 @@ class JS_FRIEND_API(TransitiveCompileOpt
     bool extraWarningsOption;
     bool expressionClosuresOption;
     bool werrorOption;
     AsmJSOption asmJSOption;
     bool throwOnAsmJSValidationFailureOption;
     bool forceAsync;
     bool sourceIsLazy;
     bool allowHTMLComments;
-    bool isProbablySystemOrAddonCode;
+    bool isProbablySystemCode;
     bool hideScriptFromDebugger;
 
     // |introductionType| is a statically allocated C string:
     // one of "eval", "Function", or "GeneratorFunction".
     const char* introductionType;
     unsigned introductionLineno;
     uint32_t introductionOffset;
     bool hasIntroductionInfo;
@@ -4990,29 +4980,16 @@ class MOZ_RAII JSAutoByteString
     char* mBytes;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     /* Copy and assignment are not supported. */
     JSAutoByteString(const JSAutoByteString& another);
     JSAutoByteString& operator=(const JSAutoByteString& another);
 };
 
-namespace JS {
-
-extern JS_PUBLIC_API(JSAddonId*)
-NewAddonId(JSContext* cx, JS::HandleString str);
-
-extern JS_PUBLIC_API(JSString*)
-StringOfAddonId(JSAddonId* id);
-
-extern JS_PUBLIC_API(JSAddonId*)
-AddonIdOfObject(JSObject* obj);
-
-} // namespace JS
-
 /************************************************************************/
 /*
  * Symbols
  */
 
 namespace JS {
 
 /**
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -773,77 +773,16 @@ ErrorReport::ErrorReport(JSContext* cx)
     exnObject(cx)
 {
 }
 
 ErrorReport::~ErrorReport()
 {
 }
 
-void
-ErrorReport::ReportAddonExceptionToTelemetry(JSContext* cx)
-{
-    MOZ_ASSERT(exnObject);
-    RootedObject unwrapped(cx, UncheckedUnwrap(exnObject));
-    MOZ_ASSERT(unwrapped, "UncheckedUnwrap failed?");
-
-    // There is not much we can report if the exception is not an ErrorObject, let's ignore those.
-    if (!unwrapped->is<ErrorObject>())
-        return;
-
-    Rooted<ErrorObject*> errObj(cx, &unwrapped->as<ErrorObject>());
-    RootedObject stack(cx, errObj->stack());
-
-    // Let's ignore TOP level exceptions. For regular add-ons those will not be reported anyway,
-    // for SDK based once it should not be a valid case either.
-    // At this point the frame stack is unwound but the exception object stored the stack so let's
-    // use that for getting the function name.
-    if (!stack)
-        return;
-
-    JSCompartment* comp = stack->compartment();
-    JSAddonId* addonId = comp->creationOptions().addonIdOrNull();
-
-    // We only want to send the report if the scope that just have thrown belongs to an add-on.
-    // Let's check the compartment of the youngest function on the stack, to determine that.
-    if (!addonId)
-        return;
-
-    RootedString funnameString(cx);
-    JS::SavedFrameResult result = GetSavedFrameFunctionDisplayName(cx, stack, &funnameString);
-    // AccessDenied should never be the case here for add-ons but let's not risk it.
-    JSAutoByteString bytes;
-    const char* funname = nullptr;
-    bool denied = result == JS::SavedFrameResult::AccessDenied;
-    funname = denied ? "unknown"
-                     : funnameString ? AtomToPrintableString(cx,
-                                                             &funnameString->asAtom(),
-                                                             &bytes)
-                                     : "anonymous";
-
-    UniqueChars addonIdChars(JS_EncodeString(cx, addonId));
-
-    const char* filename = nullptr;
-    if (reportp && reportp->filename) {
-        filename = strrchr(reportp->filename, '/');
-        if (filename)
-            filename++;
-    }
-    if (!filename) {
-        filename = "FILE_NOT_FOUND";
-    }
-    char histogramKey[64];
-    SprintfLiteral(histogramKey, "%s %s %s %u",
-                   addonIdChars.get(),
-                   funname,
-                   filename,
-                   (reportp ? reportp->lineno : 0) );
-    cx->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS, 1, histogramKey);
-}
-
 bool
 ErrorReport::init(JSContext* cx, HandleValue exn,
                   SniffingBehavior sniffingBehavior)
 {
     MOZ_ASSERT(!cx->isExceptionPending());
     MOZ_ASSERT(!reportp);
 
     if (exn.isObject()) {
@@ -852,20 +791,16 @@ ErrorReport::init(JSContext* cx, HandleV
         exnObject = &exn.toObject();
         reportp = ErrorFromException(cx, exnObject);
 
         if (!reportp && sniffingBehavior == NoSideEffects) {
             JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                       JSMSG_ERR_DURING_THROW);
             return false;
         }
-
-        // Let's see if the exception is from add-on code, if so, it should be reported
-        // to telemetry.
-        ReportAddonExceptionToTelemetry(cx);
     }
 
 
     // Be careful not to invoke ToString if we've already successfully extracted
     // an error report, since the exception might be wrapped in a security
     // wrapper, and ToString-ing it might throw.
     if (reportp) {
         str = ErrorReportToString(cx, reportp);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -154,17 +154,16 @@ enum {
     JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS,
     JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS,
     JS_TELEMETRY_GC_MINOR_REASON,
     JS_TELEMETRY_GC_MINOR_REASON_LONG,
     JS_TELEMETRY_GC_MINOR_US,
     JS_TELEMETRY_GC_NURSERY_BYTES,
     JS_TELEMETRY_GC_PRETENURE_COUNT,
     JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT,
-    JS_TELEMETRY_ADDON_EXCEPTIONS,
     JS_TELEMETRY_PRIVILEGED_PARSER_COMPILE_LAZY_AFTER_MS,
     JS_TELEMETRY_WEB_PARSER_COMPILE_LAZY_AFTER_MS,
     JS_TELEMETRY_END
 };
 
 typedef void
 (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key);
 
--- a/js/src/vm/JSCompartment.cpp
+++ b/js/src/vm/JSCompartment.cpp
@@ -68,17 +68,17 @@ JSCompartment::JSCompartment(Zone* zone,
     arraySpeciesLookup(),
     globalWriteBarriered(0),
     detachedTypedObjects(0),
     objectMetadataState(ImmediateMetadata()),
     selfHostingScriptSource(nullptr),
     objectMetadataTable(nullptr),
     innerViews(zone),
     lazyArrayBuffers(nullptr),
-    wasm(zone),
+    wasm(zone->runtimeFromActiveCooperatingThread()),
     nonSyntacticLexicalEnvironments_(nullptr),
     gcIncomingGrayPointers(nullptr),
     debugModeBits(0),
     validAccessPtr(nullptr),
     randomKeyGenerator_(runtime_->forkRandomKeyGenerator()),
     scriptCountsMap(nullptr),
     scriptNameMap(nullptr),
     debugScriptMap(nullptr),
@@ -178,17 +178,17 @@ JSRuntime::createJitRuntime(JSContext* c
         ReportOutOfMemory(cx);
         return nullptr;
     }
 
     jit::JitRuntime* jrt = cx->new_<jit::JitRuntime>(cx->runtime());
     if (!jrt)
         return nullptr;
 
-    // Protect jitRuntime_ from being observed (by InterruptRunningJitCode)
+    // Protect jitRuntime_ from being observed (by jit::InterruptRunningCode)
     // while it is being initialized. Unfortunately, initialization depends on
     // jitRuntime_ being non-null, so we can't just wait to assign jitRuntime_.
     JitRuntime::AutoPreventBackedgePatching apbp(cx->runtime(), jrt);
     jitRuntime_ = jrt;
 
     AutoEnterOOMUnsafeRegion noOOM;
     if (!jitRuntime_->initialize(cx, atomsLock)) {
         // Handling OOM here is complicated: if we delete jitRuntime_ now, we
@@ -1337,35 +1337,35 @@ JSCompartment::addSizeOfIncludingThis(mo
             *scriptCountsMapArg += r.front().value()->sizeOfIncludingThis(mallocSizeOf);
         }
     }
 }
 
 void
 JSCompartment::reportTelemetry()
 {
-    // Only report telemetry for web content, not add-ons or chrome JS.
-    if (creationOptions_.addonIdOrNull() || isSystem_)
+    // Only report telemetry for web content, not chrome JS.
+    if (isSystem_)
         return;
 
     // Hazard analysis can't tell that the telemetry callbacks don't GC.
     JS::AutoSuppressGCAnalysis nogc;
 
     // Call back into Firefox's Telemetry reporter.
     for (size_t i = 0; i < size_t(DeprecatedLanguageExtension::Count); i++) {
         if (sawDeprecatedLanguageExtension[i])
             runtime_->addTelemetry(JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, i);
     }
 }
 
 void
 JSCompartment::addTelemetry(const char* filename, DeprecatedLanguageExtension e)
 {
-    // Only report telemetry for web content, not add-ons or chrome JS.
-    if (creationOptions_.addonIdOrNull() || isSystem_)
+    // Only report telemetry for web content, not chrome JS.
+    if (isSystem_)
         return;
     if (!filename || strncmp(filename, "http", 4) != 0)
         return;
 
     sawDeprecatedLanguageExtension[size_t(e)] = true;
 }
 
 HashNumber
--- a/js/src/vm/JSCompartment.h
+++ b/js/src/vm/JSCompartment.h
@@ -603,20 +603,17 @@ struct JSCompartment
     bool isAtomsCompartment() const {
         return isAtomsCompartment_;
     }
     void setIsAtomsCompartment() {
         isAtomsCompartment_ = true;
     }
 
     // Used to approximate non-content code when reporting telemetry.
-    inline bool isProbablySystemOrAddonCode() const {
-        if (creationOptions_.addonIdOrNull())
-            return true;
-
+    inline bool isProbablySystemCode() const {
         return isSystem_;
     }
   private:
     JSPrincipals*                principals_;
     bool                         isSystem_;
     bool                         isAtomsCompartment_;
 
   public:
--- a/js/src/vm/JSContext.cpp
+++ b/js/src/vm/JSContext.cpp
@@ -47,17 +47,16 @@
 #include "vm/HelperThreads.h"
 #include "vm/Iteration.h"
 #include "vm/JSAtom.h"
 #include "vm/JSCompartment.h"
 #include "vm/JSFunction.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/Shape.h"
-#include "wasm/WasmSignalHandlers.h"
 
 #include "vm/JSObject-inl.h"
 #include "vm/JSScript-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
@@ -97,17 +96,17 @@ js::AutoCycleDetector::~AutoCycleDetecto
     }
 }
 
 bool
 JSContext::init(ContextKind kind)
 {
     // Skip most of the initialization if this thread will not be running JS.
     if (kind == ContextKind::Cooperative) {
-        // Get a platform-native handle for this thread, used by js::InterruptRunningJitCode.
+        // Get a platform-native handle for this thread, used by jit::InterruptRunningCode.
 #ifdef XP_WIN
         size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME |
                            THREAD_QUERY_INFORMATION;
         HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId());
         if (!self)
         return false;
         static_assert(sizeof(HANDLE) <= sizeof(threadNative_), "need bigger field");
         threadNative_ = (size_t)self;
@@ -118,21 +117,22 @@ JSContext::init(ContextKind kind)
 
         if (!regexpStack.ref().init())
             return false;
 
         if (!fx.initInstance())
             return false;
 
 #ifdef JS_SIMULATOR
-        simulator_ = js::jit::Simulator::Create(this);
+        simulator_ = jit::Simulator::Create(this);
         if (!simulator_)
             return false;
 #endif
 
+        jit::EnsureAsyncInterrupt(this);
         if (!wasm::EnsureSignalHandlers(this))
             return false;
     }
 
     // Set the ContextKind last, so that ProtectedData checks will allow us to
     // initialize this context before it becomes the runtime's active context.
     kind_ = kind;
 
--- a/js/src/vm/MutexIDs.h
+++ b/js/src/vm/MutexIDs.h
@@ -31,37 +31,38 @@
                                       \
   _(WasmLazyStubsTier1,          475) \
   _(WasmLazyStubsTier2,          476) \
                                       \
   _(SharedImmutableStringsCache, 500) \
   _(FutexThread,                 500) \
   _(GeckoProfilerStrings,        500) \
   _(ProtectedRegionTree,         500) \
-  _(WasmSigIdSet,                500) \
   _(ShellOffThreadState,         500) \
   _(SimulatorCacheLock,          500) \
   _(Arm64SimulatorLock,          500) \
   _(IonSpewer,                   500) \
   _(PerfSpewer,                  500) \
   _(CacheIRSpewer,               500) \
   _(TraceLoggerThreadState,      500) \
   _(DateTimeInfoMutex,           500) \
   _(IcuTimeZoneStateMutex,       500) \
   _(ProcessExecutableRegion,     500) \
   _(OffThreadPromiseState,       500) \
   _(BufferStreamState,           500) \
+  _(SharedArrayGrow,             500) \
+  _(RuntimeScriptData,           500) \
+  _(WasmSigIdSet,                500) \
   _(WasmCodeProfilingLabels,     500) \
   _(WasmModuleTieringLock,       500) \
   _(WasmCompileTaskState,        500) \
   _(WasmCodeStreamEnd,           500) \
   _(WasmTailBytesPtr,            500) \
   _(WasmStreamStatus,            500) \
-  _(SharedArrayGrow,             500) \
-  _(RuntimeScriptData,           500) \
+  _(WasmRuntimeInstances,        500) \
                                       \
   _(ThreadId,                    600) \
   _(WasmCodeSegmentMap,          600) \
   _(TraceLoggerGraphState,       600) \
   _(VTuneLock,                   600)
 
 namespace js {
 namespace mutexid {
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -39,17 +39,16 @@
 #include "js/Wrapper.h"
 #include "util/Windows.h"
 #include "vm/Debugger.h"
 #include "vm/JSAtom.h"
 #include "vm/JSObject.h"
 #include "vm/JSScript.h"
 #include "vm/TraceLogging.h"
 #include "vm/TraceLoggingGraph.h"
-#include "wasm/WasmSignalHandlers.h"
 
 #include "gc/GC-inl.h"
 #include "vm/JSContext-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::Atomic;
@@ -172,32 +171,35 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
     offthreadIonCompilationEnabled_(true),
     parallelParsingEnabled_(true),
     autoWritableJitCodeActive_(false),
     oomCallback(nullptr),
     debuggerMallocSizeOf(ReturnZeroSize),
     lastAnimationTime(0),
     performanceMonitoring_(),
     stackFormat_(parentRuntime ? js::StackFormat::Default
-                               : js::StackFormat::SpiderMonkey)
+                               : js::StackFormat::SpiderMonkey),
+    wasmInstances(mutexid::WasmRuntimeInstances)
 {
     liveRuntimesCount++;
 
     /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
 
     PodZero(&asmJSCacheOps);
     lcovOutput().init();
 }
 
 JSRuntime::~JSRuntime()
 {
     MOZ_ASSERT(!initialized_);
 
     DebugOnly<size_t> oldCount = liveRuntimesCount--;
     MOZ_ASSERT(oldCount > 0);
+
+    MOZ_ASSERT(wasmInstances.lock()->empty());
 }
 
 bool
 JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
 {
 #ifdef DEBUG
     MOZ_ASSERT(!initialized_);
     initialized_ = true;
@@ -504,16 +506,18 @@ JSRuntime::addSizeOfIncludingThis(mozill
         for (ScriptDataTable::Range r = scriptDataTable(lock).all(); !r.empty(); r.popFront())
             rtSizes->scriptData += mallocSizeOf(r.front());
     }
 
     if (jitRuntime_) {
         jitRuntime_->execAlloc().addSizeOfCode(&rtSizes->code);
         jitRuntime_->backedgeExecAlloc().addSizeOfCode(&rtSizes->code);
     }
+
+    rtSizes->wasmRuntime += wasmInstances.lock()->sizeOfExcludingThis(mallocSizeOf);
 }
 
 static bool
 InvokeInterruptCallback(JSContext* cx)
 {
     MOZ_ASSERT(cx->requestDepth >= 1);
     MOZ_ASSERT(!cx->compartment()->isAtomsCompartment());
 
@@ -593,17 +597,18 @@ JSContext::requestInterrupt(InterruptMod
         // additional steps to interrupt corner cases where the above fields are
         // not regularly polled. Wake ilooping Ion code, irregexp JIT code and
         // Atomics.wait()
         interruptRegExpJit_ = true;
         fx.lock();
         if (fx.isWaiting())
             fx.wake(FutexThread::WakeForJSInterrupt);
         fx.unlock();
-        InterruptRunningJitCode(this);
+        jit::InterruptRunningCode(this);
+        wasm::InterruptRunningCode(this);
     }
 }
 
 bool
 JSContext::handleInterrupt()
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime()));
     if (interrupt_ || jitStackLimit == UINTPTR_MAX) {
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -994,28 +994,24 @@ struct JSRuntime : public js::MallocProv
     friend class js::gc::AutoTraceSession;
     friend class JS::AutoEnterCycleCollection;
 
   private:
     js::ActiveThreadData<js::RuntimeCaches> caches_;
   public:
     js::RuntimeCaches& caches() { return caches_.ref(); }
 
-    // When wasm traps or is interrupted, the signal handler records some data
-    // for unwinding purposes. Wasm code can't interrupt or trap reentrantly.
-    js::ActiveThreadData<
-        mozilla::MaybeOneOf<js::wasm::TrapData, js::wasm::InterruptData>
-    > wasmUnwindData;
+    // When wasm traps, the signal handler records some data for unwinding
+    // purposes. Wasm code can't trap reentrantly.
+    js::ActiveThreadData<mozilla::Maybe<js::wasm::TrapData>> wasmTrapData;
 
-    js::wasm::TrapData& wasmTrapData() {
-        return wasmUnwindData.ref().ref<js::wasm::TrapData>();
-    }
-    js::wasm::InterruptData& wasmInterruptData() {
-        return wasmUnwindData.ref().ref<js::wasm::InterruptData>();
-    }
+    // List of all the live wasm::Instances in the runtime. Equal to the union
+    // of all instances registered in all JSCompartments. Accessed from watchdog
+    // threads for purposes of wasm::InterruptRunningCode().
+    js::ExclusiveData<js::wasm::InstanceVector> wasmInstances;
 
   public:
 #if defined(NIGHTLY_BUILD)
     // Support for informing the embedding of any error thrown.
     // This mechanism is designed to let the embedding
     // log/report/fail in case certain errors are thrown
     // (e.g. SyntaxError, ReferenceError or TypeError
     // in critical code).
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -1877,17 +1877,17 @@ intrinsic_AddContentTelemetry(JSContext*
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 2);
 
     int id = args[0].toInt32();
     MOZ_ASSERT(id < JS_TELEMETRY_END);
     MOZ_ASSERT(id >= 0);
 
-    if (!cx->compartment()->isProbablySystemOrAddonCode())
+    if (!cx->compartment()->isProbablySystemCode())
         cx->runtime()->addTelemetry(id, args[1].toInt32());
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 intrinsic_WarnDeprecatedStringMethod(JSContext* cx, unsigned argc, Value* vp)
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1569,17 +1569,17 @@ jit::JitActivation::~JitActivation()
 
     // All reocvered value are taken from activation during the bailout.
     MOZ_ASSERT(ionRecovery_.empty());
 
     // The BailoutFrameInfo should have unregistered itself from the
     // JitActivations.
     MOZ_ASSERT(!bailoutData_);
 
-    MOZ_ASSERT(!isWasmInterrupted());
+    // Traps get handled immediately.
     MOZ_ASSERT(!isWasmTrapping());
 
     clearRematerializedFrames();
     js_delete(rematerializedFrames_);
 }
 
 void
 jit::JitActivation::setBailoutData(jit::BailoutFrameInfo* bailoutData)
@@ -1737,96 +1737,16 @@ jit::JitActivation::removeIonFrameRecove
 
 void
 jit::JitActivation::traceIonRecovery(JSTracer* trc)
 {
     for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); it++)
         it->trace(trc);
 }
 
-bool
-jit::JitActivation::startWasmInterrupt(const JS::ProfilingFrameIterator::RegisterState& state)
-{
-    // fp may be null when first entering wasm code from an interpreter entry
-    // stub.
-    if (!state.fp)
-        return false;
-
-    MOZ_ASSERT(state.pc);
-
-    // Execution can only be interrupted in function code. Afterwards, control
-    // flow does not reenter function code and thus there can be no
-    // interrupt-during-interrupt.
-
-    bool unwound;
-    wasm::UnwindState unwindState;
-    MOZ_ALWAYS_TRUE(wasm::StartUnwinding(state, &unwindState, &unwound));
-
-    void* pc = unwindState.pc;
-
-    if (unwound) {
-        // In the prologue/epilogue, FP might have been fixed up to the
-        // caller's FP, and the caller could be the jit entry. Ignore this
-        // interrupt, in this case, because FP points to a jit frame and not a
-        // wasm one.
-        if (!wasm::LookupCode(pc)->lookupFuncRange(pc))
-            return false;
-    }
-
-    cx_->runtime()->wasmUnwindData.ref().construct<wasm::InterruptData>(pc, state.pc);
-    setWasmExitFP(unwindState.fp);
-
-    MOZ_ASSERT(compartment() == unwindState.fp->tls->instance->compartment());
-    MOZ_ASSERT(isWasmInterrupted());
-    return true;
-}
-
-void
-jit::JitActivation::finishWasmInterrupt()
-{
-    MOZ_ASSERT(isWasmInterrupted());
-
-    cx_->runtime()->wasmUnwindData.ref().destroy();
-    packedExitFP_ = nullptr;
-}
-
-bool
-jit::JitActivation::isWasmInterrupted() const
-{
-    JSRuntime* rt = cx_->runtime();
-    if (!rt->wasmUnwindData.ref().constructed<wasm::InterruptData>())
-        return false;
-
-    Activation* act = cx_->activation();
-    while (act && !act->hasWasmExitFP())
-        act = act->prev();
-
-    if (act != this)
-        return false;
-
-    DebugOnly<const wasm::Frame*> fp = wasmExitFP();
-    DebugOnly<void*> unwindPC = rt->wasmInterruptData().unwindPC;
-    MOZ_ASSERT(fp->instance()->code().containsCodePC(unwindPC));
-    return true;
-}
-
-void*
-jit::JitActivation::wasmInterruptUnwindPC() const
-{
-    MOZ_ASSERT(isWasmInterrupted());
-    return cx_->runtime()->wasmInterruptData().unwindPC;
-}
-
-void*
-jit::JitActivation::wasmInterruptResumePC() const
-{
-    MOZ_ASSERT(isWasmInterrupted());
-    return cx_->runtime()->wasmInterruptData().resumePC;
-}
-
 void
 jit::JitActivation::startWasmTrap(wasm::Trap trap, uint32_t bytecodeOffset,
                                   const wasm::RegisterState& state)
 {
     bool unwound;
     wasm::UnwindState unwindState;
     MOZ_ALWAYS_TRUE(wasm::StartUnwinding(state, &unwindState, &unwound));
     MOZ_ASSERT(unwound == (trap == wasm::Trap::IndirectCallBadSig));
@@ -1837,61 +1757,72 @@ jit::JitActivation::startWasmTrap(wasm::
     const wasm::Code& code = fp->tls->instance->code();
     MOZ_RELEASE_ASSERT(&code == wasm::LookupCode(pc));
 
     // If the frame was unwound, the bytecodeOffset must be recovered from the
     // callsite so that it is accurate.
     if (unwound)
         bytecodeOffset = code.lookupCallSite(pc)->lineOrBytecode();
 
-    cx_->runtime()->wasmUnwindData.ref().construct<wasm::TrapData>(pc, trap, bytecodeOffset);
+    wasm::TrapData trapData;
+    trapData.resumePC = ((uint8_t*)state.pc) + jit::WasmTrapInstructionLength;
+    trapData.unwoundPC = pc;
+    trapData.trap = trap;
+    trapData.bytecodeOffset = bytecodeOffset;
+
+    cx_->runtime()->wasmTrapData = Some(trapData);
     setWasmExitFP(fp);
 }
 
 void
 jit::JitActivation::finishWasmTrap()
 {
     MOZ_ASSERT(isWasmTrapping());
 
-    cx_->runtime()->wasmUnwindData.ref().destroy();
+    cx_->runtime()->wasmTrapData.ref().reset();
     packedExitFP_ = nullptr;
 }
 
 bool
 jit::JitActivation::isWasmTrapping() const
 {
     JSRuntime* rt = cx_->runtime();
-    if (!rt->wasmUnwindData.ref().constructed<wasm::TrapData>())
+    if (!rt->wasmTrapData.ref())
         return false;
 
     Activation* act = cx_->activation();
     while (act && !act->hasWasmExitFP())
         act = act->prev();
 
     if (act != this)
         return false;
 
-    DebugOnly<const wasm::Frame*> fp = wasmExitFP();
-    DebugOnly<void*> unwindPC = rt->wasmTrapData().pc;
-    MOZ_ASSERT(fp->instance()->code().containsCodePC(unwindPC));
+    MOZ_ASSERT(wasmExitFP()->instance()->code().containsCodePC(rt->wasmTrapData->unwoundPC));
     return true;
 }
 
 void*
-jit::JitActivation::wasmTrapPC() const
+jit::JitActivation::wasmTrapResumePC() const
 {
     MOZ_ASSERT(isWasmTrapping());
-    return cx_->runtime()->wasmTrapData().pc;
+    return cx_->runtime()->wasmTrapData->resumePC;
+}
+
+void*
+jit::JitActivation::wasmTrapUnwoundPC() const
+{
+    MOZ_ASSERT(isWasmTrapping());
+    return cx_->runtime()->wasmTrapData->unwoundPC;
 }
 
 uint32_t
 jit::JitActivation::wasmTrapBytecodeOffset() const
 {
     MOZ_ASSERT(isWasmTrapping());
-    return cx_->runtime()->wasmTrapData().bytecodeOffset;
+    return cx_->runtime()->wasmTrapData->bytecodeOffset;
 }
 
 InterpreterFrameIterator&
 InterpreterFrameIterator::operator++()
 {
     MOZ_ASSERT(!done());
     if (fp_ != activation_->entryFrame_) {
         pc_ = fp_->prevpc();
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1800,31 +1800,21 @@ class JitActivation : public Activation
     wasm::ExitReason wasmExitReason() const {
         MOZ_ASSERT(hasWasmExitFP());
         return wasm::ExitReason::Decode(encodedWasmExitReason_);
     }
     static size_t offsetOfEncodedWasmExitReason() {
         return offsetof(JitActivation, encodedWasmExitReason_);
     }
 
-    // Interrupts are started from the interrupt signal handler (or the ARM
-    // simulator) and cleared by WasmHandleExecutionInterrupt or WasmHandleThrow
-    // when the interrupt is handled.
-
-    // Returns true iff we've entered interrupted state.
-    bool startWasmInterrupt(const wasm::RegisterState& state);
-    void finishWasmInterrupt();
-    bool isWasmInterrupted() const;
-    void* wasmInterruptUnwindPC() const;
-    void* wasmInterruptResumePC() const;
-
     void startWasmTrap(wasm::Trap trap, uint32_t bytecodeOffset, const wasm::RegisterState& state);
     void finishWasmTrap();
     bool isWasmTrapping() const;
-    void* wasmTrapPC() const;
+    void* wasmTrapResumePC() const;
+    void* wasmTrapUnwoundPC() const;
     uint32_t wasmTrapBytecodeOffset() const;
 };
 
 // A filtering of the ActivationIterator to only stop at JitActivations.
 class JitActivationIterator : public ActivationIterator
 {
     void settle() {
         while (!done() && !activation_->isJit())
--- a/js/src/vm/StringType.h
+++ b/js/src/vm/StringType.h
@@ -1633,21 +1633,16 @@ ValueToSource(JSContext* cx, HandleValue
  * error, otherwise returns a new string reference. No Handle needed since the
  * input is dead after the GC.
  */
 extern JSString*
 StringToSource(JSContext* cx, JSString* str);
 
 } /* namespace js */
 
-// Addon IDs are interned atoms which are never destroyed. This detail is
-// not exposed outside the API.
-class JSAddonId : public JSAtom
-{};
-
 MOZ_ALWAYS_INLINE bool
 JSString::getChar(JSContext* cx, size_t index, char16_t* code)
 {
     MOZ_ASSERT(index < length());
 
     /*
      * Optimization for one level deep ropes.
      * This is common for the following pattern:
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -1173,26 +1173,16 @@ class BaseStackFrame
 
     // Just an alias, for clarity.
     uint32_t minimumSize() const {
         return fixedSize();
     }
 
   public:
 
-    void endFunctionPrologue() {
-        MOZ_ASSERT(masm.framePushed() == fixedSize());
-        MOZ_ASSERT(fixedSize() % WasmStackAlignment == 0);
-
-        maxFramePushed_ = localSize_;
-#ifdef RABALDR_CHUNKY_STACK
-        currentFramePushed_ = localSize_;
-#endif
-    }
-
     // Initialize `localInfo` based on the types of `locals` and `args`.
     bool setupLocals(const ValTypeVector& locals, const ValTypeVector& args, bool debugEnabled,
                      LocalVector* localInfo)
     {
         MOZ_ASSERT(maxFramePushed_ != UINT32_MAX);
 
         if (!localInfo->reserve(locals.length()))
             return false;
@@ -1213,17 +1203,20 @@ class BaseStackFrame
             MOZ_ASSERT(!i.isArg());
             MOZ_ASSERT(i.index() == index);
             localInfo->infallibleEmplaceBack(i.mirType(), i.frameOffset());
             varHigh_ = i.currentLocalSize();
             index++;
         }
 
         localSize_ = AlignBytes(varHigh_, WasmStackAlignment);
-
+        maxFramePushed_ = localSize_;
+#ifdef RABALDR_CHUNKY_STACK
+        currentFramePushed_ = localSize_;
+#endif
         return true;
     }
 
     // The fixed amount of memory, in bytes, allocated on the stack below the
     // Frame for purposes such as locals and other fixed values.  Includes all
     // necessary alignment.
 
     uint32_t fixedSize() const {
@@ -1375,29 +1368,28 @@ class BaseStackFrame
 
     // We won't know until after we've generated code how big the frame will be
     // (we may need arbitrary spill slots and outgoing param slots) so emit a
     // patchable add that is patched in endFunction().
     //
     // Note the platform scratch register may be used by branchPtr(), so
     // generally tmp must be something else.
 
-    void allocStack(Register tmp, BytecodeOffset trapOffset) {
+    void checkStack(Register tmp, BytecodeOffset trapOffset) {
         stackAddOffset_ = masm.sub32FromStackPtrWithPatch(tmp);
         Label ok;
         masm.branchPtr(Assembler::Below,
                        Address(WasmTlsReg, offsetof(wasm::TlsData, stackLimit)),
                        tmp, &ok);
         masm.wasmTrap(Trap::StackOverflow, trapOffset);
         masm.bind(&ok);
     }
 
-    void patchAllocStack() {
-        masm.patchSub32FromStackPtr(stackAddOffset_,
-                                    Imm32(int32_t(maxFramePushed_ - localSize_)));
+    void patchCheckStack() {
+        masm.patchSub32FromStackPtr(stackAddOffset_, Imm32(int32_t(maxFramePushed_)));
     }
 
     // Very large frames are implausible, probably an attack.
     bool checkStackHeight() {
         // 512KiB should be enough, considering how Rabaldr uses the stack and
         // what the standard limits are:
         //
         // - 1,000 parameters
@@ -3156,36 +3148,37 @@ class BaseCompiler final : public BaseCo
 
     //////////////////////////////////////////////////////////////////////
     //
     // Function prologue and epilogue.
 
     void beginFunction() {
         JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code");
 
-        // We are unconditionally checking for overflow in fr.allocStack(), so
-        // pass IsLeaf = true to avoid a second check in the prologue.
-        IsLeaf isLeaf = true;
-        SigIdDesc sigId = env_.funcSigs[func_.index]->id;
-        BytecodeOffset trapOffset(func_.lineOrBytecode);
-        GenerateFunctionPrologue(masm, fr.fixedSize(), isLeaf, sigId, trapOffset, &offsets_,
-                                 mode_ == CompileMode::Tier1 ? Some(func_.index) : Nothing());
-
-        fr.endFunctionPrologue();
-
+        GenerateFunctionPrologue(masm,
+                                 env_.funcSigs[func_.index]->id,
+                                 mode_ == CompileMode::Tier1 ? Some(func_.index) : Nothing(),
+                                 &offsets_);
+
+        // Initialize DebugFrame fields before the stack overflow trap so that
+        // we have the invariant that all observable Frames in a debugEnabled
+        // Module have valid DebugFrames.
         if (debugEnabled_) {
-            // Initialize funcIndex and flag fields of DebugFrame.
-            size_t debugFrame = masm.framePushed() - DebugFrame::offsetOfFrame();
+#ifdef JS_CODEGEN_ARM64
+            static_assert(DebugFrame::offsetOfFrame() % WasmStackAlignment == 0, "aligned");
+#endif
+            masm.reserveStack(DebugFrame::offsetOfFrame());
             masm.store32(Imm32(func_.index),
-                         Address(masm.getStackPointer(), debugFrame + DebugFrame::offsetOfFuncIndex()));
+                         Address(masm.getStackPointer(), DebugFrame::offsetOfFuncIndex()));
             masm.storePtr(ImmWord(0),
-                          Address(masm.getStackPointer(), debugFrame + DebugFrame::offsetOfFlagsWord()));
-        }
-
-        fr.allocStack(ABINonArgReg0, trapOffset);
+                          Address(masm.getStackPointer(), DebugFrame::offsetOfFlagsWord()));
+        }
+
+        fr.checkStack(ABINonArgReg0, BytecodeOffset(func_.lineOrBytecode));
+        masm.reserveStack(fr.fixedSize() - masm.framePushed());
 
         // Copy arguments from registers to stack.
 
         const ValTypeVector& args = sig().args();
 
         for (ABIArgIter<const ValTypeVector> i(args); !i.done(); i++) {
             Local& l = localInfo_[i.index()];
             switch (i.mirType()) {
@@ -3271,17 +3264,17 @@ class BaseCompiler final : public BaseCo
         // Patch the add in the prologue so that it checks against the correct
         // frame size. Flush the constant pool in case it needs to be patched.
         masm.flush();
 
         // Precondition for patching.
         if (masm.oom())
             return false;
 
-        fr.patchAllocStack();
+        fr.patchCheckStack();
 
         masm.bind(&returnLabel_);
 
         if (debugEnabled_) {
             // Store and reload the return value from DebugFrame::return so that
             // it can be clobbered, and/or modified by the debug trap.
             saveResult();
             insertBreakablePoint(CallSiteDesc::Breakpoint);
@@ -3606,20 +3599,20 @@ class BaseCompiler final : public BaseCo
     void moveImmF32(float f, RegF32 dest) {
         masm.loadConstantFloat32(f, dest);
     }
 
     void moveImmF64(double d, RegF64 dest) {
         masm.loadConstantDouble(d, dest);
     }
 
-    void addInterruptCheck()
-    {
-        // Always use signals for interrupts with Asm.JS/Wasm
-        MOZ_RELEASE_ASSERT(HaveSignalHandlers());
+    void addInterruptCheck() {
+        ScratchI32 tmp(*this);
+        masm.loadWasmTlsRegFromFrame(tmp);
+        masm.wasmInterruptCheck(tmp, bytecodeOffset());
     }
 
     void jumpTable(const LabelVector& labels, Label* theTable) {
         // Flush constant pools to ensure that the table is never interrupted by
         // constant pool entries.
         masm.flush();
 
         masm.bind(theTable);
@@ -4687,16 +4680,19 @@ class BaseCompiler final : public BaseCo
 #elif defined(JS_CODEGEN_X86)
         // As for x64, though edx is part of r0.
         need2xI32(specific.eax, specific.edx);
         *r1 = popI64();
         *r0 = popI64ToSpecific(specific.edx_eax);
         *temp = needI32();
 #elif defined(JS_CODEGEN_MIPS64)
         pop2xI64(r0, r1);
+#elif defined(JS_CODEGEN_MIPS32)
+        pop2xI64(r0, r1);
+        *temp = needI32();
 #elif defined(JS_CODEGEN_ARM)
         pop2xI64(r0, r1);
         *temp = needI32();
 #elif defined(JS_CODEGEN_ARM64)
         pop2xI64(r0, r1);
 #else
         MOZ_CRASH("BaseCompiler porting interface: pop2xI64ForMulI64");
 #endif
@@ -9819,18 +9815,16 @@ BaseCompiler::init()
         !SigPILL_.append(MIRType::Int64) || !SigPILL_.append(MIRType::Int64))
     {
         return false;
     }
 
     if (!fr.setupLocals(locals_, sig().args(), debugEnabled_, &localInfo_))
         return false;
 
-    addInterruptCheck();
-
     return true;
 }
 
 FuncOffsets
 BaseCompiler::finish()
 {
     MOZ_ASSERT(done(), "all bytes must be consumed");
     MOZ_ASSERT(func_.callSiteLineNums.length() == lastReadCallSite_);
--- a/js/src/wasm/WasmBuiltins.cpp
+++ b/js/src/wasm/WasmBuiltins.cpp
@@ -64,38 +64,16 @@ extern MOZ_EXPORT int64_t
 static JitActivation*
 CallingActivation()
 {
     Activation* act = TlsContext.get()->activation();
     MOZ_ASSERT(act->asJit()->hasWasmExitFP());
     return act->asJit();
 }
 
-static void*
-WasmHandleExecutionInterrupt()
-{
-    JitActivation* activation = CallingActivation();
-    MOZ_ASSERT(activation->isWasmInterrupted());
-
-    if (!CheckForInterrupt(activation->cx())) {
-        // If CheckForInterrupt failed, it is time to interrupt execution.
-        // Returning nullptr to the caller will jump to the throw stub which
-        // will call HandleThrow. The JitActivation must stay in the
-        // interrupted state until then so that stack unwinding works in
-        // HandleThrow.
-        return nullptr;
-    }
-
-    // If CheckForInterrupt succeeded, then execution can proceed and the
-    // interrupt is over.
-    void* resumePC = activation->wasmInterruptResumePC();
-    activation->finishWasmInterrupt();
-    return resumePC;
-}
-
 static bool
 WasmHandleDebugTrap()
 {
     JitActivation* activation = CallingActivation();
     JSContext* cx = activation->cx();
     Frame* fp = activation->wasmExitFP();
     Instance* instance = fp->tls->instance;
     const Code& code = instance->code();
@@ -214,86 +192,118 @@ wasm::HandleThrow(JSContext* cx, WasmFra
             // Unexpected success from the handler onLeaveFrame -- raising error
             // since throw recovery is not yet implemented in the wasm baseline.
             // TODO properly handle success and resume wasm execution.
             JS_ReportErrorASCII(cx, "Unexpected success from onLeaveFrame");
         }
         frame->leave(cx);
     }
 
-    MOZ_ASSERT(!cx->activation()->asJit()->isWasmInterrupted(), "unwinding clears the interrupt");
     MOZ_ASSERT(!cx->activation()->asJit()->isWasmTrapping(), "unwinding clears the trapping state");
 
     return iter.unwoundAddressOfReturnAddress();
 }
 
 static void*
 WasmHandleThrow()
 {
     JitActivation* activation = CallingActivation();
     JSContext* cx = activation->cx();
     WasmFrameIter iter(activation);
     return HandleThrow(cx, iter);
 }
 
+// Unconditionally returns nullptr per calling convention of HandleTrap().
+static void*
+ReportError(JSContext* cx, unsigned errorNumber)
+{
+    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber);
+    return nullptr;
+};
+
+// Has the same return-value convention as HandleTrap().
+static void*
+CheckInterrupt(JSContext* cx, JitActivation* activation)
+{
+    ResetInterruptState(cx);
+
+    if (!CheckForInterrupt(cx))
+        return nullptr;
+
+    void* resumePC = activation->wasmTrapResumePC();
+    activation->finishWasmTrap();
+    return resumePC;
+}
+
+// The calling convention between this function and its caller in the stub
+// generated by GenerateTrapExit() is:
+//   - return nullptr if the stub should jump to the throw stub to unwind
+//     the activation;
+//   - return the (non-null) resumePC that should be jumped if execution should
+//     resume after the trap.
+static void*
+HandleTrap(Trap trap)
+{
+    JitActivation* activation = CallingActivation();
+    JSContext* cx = activation->cx();
+
+    switch (trap) {
+      case Trap::Unreachable:
+        return ReportError(cx, JSMSG_WASM_UNREACHABLE);
+      case Trap::IntegerOverflow:
+        return ReportError(cx, JSMSG_WASM_INTEGER_OVERFLOW);
+      case Trap::InvalidConversionToInteger:
+        return ReportError(cx, JSMSG_WASM_INVALID_CONVERSION);
+      case Trap::IntegerDivideByZero:
+        return ReportError(cx, JSMSG_WASM_INT_DIVIDE_BY_ZERO);
+      case Trap::IndirectCallToNull:
+        return ReportError(cx, JSMSG_WASM_IND_CALL_TO_NULL);
+      case Trap::IndirectCallBadSig:
+        return ReportError(cx, JSMSG_WASM_IND_CALL_BAD_SIG);
+      case Trap::ImpreciseSimdConversion:
+        return ReportError(cx, JSMSG_SIMD_FAILED_CONVERSION);
+      case Trap::OutOfBounds:
+        return ReportError(cx, JSMSG_WASM_OUT_OF_BOUNDS);
+      case Trap::UnalignedAccess:
+        return ReportError(cx, JSMSG_WASM_UNALIGNED_ACCESS);
+      case Trap::CheckInterrupt:
+        return CheckInterrupt(cx, activation);
+      case Trap::StackOverflow:
+        // TlsData::setInterrupt() causes a fake stack overflow. Since
+        // TlsData::setInterrupt() is called racily, it's possible for a real
+        // stack overflow to trap, followed by a racy call to setInterrupt().
+        // Thus, we must check for a real stack overflow first before we
+        // CheckInterrupt() and possibly resume execution.
+        if (!CheckRecursionLimit(cx))
+            return nullptr;
+        if (activation->wasmExitFP()->tls->isInterrupted())
+            return CheckInterrupt(cx, activation);
+        return ReportError(cx, JSMSG_OVER_RECURSED);
+      case Trap::ThrowReported:
+        // Error was already reported under another name.
+        return nullptr;
+      case Trap::Limit:
+        break;
+    }
+
+    MOZ_CRASH("unexpected trap");
+}
+
 static void
 WasmOldReportTrap(int32_t trapIndex)
 {
-    JSContext* cx = TlsContext.get();
-
     MOZ_ASSERT(trapIndex < int32_t(Trap::Limit) && trapIndex >= 0);
-    Trap trap = Trap(trapIndex);
-
-    unsigned errorNumber;
-    switch (trap) {
-      case Trap::Unreachable:
-        errorNumber = JSMSG_WASM_UNREACHABLE;
-        break;
-      case Trap::IntegerOverflow:
-        errorNumber = JSMSG_WASM_INTEGER_OVERFLOW;
-        break;
-      case Trap::InvalidConversionToInteger:
-        errorNumber = JSMSG_WASM_INVALID_CONVERSION;
-        break;
-      case Trap::IntegerDivideByZero:
-        errorNumber = JSMSG_WASM_INT_DIVIDE_BY_ZERO;
-        break;
-      case Trap::IndirectCallToNull:
-        errorNumber = JSMSG_WASM_IND_CALL_TO_NULL;
-        break;
-      case Trap::IndirectCallBadSig:
-        errorNumber = JSMSG_WASM_IND_CALL_BAD_SIG;
-        break;
-      case Trap::ImpreciseSimdConversion:
-        errorNumber = JSMSG_SIMD_FAILED_CONVERSION;
-        break;
-      case Trap::OutOfBounds:
-        errorNumber = JSMSG_WASM_OUT_OF_BOUNDS;
-        break;
-      case Trap::UnalignedAccess:
-        errorNumber = JSMSG_WASM_UNALIGNED_ACCESS;
-        break;
-      case Trap::StackOverflow:
-        errorNumber = JSMSG_OVER_RECURSED;
-        break;
-      case Trap::ThrowReported:
-        // Error was already reported under another name.
-        return;
-      default:
-        MOZ_CRASH("unexpected trap");
-    }
-
-    JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber);
+    DebugOnly<void*> resumePC = HandleTrap(Trap(trapIndex));
+    MOZ_ASSERT(!resumePC);
 }
 
-static void
-WasmReportTrap()
+static void*
+WasmHandleTrap()
 {
-    Trap trap = TlsContext.get()->runtime()->wasmTrapData().trap;
-    WasmOldReportTrap(int32_t(trap));
+    return HandleTrap(TlsContext.get()->runtime()->wasmTrapData->trap);
 }
 
 static void
 WasmReportOutOfBounds()
 {
     JSContext* cx = TlsContext.get();
     JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_OUT_OF_BOUNDS);
 }
@@ -506,28 +516,25 @@ FuncCast(F* funcPtr, ABIFunctionType abi
 #endif
     return pf;
 }
 
 void*
 wasm::AddressOf(SymbolicAddress imm, ABIFunctionType* abiType)
 {
     switch (imm) {
-      case SymbolicAddress::HandleExecutionInterrupt:
-        *abiType = Args_General0;
-        return FuncCast(WasmHandleExecutionInterrupt, *abiType);
       case SymbolicAddress::HandleDebugTrap:
         *abiType = Args_General0;
         return FuncCast(WasmHandleDebugTrap, *abiType);
       case SymbolicAddress::HandleThrow:
         *abiType = Args_General0;
         return FuncCast(WasmHandleThrow, *abiType);
-      case SymbolicAddress::ReportTrap:
+      case SymbolicAddress::HandleTrap:
         *abiType = Args_General0;
-        return FuncCast(WasmReportTrap, *abiType);
+        return FuncCast(WasmHandleTrap, *abiType);
       case SymbolicAddress::OldReportTrap:
         *abiType = Args_General1;
         return FuncCast(WasmOldReportTrap, *abiType);
       case SymbolicAddress::ReportOutOfBounds:
         *abiType = Args_General0;
         return FuncCast(WasmReportOutOfBounds, *abiType);
       case SymbolicAddress::ReportUnalignedAccess:
         *abiType = Args_General0;
@@ -687,20 +694,19 @@ wasm::AddressOf(SymbolicAddress imm, ABI
 }
 
 bool
 wasm::NeedsBuiltinThunk(SymbolicAddress sym)
 {
     // Some functions don't want to a thunk, because they already have one or
     // they don't have frame info.
     switch (sym) {
-      case SymbolicAddress::HandleExecutionInterrupt: // GenerateInterruptExit
       case SymbolicAddress::HandleDebugTrap:          // GenerateDebugTrapStub
       case SymbolicAddress::HandleThrow:              // GenerateThrowStub
-      case SymbolicAddress::ReportTrap:               // GenerateTrapExit
+      case SymbolicAddress::HandleTrap:               // GenerateTrapExit
       case SymbolicAddress::OldReportTrap:            // GenerateOldTrapExit
       case SymbolicAddress::ReportOutOfBounds:        // GenerateOutOfBoundsExit
       case SymbolicAddress::ReportUnalignedAccess:    // GenerateUnalignedExit
       case SymbolicAddress::CallImport_Void:          // GenerateImportInterpExit
       case SymbolicAddress::CallImport_I32:
       case SymbolicAddress::CallImport_I64:
       case SymbolicAddress::CallImport_F64:
       case SymbolicAddress::CoerceInPlace_ToInt32:    // GenerateImportJitExit
@@ -869,18 +875,18 @@ PopulateTypedNatives(TypedNativeToFuncPt
 
 // ============================================================================
 // Process-wide builtin thunk set
 //
 // Thunks are inserted between wasm calls and the C++ callee and achieve two
 // things:
 //  - bridging the few differences between the internal wasm ABI and the external
 //    native ABI (viz. float returns on x86 and soft-fp ARM)
-//  - executing an exit prologue/epilogue which in turn allows any asynchronous
-//    interrupt to see the full stack up to the wasm operation that called out
+//  - executing an exit prologue/epilogue which in turn allows any profiling
+//    iterator to see the full stack up to the wasm operation that called out
 //
 // Thunks are created for two kinds of C++ callees, enumerated above:
 //  - SymbolicAddress: for statically compiled calls in the wasm module
 //  - Imported JS builtins: optimized calls to imports
 //
 // All thunks are created up front, lazily, when the first wasm module is
 // compiled in the process. Thunks are kept alive until the JS engine shuts down
 // in the process. No thunks are created at runtime after initialization. This
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -330,25 +330,23 @@ ModuleSegment::initialize(Tier tier,
                           UniqueCodeBytes codeBytes,
                           uint32_t codeLength,
                           const ShareableBytes& bytecode,
                           const LinkDataTier& linkData,
                           const Metadata& metadata,
                           const CodeRangeVector& codeRanges)
 {
     MOZ_ASSERT(bytes_ == nullptr);
-    MOZ_ASSERT(linkData.interruptOffset);
     MOZ_ASSERT(linkData.outOfBoundsOffset);
     MOZ_ASSERT(linkData.unalignedAccessOffset);
     MOZ_ASSERT(linkData.trapOffset);
 
     tier_ = tier;
     bytes_ = Move(codeBytes);
     length_ = codeLength;
-    interruptCode_ = bytes_.get() + linkData.interruptOffset;
     outOfBoundsCode_ = bytes_.get() + linkData.outOfBoundsOffset;
     unalignedAccessCode_ = bytes_.get() + linkData.unalignedAccessOffset;
     trapCode_ = bytes_.get() + linkData.trapOffset;
 
     if (!StaticallyLink(*this, linkData))
         return false;
 
     ExecutableAllocator::cacheFlush(bytes_.get(), RoundupCodeLength(codeLength));
--- a/js/src/wasm/WasmCode.h
+++ b/js/src/wasm/WasmCode.h
@@ -139,19 +139,18 @@ class CodeSegment
 
 typedef UniquePtr<ModuleSegment> UniqueModuleSegment;
 typedef UniquePtr<const ModuleSegment> UniqueConstModuleSegment;
 
 class ModuleSegment : public CodeSegment
 {
     Tier            tier_;
 
-    // These are pointers into code for stubs used for asynchronous
-    // signal-handler control-flow transfer.
-    uint8_t*        interruptCode_;
+    // These are pointers into code for stubs used for signal-handler
+    // control-flow transfer.
     uint8_t*        outOfBoundsCode_;
     uint8_t*        unalignedAccessCode_;
     uint8_t*        trapCode_;
 
     bool initialize(Tier tier,
                     UniqueCodeBytes bytes,
                     uint32_t codeLength,
                     const ShareableBytes& bytecode,
@@ -168,17 +167,16 @@ class ModuleSegment : public CodeSegment
                                       const CodeRangeVector& codeRanges);
   public:
     ModuleSegment(const ModuleSegment&) = delete;
     void operator=(const ModuleSegment&) = delete;
 
     ModuleSegment()
       : CodeSegment(),
         tier_(Tier(-1)),
-        interruptCode_(nullptr),
         outOfBoundsCode_(nullptr),
         unalignedAccessCode_(nullptr),
         trapCode_(nullptr)
     {}
 
     static UniqueModuleSegment create(Tier tier,
                                       jit::MacroAssembler& masm,
                                       const ShareableBytes& bytecode,
@@ -190,17 +188,16 @@ class ModuleSegment : public CodeSegment
                                       const Bytes& unlinkedBytes,
                                       const ShareableBytes& bytecode,
                                       const LinkDataTier& linkData,
                                       const Metadata& metadata,
                                       const CodeRangeVector& codeRanges);
 
     Tier tier() const { return tier_; }
 
-    uint8_t* interruptCode() const { return interruptCode_; }
     uint8_t* outOfBoundsCode() const { return outOfBoundsCode_; }
     uint8_t* unalignedAccessCode() const { return unalignedAccessCode_; }
     uint8_t* trapCode() const { return trapCode_; }
 
     // Structured clone support:
 
     size_t serializedSize() const;
     uint8_t* serialize(uint8_t* cursor, const LinkDataTier& linkDataTier) const;
--- a/js/src/wasm/WasmCompartment.cpp
+++ b/js/src/wasm/WasmCompartment.cpp
@@ -21,17 +21,18 @@
 #include "vm/JSCompartment.h"
 #include "wasm/WasmInstance.h"
 
 #include "vm/Debugger-inl.h"
 
 using namespace js;
 using namespace wasm;
 
-Compartment::Compartment(Zone* zone)
+Compartment::Compartment(JSRuntime* rt)
+  : runtime_(rt)
 {}
 
 Compartment::~Compartment()
 {
     MOZ_ASSERT(instances_.empty());
 }
 
 struct InstanceComparator
@@ -57,50 +58,85 @@ struct InstanceComparator
 
         return target.codeBase(targetTier) < instance->codeBase(instanceTier) ? -1 : 1;
     }
 };
 
 bool
 Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceObj)
 {
+    MOZ_ASSERT(runtime_ == cx->runtime());
+
     Instance& instance = instanceObj->instance();
     MOZ_ASSERT(this == &instance.compartment()->wasm);
 
     instance.ensureProfilingLabels(cx->runtime()->geckoProfiler().enabled());
 
     if (instance.debugEnabled() && instance.compartment()->debuggerObservesAllExecution())
         instance.ensureEnterFrameTrapsState(cx, true);
 
-    size_t index;
-    if (BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
-        MOZ_CRASH("duplicate registration");
+    {
+        if (!instances_.reserve(instances_.length() + 1))
+            return false;
+
+        auto runtimeInstances = cx->runtime()->wasmInstances.lock();
+        if (!runtimeInstances->reserve(runtimeInstances->length() + 1))
+            return false;
 
-    if (!instances_.insert(instances_.begin() + index, &instance)) {
-        ReportOutOfMemory(cx);
-        return false;
+        // To avoid implementing rollback, do not fail after mutations start.
+
+        InstanceComparator cmp(instance);
+        size_t index;
+
+        MOZ_ALWAYS_FALSE(BinarySearchIf(instances_, 0, instances_.length(), cmp, &index));
+        MOZ_ALWAYS_TRUE(instances_.insert(instances_.begin() + index, &instance));
+
+        MOZ_ALWAYS_FALSE(BinarySearchIf(runtimeInstances.get(), 0, runtimeInstances->length(), cmp, &index));
+        MOZ_ALWAYS_TRUE(runtimeInstances->insert(runtimeInstances->begin() + index, &instance));
     }
 
+    // Notify the debugger after wasmInstances is unlocked.
     Debugger::onNewWasmInstance(cx, instanceObj);
     return true;
 }
 
 void
 Compartment::unregisterInstance(Instance& instance)
 {
+    InstanceComparator cmp(instance);
     size_t index;
-    if (!BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
-        return;
-    instances_.erase(instances_.begin() + index);
+
+    if (BinarySearchIf(instances_, 0, instances_.length(), cmp, &index))
+        instances_.erase(instances_.begin() + index);
+
+    auto runtimeInstances = runtime_->wasmInstances.lock();
+    if (BinarySearchIf(runtimeInstances.get(), 0, runtimeInstances->length(), cmp, &index))
+        runtimeInstances->erase(runtimeInstances->begin() + index);
 }
 
 void
 Compartment::ensureProfilingLabels(bool profilingEnabled)
 {
     for (Instance* instance : instances_)
         instance->ensureProfilingLabels(profilingEnabled);
 }
 
 void
 Compartment::addSizeOfExcludingThis(MallocSizeOf mallocSizeOf, size_t* compartmentTables)
 {
     *compartmentTables += instances_.sizeOfExcludingThis(mallocSizeOf);
 }
+
+void
+wasm::InterruptRunningCode(JSContext* cx)
+{
+    auto runtimeInstances = cx->runtime()->wasmInstances.lock();
+    for (Instance* instance : runtimeInstances.get())
+        instance->tlsData()->setInterrupt();
+}
+
+void
+wasm::ResetInterruptState(JSContext* cx)
+{
+    auto runtimeInstances = cx->runtime()->wasmInstances.lock();
+    for (Instance* instance : runtimeInstances.get())
+        instance->tlsData()->resetInterrupt(cx);
+}
--- a/js/src/wasm/WasmCompartment.h
+++ b/js/src/wasm/WasmCompartment.h
@@ -19,29 +19,28 @@
 #ifndef wasm_compartment_h
 #define wasm_compartment_h
 
 #include "wasm/WasmJS.h"
 
 namespace js {
 namespace wasm {
 
-typedef Vector<Instance*, 0, SystemAllocPolicy> InstanceVector;
-
 // wasm::Compartment lives in JSCompartment and contains the wasm-related
 // per-compartment state. wasm::Compartment tracks every live instance in the
 // compartment and must be notified, via registerInstance(), of any new
 // WasmInstanceObject.
 
 class Compartment
 {
+    JSRuntime* runtime_;
     InstanceVector instances_;
 
   public:
-    explicit Compartment(Zone* zone);
+    explicit Compartment(JSRuntime* rt);
     ~Compartment();
 
     // Before a WasmInstanceObject can be considered fully constructed and
     // valid, it must be registered with the Compartment. If this method fails,
     // an error has been reported and the instance object must be abandoned.
     // After a successful registration, an Instance must call
     // unregisterInstance() before being destroyed.
 
@@ -59,12 +58,25 @@ class Compartment
 
     void ensureProfilingLabels(bool profilingEnabled);
 
     // about:memory reporting
 
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* compartmentTables);
 };
 
+// Interrupt all running wasm Instances that have been registered with
+// wasm::Compartments in the given JSContext.
+
+extern void
+InterruptRunningCode(JSContext* cx);
+
+// After a wasm Instance sees an interrupt request and calls
+// CheckForInterrupt(), it should call RunningCodeInterrupted() to clear the
+// interrupt request for all wasm Instances to avoid spurious trapping.
+
+void
+ResetInterruptState(JSContext* cx);
+
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_compartment_h
--- a/js/src/wasm/WasmFrameIter.cpp
+++ b/js/src/wasm/WasmFrameIter.cpp
@@ -45,48 +45,27 @@ WasmFrameIter::WasmFrameIter(JitActivati
     MOZ_ASSERT(fp_);
 
     // When the stack is captured during a trap (viz., to create the .stack
     // for an Error object), use the pc/bytecode information captured by the
     // signal handler in the runtime.
 
     if (activation->isWasmTrapping()) {
         code_ = &fp_->tls->instance->code();
-        MOZ_ASSERT(code_ == LookupCode(activation->wasmTrapPC()));
+        MOZ_ASSERT(code_ == LookupCode(activation->wasmTrapUnwoundPC()));
 
-        codeRange_ = code_->lookupFuncRange(activation->wasmTrapPC());
+        codeRange_ = code_->lookupFuncRange(activation->wasmTrapUnwoundPC());
         MOZ_ASSERT(codeRange_);
 
         lineOrBytecode_ = activation->wasmTrapBytecodeOffset();
 
         MOZ_ASSERT(!done());
         return;
     }
 
-    // When asynchronously interrupted, exitFP is set to the interrupted frame
-    // itself and so we do not want to skip it. Instead, we can recover the
-    // Code and CodeRange from the JitActivation, which are set when control
-    // flow was interrupted. There is no CallSite (b/c the interrupt was
-    // async), but this is fine because CallSite is only used for line number
-    // for which we can use the beginning of the function from the CodeRange
-    // instead.
-
-    if (activation->isWasmInterrupted()) {
-        code_ = &fp_->tls->instance->code();
-        MOZ_ASSERT(code_ == LookupCode(activation->wasmInterruptUnwindPC()));
-
-        codeRange_ = code_->lookupFuncRange(activation->wasmInterruptUnwindPC());
-        MOZ_ASSERT(codeRange_);
-
-        lineOrBytecode_ = codeRange_->funcLineOrBytecode();
-
-        MOZ_ASSERT(!done());
-        return;
-    }
-
     // Otherwise, execution exits wasm code via an exit stub which sets exitFP
     // to the exit stub's frame. Thus, in this case, we want to start iteration
     // at the caller of the exit frame, whose Code, CodeRange and CallSite are
     // indicated by the returnAddress of the exit stub's frame. If the caller
     // was Ion, we can just skip the wasm frames.
 
     popFrame();
     MOZ_ASSERT(!done() || unwoundIonCallerFP_);
@@ -106,24 +85,22 @@ WasmFrameIter::operator++()
     MOZ_ASSERT(!done());
 
     // When the iterator is set to unwind, each time the iterator pops a frame,
     // the JitActivation is updated so that the just-popped frame is no longer
     // visible. This is necessary since Debugger::onLeaveFrame is called before
     // popping each frame and, once onLeaveFrame is called for a given frame,
     // that frame must not be visible to subsequent stack iteration (or it
     // could be added as a "new" frame just as it becomes garbage).  When the
-    // frame is "interrupted", then exitFP is included in the callstack
-    // (otherwise, it is skipped, as explained above). So to unwind the
-    // innermost frame, we just clear the interrupt state.
+    // frame is trapping, then exitFP is included in the callstack (otherwise,
+    // it is skipped, as explained above). So to unwind the innermost frame, we
+    // just clear the trapping state.
 
     if (unwind_ == Unwind::True) {
-        if (activation_->isWasmInterrupted())
-            activation_->finishWasmInterrupt();
-        else if (activation_->isWasmTrapping())
+        if (activation_->isWasmTrapping())
             activation_->finishWasmTrap();
         activation_->setWasmExitFP(fp_);
     }
 
     popFrame();
 }
 
 void
@@ -492,19 +469,18 @@ GenerateCallableEpilogue(MacroAssembler&
 
 #endif
 
     MOZ_ASSERT_IF(!masm.oom(), PoppedFP == *ret - poppedFP);
     MOZ_ASSERT_IF(!masm.oom(), PoppedTLSReg == *ret - poppedTlsReg);
 }
 
 void
-wasm::GenerateFunctionPrologue(MacroAssembler& masm, uint32_t framePushed, IsLeaf isLeaf,
-                               const SigIdDesc& sigId, BytecodeOffset trapOffset,
-                               FuncOffsets* offsets, const Maybe<uint32_t>& tier1FuncIndex)
+wasm::GenerateFunctionPrologue(MacroAssembler& masm, const SigIdDesc& sigId,
+                               const Maybe<uint32_t>& tier1FuncIndex, FuncOffsets* offsets)
 {
     // Flush pending pools so they do not get dumped between the 'begin' and
     // 'normalEntry' offsets since the difference must be less than UINT8_MAX
     // to be stored in CodeRange::funcBeginToNormalEntry_.
     masm.flushBuffer();
     masm.haltingAlign(CodeAlignment);
 
     // The table entry falls through into the normal entry after it has checked
@@ -558,44 +534,17 @@ wasm::GenerateFunctionPrologue(MacroAsse
     if (tier1FuncIndex) {
         Register scratch = ABINonArgReg0;
         masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, jumpTable)), scratch);
         masm.jump(Address(scratch, *tier1FuncIndex * sizeof(uintptr_t)));
     }
 
     offsets->tierEntry = masm.currentOffset();
 
-    // The framePushed value is tier-variant and thus the stack increment must
-    // go after the tiering jump/entry.
-    if (framePushed > 0) {
-        // If the frame is large, don't bump sp until after the stack limit check so
-        // that the trap handler isn't called with a wild sp.
-        if (framePushed > MAX_UNCHECKED_LEAF_FRAME_SIZE) {
-            Label ok;
-            Register scratch = ABINonArgReg0;
-            masm.moveStackPtrTo(scratch);
-            masm.subPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, stackLimit)), scratch);
-            masm.branchPtr(Assembler::GreaterThan, scratch, Imm32(framePushed), &ok);
-            masm.wasmTrap(wasm::Trap::StackOverflow, trapOffset);
-            masm.bind(&ok);
-        }
-
-        masm.reserveStack(framePushed);
-
-        if (framePushed <= MAX_UNCHECKED_LEAF_FRAME_SIZE && !isLeaf) {
-            Label ok;
-            masm.branchStackPtrRhs(Assembler::Below,
-                                   Address(WasmTlsReg, offsetof(wasm::TlsData, stackLimit)),
-                                   &ok);
-            masm.wasmTrap(wasm::Trap::StackOverflow, trapOffset);
-            masm.bind(&ok);
-        }
-    }
-
-    MOZ_ASSERT(masm.framePushed() == framePushed);
+    MOZ_ASSERT(masm.framePushed() == 0);
 }
 
 void
 wasm::GenerateFunctionEpilogue(MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets)
 {
     // Inverse of GenerateFunctionPrologue:
     MOZ_ASSERT(masm.framePushed() == framePushed);
     GenerateCallableEpilogue(masm, framePushed, ExitReason::None(), &offsets->ret);
@@ -783,20 +732,18 @@ ProfilingFrameIterator::initFromExitFP(c
     code_ = LookupCode(pc, &codeRange_);
     MOZ_ASSERT(code_);
     MOZ_ASSERT(codeRange_);
 
     // Since we don't have the pc for fp, start unwinding at the caller of fp.
     // This means that the innermost frame is skipped. This is fine because:
     //  - for import exit calls, the innermost frame is a thunk, so the first
     //    frame that shows up is the function calling the import;
-    //  - for Math and other builtin calls as well as interrupts, we note the
-    //    absence of an exit reason and inject a fake "builtin" frame; and
-    //  - for async interrupts, we just accept that we'll lose the innermost
-    //    frame.
+    //  - for Math and other builtin calls, we note the absence of an exit
+    //    reason and inject a fake "builtin" frame; and
     switch (codeRange_->kind()) {
       case CodeRange::InterpEntry:
         callerPC_ = nullptr;
         callerFP_ = nullptr;
         codeRange_ = nullptr;
         exitReason_ = ExitReason(ExitReason::Fixed::FakeInterpEntry);
         break;
       case CodeRange::JitEntry:
@@ -814,17 +761,16 @@ ProfilingFrameIterator::initFromExitFP(c
       case CodeRange::ImportInterpExit:
       case CodeRange::BuiltinThunk:
       case CodeRange::TrapExit:
       case CodeRange::OldTrapExit:
       case CodeRange::DebugTrap:
       case CodeRange::OutOfBoundsExit:
       case CodeRange::UnalignedExit:
       case CodeRange::Throw:
-      case CodeRange::Interrupt:
       case CodeRange::FarJumpIsland:
         MOZ_CRASH("Unexpected CodeRange kind");
     }
 
     MOZ_ASSERT(!done());
 }
 
 bool
@@ -1035,21 +981,16 @@ js::wasm::StartUnwinding(const RegisterS
         if (intptr_t(fixedFP) == (FailFP & ~JitActivation::ExitFpWasmBit))
             return false;
         break;
       case CodeRange::Throw:
         // The throw stub executes a small number of instructions before popping
         // the entire activation. To simplify testing, we simply pretend throw
         // stubs have already popped the entire stack.
         return false;
-      case CodeRange::Interrupt:
-        // When the PC is in the async interrupt stub, the fp may be garbage and
-        // so we cannot blindly unwind it. Since the percent of time spent in
-        // the interrupt stub is extremely small, just ignore the stack.
-        return false;
     }
 
     unwindState->code = code;
     unwindState->codeRange = codeRange;
     unwindState->fp = fixedFP;
     unwindState->pc = fixedPC;
     return true;
 }
@@ -1165,33 +1106,31 @@ ProfilingFrameIterator::operator++()
         callerPC_ = callerFP_->returnAddress;
         AssertMatchesCallSite(callerPC_, callerFP_->callerFP);
         callerFP_ = callerFP_->callerFP;
         break;
       case CodeRange::InterpEntry:
         MOZ_CRASH("should have had null caller fp");
       case CodeRange::JitEntry:
         MOZ_CRASH("should have been guarded above");
-      case CodeRange::Interrupt:
       case CodeRange::Throw:
         MOZ_CRASH("code range doesn't have frame");
     }
 
     MOZ_ASSERT(!done());
 }
 
 static const char*
 ThunkedNativeToDescription(SymbolicAddress func)
 {
     MOZ_ASSERT(NeedsBuiltinThunk(func));
     switch (func) {
-      case SymbolicAddress::HandleExecutionInterrupt:
       case SymbolicAddress::HandleDebugTrap:
       case SymbolicAddress::HandleThrow:
-      case SymbolicAddress::ReportTrap:
+      case SymbolicAddress::HandleTrap:
       case SymbolicAddress::OldReportTrap:
       case SymbolicAddress::ReportOutOfBounds:
       case SymbolicAddress::ReportUnalignedAccess:
       case SymbolicAddress::CallImport_Void:
       case SymbolicAddress::CallImport_I32:
       case SymbolicAddress::CallImport_I64:
       case SymbolicAddress::CallImport_F64:
       case SymbolicAddress::CoerceInPlace_ToInt32:
@@ -1334,18 +1273,17 @@ ProfilingFrameIterator::label() const
       case CodeRange::BuiltinThunk:      return builtinNativeDescription;
       case CodeRange::ImportInterpExit:  return importInterpDescription;
       case CodeRange::TrapExit:          return trapDescription;
       case CodeRange::OldTrapExit:       return trapDescription;
       case CodeRange::DebugTrap:         return debugTrapDescription;
       case CodeRange::OutOfBoundsExit:   return "out-of-bounds stub (in wasm)";
       case CodeRange::UnalignedExit:     return "unaligned trap stub (in wasm)";
       case CodeRange::FarJumpIsland:     return "interstitial (in wasm)";
-      case CodeRange::Throw:             MOZ_FALLTHROUGH;
-      case CodeRange::Interrupt:         MOZ_CRASH("does not have a frame");
+      case CodeRange::Throw:             MOZ_CRASH("does not have a frame");
     }
 
     MOZ_CRASH("bad code range kind");
 }
 
 Instance*
 wasm::LookupFaultingInstance(const ModuleSegment& codeSegment, void* pc, void* fp)
 {
--- a/js/src/wasm/WasmFrameIter.h
+++ b/js/src/wasm/WasmFrameIter.h
@@ -44,22 +44,16 @@ struct FuncOffsets;
 struct CallableOffsets;
 
 // Iterates over a linear group of wasm frames of a single wasm JitActivation,
 // called synchronously from C++ in the wasm thread. It will stop at the first
 // frame that is not of the same kind, or at the end of an activation.
 //
 // If you want to handle every kind of frames (including JS jit frames), use
 // JitFrameIter.
-//
-// 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. That being said, we try our best printing
-// an informative message to the user and at least the name of the innermost
-// function stack frame.
 
 class WasmFrameIter
 {
   public:
     enum class Unwind { True, False };
 
   private:
     jit::JitActivation* activation_;
@@ -153,17 +147,17 @@ class ExitReason
     }
     SymbolicAddress symbolic() const {
         MOZ_ASSERT(!isFixed());
         return SymbolicAddress(payload_ >> 1);
     }
 };
 
 // Iterates over the frames of a single wasm JitActivation, given an
-// asynchronously-interrupted thread's state.
+// asynchronously-profiled thread's state.
 class ProfilingFrameIterator
 {
     const Code* code_;
     const CodeRange* codeRange_;
     Frame* callerFP_;
     void* callerPC_;
     void* stackAddress_;
     uint8_t* unwoundIonCallerFP_;
@@ -212,22 +206,20 @@ GenerateExitEpilogue(jit::MacroAssembler
 void
 GenerateJitExitPrologue(jit::MacroAssembler& masm, unsigned framePushed, CallableOffsets* offsets);
 void
 GenerateJitExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, CallableOffsets* offsets);
 
 void
 GenerateJitEntryPrologue(jit::MacroAssembler& masm, Offsets* offsets);
 
-typedef bool IsLeaf;
-
 void
-GenerateFunctionPrologue(jit::MacroAssembler& masm, uint32_t framePushed, IsLeaf isLeaf,
-                         const SigIdDesc& sigId, BytecodeOffset trapOffset, FuncOffsets* offsets,
-                         const mozilla::Maybe<uint32_t>& tier1FuncIndex = mozilla::Nothing());
+GenerateFunctionPrologue(jit::MacroAssembler& masm, const SigIdDesc& sigId,
+                         const mozilla::Maybe<uint32_t>& tier1FuncIndex,
+                         FuncOffsets* offsets);
 void
 GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);
 
 // Given a fault at pc with register fp, return the faulting instance if there
 // is such a plausible instance, and otherwise null.
 
 Instance*
 LookupFaultingInstance(const ModuleSegment& codeSegment, void* pc, void* fp);
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -545,20 +545,16 @@ ModuleGenerator::noteCodeRange(uint32_t 
       case CodeRange::OutOfBoundsExit:
         MOZ_ASSERT(!linkDataTier_->outOfBoundsOffset);
         linkDataTier_->outOfBoundsOffset = codeRange.begin();
         break;
       case CodeRange::UnalignedExit:
         MOZ_ASSERT(!linkDataTier_->unalignedAccessOffset);
         linkDataTier_->unalignedAccessOffset = codeRange.begin();
         break;
-      case CodeRange::Interrupt:
-        MOZ_ASSERT(!linkDataTier_->interruptOffset);
-        linkDataTier_->interruptOffset = codeRange.begin();
-        break;
       case CodeRange::TrapExit:
         MOZ_ASSERT(!linkDataTier_->trapOffset);
         linkDataTier_->trapOffset = codeRange.begin();
         break;
       case CodeRange::Throw:
         // Jumped to by other stubs, so nothing to do.
         break;
       case CodeRange::FarJumpIsland:
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -401,17 +401,17 @@ Instance::Instance(JSContext* cx,
     MOZ_ASSERT(tables_.length() == metadata().tables.length());
 
     tlsData()->memoryBase = memory ? memory->buffer().dataPointerEither().unwrap() : nullptr;
 #ifndef WASM_HUGE_MEMORY
     tlsData()->boundsCheckLimit = memory ? memory->buffer().wasmBoundsCheckLimit() : 0;
 #endif
     tlsData()->instance = this;
     tlsData()->cx = cx;
-    tlsData()->stackLimit = cx->stackLimitForJitCode(JS::StackForUntrustedScript);
+    tlsData()->resetInterrupt(cx);
     tlsData()->jumpTable = code_->tieringJumpTable();
 
     Tier callerTier = code_->bestTier();
 
     for (size_t i = 0; i < metadata(callerTier).funcImports.length(); i++) {
         HandleFunction f = funcImports[i];
         const FuncImport& fi = metadata(callerTier).funcImports[i];
         FuncImportTls& import = funcImportTls(fi);
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -246,18 +246,16 @@ class FunctionCompiler
             }
 
             curBlock_->add(ins);
             curBlock_->initSlot(info().localSlot(i), ins);
             if (!mirGen_.ensureBallast())
                 return false;
         }
 
-        addInterruptCheck();
-
         return true;
     }
 
     void finish()
     {
         mirGen().initWasmMaxStackArgBytes(maxStackArgBytes_);
 
         MOZ_ASSERT(callStack_.empty());
@@ -1030,18 +1028,19 @@ class FunctionCompiler
     {
         if (inDeadCode())
             return;
         curBlock_->add(MWasmStoreGlobalVar::New(alloc(), globalDataOffset, v, tlsPointer_));
     }
 
     void addInterruptCheck()
     {
-        // We rely on signal handlers for interrupts on Asm.JS/Wasm
-        MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
+        if (inDeadCode())
+            return;
+        curBlock_->add(MWasmInterruptCheck::New(alloc(), tlsPointer_, bytecodeOffset()));
     }
 
     MDefinition* extractSimdElement(unsigned lane, MDefinition* base, MIRType type, SimdSign sign)
     {
         if (inDeadCode())
             return nullptr;
 
         MOZ_ASSERT(IsSimdType(base->type()));
--- a/js/src/wasm/WasmModule.h
+++ b/js/src/wasm/WasmModule.h
@@ -37,17 +37,16 @@ struct CompileArgs;
 //
 // LinkData is built incrementally by ModuleGenerator and then stored immutably
 // in Module. LinkData is distinct from Metadata in that LinkData is owned and
 // destroyed by the Module since it is not needed after instantiation; Metadata
 // is needed at runtime.
 
 struct LinkDataTierCacheablePod
 {
-    uint32_t interruptOffset;
     uint32_t outOfBoundsOffset;
     uint32_t unalignedAccessOffset;
     uint32_t trapOffset;
 
     LinkDataTierCacheablePod() { mozilla::PodZero(this); }
 };
 
 struct LinkDataTier : LinkDataTierCacheablePod
--- a/js/src/wasm/WasmProcess.cpp
+++ b/js/src/wasm/WasmProcess.cpp
@@ -45,25 +45,24 @@ class ProcessCodeSegmentMap
     // Since writes (insertions or removals) can happen on any background
     // thread at the same time, we need a lock here.
 
     Mutex mutatorsMutex_;
 
     CodeSegmentVector segments1_;
     CodeSegmentVector segments2_;
 
-    // Because of sampling/interruptions/stack iteration in general, the
-    // thread running wasm might need to know to which CodeSegment the
-    // current PC belongs, during a call to lookup(). A lookup is a
-    // read-only operation, and we don't want to take a lock then
+    // Because of profiling, the thread running wasm might need to know to which
+    // CodeSegment the current PC belongs, during a call to lookup(). A lookup
+    // is a read-only operation, and we don't want to take a lock then
     // (otherwise, we could have a deadlock situation if an async lookup
     // happened on a given thread that was holding mutatorsMutex_ while getting
-    // interrupted/sampled). Since the writer could be modifying the data that
-    // is getting looked up, the writer functions use spin-locks to know if
-    // there are any observers (i.e. calls to lookup()) of the atomic data.
+    // sampled). Since the writer could be modifying the data that is getting
+    // looked up, the writer functions use spin-locks to know if there are any
+    // observers (i.e. calls to lookup()) of the atomic data.
 
     Atomic<size_t> observers_;
 
     // Except during swapAndWait(), there are no lookup() observers of the
     // vector pointed to by mutableCodeSegments_
 
     CodeSegmentVector* mutableCodeSegments_;
     Atomic<const CodeSegmentVector*> readonlyCodeSegments_;
--- a/js/src/wasm/WasmProcess.h
+++ b/js/src/wasm/WasmProcess.h
@@ -25,17 +25,17 @@ namespace js {
 namespace wasm {
 
 class Code;
 class CodeRange;
 class CodeSegment;
 
 // These methods return the wasm::CodeSegment (resp. wasm::Code) containing
 // the given pc, if any exist in the process. These methods do not take a lock,
-// and thus are safe to use in a profiling or async interrupt context.
+// and thus are safe to use in a profiling context.
 
 const CodeSegment*
 LookupCodeSegment(const void* pc, const CodeRange** codeRange = nullptr);
 
 const Code*
 LookupCode(const void* pc, const CodeRange** codeRange = nullptr);
 
 // A bool member that can be used as a very fast lookup to know if there is any
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -26,30 +26,42 @@
 #include "jit/AtomicOperations.h"
 #include "jit/Disassembler.h"
 #include "vm/Runtime.h"
 #include "wasm/WasmBuiltins.h"
 #include "wasm/WasmInstance.h"
 
 #include "vm/ArrayBufferObject-inl.h"
 
+#if defined(XP_WIN)
+# include "util/Windows.h"
+#else
+# include <signal.h>
+# include <sys/mman.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# include <sys/ucontext.h> // for ucontext_t, mcontext_t
+#endif
+
+#if defined(__x86_64__)
+# if defined(__DragonFly__)
+#  include <machine/npx.h> // for union savefpu
+# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
+       defined(__NetBSD__) || defined(__OpenBSD__)
+#  include <machine/fpu.h> // for struct savefpu/fxsave64
+# endif
+#endif
+
 using namespace js;
 using namespace js::jit;
 using namespace js::wasm;
 
 using JS::GenericNaN;
 using mozilla::DebugOnly;
-using mozilla::PodArrayZero;
-
-#if defined(ANDROID)
-# include <sys/system_properties.h>
-# if defined(MOZ_LINKER)
-extern "C" MFBT_API bool IsSignalHandlingBroken();
-# endif
-#endif
 
 // Crashing inside the signal handler can cause the handler to be recursively
 // invoked, eventually blowing the stack without actually showing a crash
 // report dialog via Breakpad. To guard against this we watch for such
 // recursion and fall through to the next handler immediately rather than
 // trying to handle it.
 
 static MOZ_THREAD_LOCAL(bool) sAlreadyInSignalHandler;
@@ -252,48 +264,30 @@ struct AutoSignalHandler
 #  define RLR_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_lr)
 #  define R31_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_sp)
 # endif
 # if defined(__FreeBSD__) && defined(__mips__)
 #  define EPC_sig(p) ((p)->uc_mcontext.mc_pc)
 #  define RFP_sig(p) ((p)->uc_mcontext.mc_regs[30])
 # endif
 #elif defined(XP_DARWIN)
-# define EIP_sig(p) ((p)->uc_mcontext->__ss.__eip)
-# define EBP_sig(p) ((p)->uc_mcontext->__ss.__ebp)
-# define ESP_sig(p) ((p)->uc_mcontext->__ss.__esp)
-# define RIP_sig(p) ((p)->uc_mcontext->__ss.__rip)
-# define RBP_sig(p) ((p)->uc_mcontext->__ss.__rbp)
-# define RSP_sig(p) ((p)->uc_mcontext->__ss.__rsp)
-# define R14_sig(p) ((p)->uc_mcontext->__ss.__lr)
-# define R15_sig(p) ((p)->uc_mcontext->__ss.__pc)
+# define EIP_sig(p) ((p)->thread.uts.ts32.__eip)
+# define EBP_sig(p) ((p)->thread.uts.ts32.__ebp)
+# define ESP_sig(p) ((p)->thread.uts.ts32.__esp)
+# define RIP_sig(p) ((p)->thread.__rip)
+# define RBP_sig(p) ((p)->thread.__rbp)
+# define RSP_sig(p) ((p)->thread.__rsp)
+# define R11_sig(p) ((p)->thread.__r[11])
+# define R13_sig(p) ((p)->thread.__sp)
+# define R14_sig(p) ((p)->thread.__lr)
+# define R15_sig(p) ((p)->thread.__pc)
 #else
 # error "Don't know how to read/write to the thread state via the mcontext_t."
 #endif
 
-#if defined(XP_WIN)
-# include "util/Windows.h"
-#else
-# include <signal.h>
-# include <sys/mman.h>
-#endif
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-# include <sys/ucontext.h> // for ucontext_t, mcontext_t
-#endif
-
-#if defined(__x86_64__)
-# if defined(__DragonFly__)
-#  include <machine/npx.h> // for union savefpu
-# elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
-       defined(__NetBSD__) || defined(__OpenBSD__)
-#  include <machine/fpu.h> // for struct savefpu/fxsave64
-# endif
-#endif
-
 #if defined(ANDROID)
 // Not all versions of the Android NDK define ucontext_t or mcontext_t.
 // Detect this and provide custom but compatible definitions. Note that these
 // follow the GLibc naming convention to access register values from
 // mcontext_t.
 //
 // See: https://chromiumcodereview.appspot.com/10829122/
 // See: http://code.google.com/p/android/issues/detail?id=34784
@@ -364,48 +358,40 @@ typedef struct ucontext {
     mcontext_t uc_mcontext;
     // Other fields are not used by V8, don't define them here.
 } ucontext_t;
 enum { REG_EIP = 14 };
 #  endif  // defined(__i386__)
 # endif  // !defined(__BIONIC_HAVE_UCONTEXT_T)
 #endif // defined(ANDROID)
 
-#if !defined(XP_WIN)
-# define CONTEXT ucontext_t
-#endif
-
-// Define a context type for use in the emulator code. This is usually just
-// the same as CONTEXT, but on Mac we use a different structure since we call
-// into the emulator code from a Mach exception handler rather than a
-// sigaction-style signal handler.
 #if defined(XP_DARWIN)
 # if defined(__x86_64__)
 struct macos_x64_context {
     x86_thread_state64_t thread;
     x86_float_state64_t float_;
 };
-#  define EMULATOR_CONTEXT macos_x64_context
+#  define CONTEXT macos_x64_context
 # elif defined(__i386__)
 struct macos_x86_context {
     x86_thread_state_t thread;
     x86_float_state_t float_;
 };
-#  define EMULATOR_CONTEXT macos_x86_context
+#  define CONTEXT macos_x86_context
 # elif defined(__arm__)
 struct macos_arm_context {
     arm_thread_state_t thread;
     arm_neon_state_t float_;
 };
-#  define EMULATOR_CONTEXT macos_arm_context
+#  define CONTEXT macos_arm_context
 # else
 #  error Unsupported architecture
 # endif
-#else
-# define EMULATOR_CONTEXT CONTEXT
+#elif !defined(XP_WIN)
+# define CONTEXT ucontext_t
 #endif
 
 #if defined(_M_X64) || defined(__x86_64__)
 # define PC_sig(p) RIP_sig(p)
 # define FP_sig(p) RBP_sig(p)
 # define SP_sig(p) RSP_sig(p)
 #elif defined(_M_IX86) || defined(__i386__)
 # define PC_sig(p) EIP_sig(p)
@@ -423,144 +409,72 @@ struct macos_arm_context {
 # define LR_sig(p) RLR_sig(p)
 #elif defined(__mips__)
 # define PC_sig(p) EPC_sig(p)
 # define FP_sig(p) RFP_sig(p)
 # define SP_sig(p) RSP_sig(p)
 # define LR_sig(p) R31_sig(p)
 #endif
 
-#if defined(PC_sig) && defined(FP_sig) && defined(SP_sig)
-# define KNOWS_MACHINE_STATE
-#endif
-
 static uint8_t**
 ContextToPC(CONTEXT* context)
 {
-#ifdef KNOWS_MACHINE_STATE
+#ifdef PC_sig
     return reinterpret_cast<uint8_t**>(&PC_sig(context));
 #else
     MOZ_CRASH();
 #endif
 }
 
 static uint8_t*
 ContextToFP(CONTEXT* context)
 {
-#ifdef KNOWS_MACHINE_STATE
+#ifdef FP_sig
     return reinterpret_cast<uint8_t*>(FP_sig(context));
 #else
     MOZ_CRASH();
 #endif
 }
 
-#ifdef KNOWS_MACHINE_STATE
 static uint8_t*
 ContextToSP(CONTEXT* context)
 {
+#ifdef SP_sig
     return reinterpret_cast<uint8_t*>(SP_sig(context));
+#else
+    MOZ_CRASH();
+#endif
 }
 
-# if defined(__arm__) || defined(__aarch64__) || defined(__mips__)
+#if defined(__arm__) || defined(__aarch64__) || defined(__mips__)
 static uint8_t*
 ContextToLR(CONTEXT* context)
 {
+# ifdef LR_sig
     return reinterpret_cast<uint8_t*>(LR_sig(context));
-}
-# endif
-#endif // KNOWS_MACHINE_STATE
-
-#if defined(XP_DARWIN)
-
-static uint8_t**
-ContextToPC(EMULATOR_CONTEXT* context)
-{
-# if defined(__x86_64__)
-    static_assert(sizeof(context->thread.__rip) == sizeof(void*),
-                  "stored IP should be compile-time pointer-sized");
-    return reinterpret_cast<uint8_t**>(&context->thread.__rip);
-# elif defined(__i386__)
-    static_assert(sizeof(context->thread.uts.ts32.__eip) == sizeof(void*),
-                  "stored IP should be compile-time pointer-sized");
-    return reinterpret_cast<uint8_t**>(&context->thread.uts.ts32.__eip);
-# elif defined(__arm__)
-    static_assert(sizeof(context->thread.__pc) == sizeof(void*),
-                  "stored IP should be compile-time pointer-sized");
-    return reinterpret_cast<uint8_t**>(&context->thread.__pc);
 # else
-#  error Unsupported architecture
+    MOZ_CRASH();
 # endif
 }
-
-static uint8_t*
-ContextToFP(EMULATOR_CONTEXT* context)
-{
-# if defined(__x86_64__)
-    return (uint8_t*)context->thread.__rbp;
-# elif defined(__i386__)
-    return (uint8_t*)context->thread.uts.ts32.__ebp;
-# elif defined(__arm__)
-    return (uint8_t*)context->thread.__r[11];
-# else
-#  error Unsupported architecture
-# endif
-}
-
-# if defined(__arm__) || defined(__aarch64__)
-static uint8_t*
-ContextToLR(EMULATOR_CONTEXT* context)
-{
-    return (uint8_t*)context->thread.__lr;
-}
-# endif
-
-static uint8_t*
-ContextToSP(EMULATOR_CONTEXT* context)
-{
-# if defined(__x86_64__)
-    return (uint8_t*)context->thread.__rsp;
-# elif defined(__i386__)
-    return (uint8_t*)context->thread.uts.ts32.__esp;
-# elif defined(__arm__)
-    return (uint8_t*)context->thread.__sp;
-# else
-#  error Unsupported architecture
-# endif
-}
+#endif
 
 static JS::ProfilingFrameIterator::RegisterState
-ToRegisterState(EMULATOR_CONTEXT* context)
+ToRegisterState(CONTEXT* context)
 {
     JS::ProfilingFrameIterator::RegisterState state;
     state.fp = ContextToFP(context);
     state.pc = *ContextToPC(context);
     state.sp = ContextToSP(context);
-# if defined(__arm__) || defined(__aarch64__)
+#if defined(__arm__) || defined(__aarch64__) || defined(__mips__)
     state.lr = ContextToLR(context);
-# endif
+#else
+    state.lr = (void*)UINTPTR_MAX;
+#endif
     return state;
 }
-#endif // XP_DARWIN
-
-static JS::ProfilingFrameIterator::RegisterState
-ToRegisterState(CONTEXT* context)
-{
-#ifdef KNOWS_MACHINE_STATE
-    JS::ProfilingFrameIterator::RegisterState state;
-    state.fp = ContextToFP(context);
-    state.pc = *ContextToPC(context);
-    state.sp = ContextToSP(context);
-# if defined(__arm__) || defined(__aarch64__) || defined(__mips__)
-    state.lr = ContextToLR(context);
-# endif
-    return state;
-#else
-    MOZ_CRASH();
-#endif
-}
 
 #if defined(WASM_HUGE_MEMORY)
 MOZ_COLD static void
 SetFPRegToNaN(size_t size, void* fp_reg)
 {
     MOZ_RELEASE_ASSERT(size <= Simd128DataSize);
     memset(fp_reg, 0, Simd128DataSize);
     switch (size) {
@@ -648,17 +562,17 @@ AddressOfFPRegisterSlot(CONTEXT* context
       case X86Encoding::xmm14: return &XMM_sig(context, 14);
       case X86Encoding::xmm15: return &XMM_sig(context, 15);
       default: break;
     }
     MOZ_CRASH();
 }
 
 MOZ_COLD static void*
-AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
+AddressOfGPRegisterSlot(CONTEXT* context, Registers::Code code)
 {
     switch (code) {
       case X86Encoding::rax: return &RAX_sig(context);
       case X86Encoding::rcx: return &RCX_sig(context);
       case X86Encoding::rdx: return &RDX_sig(context);
       case X86Encoding::rbx: return &RBX_sig(context);
       case X86Encoding::rsp: return &RSP_sig(context);
       case X86Encoding::rbp: return &RBP_sig(context);
@@ -673,17 +587,17 @@ AddressOfGPRegisterSlot(EMULATOR_CONTEXT
       case X86Encoding::r14: return &R14_sig(context);
       case X86Encoding::r15: return &R15_sig(context);
       default: break;
     }
     MOZ_CRASH();
 }
 # else
 MOZ_COLD static void*
-AddressOfFPRegisterSlot(EMULATOR_CONTEXT* context, FloatRegisters::Encoding encoding)
+AddressOfFPRegisterSlot(CONTEXT* context, FloatRegisters::Encoding encoding)
 {
     switch (encoding) {
       case X86Encoding::xmm0:  return &context->float_.__fpu_xmm0;
       case X86Encoding::xmm1:  return &context->float_.__fpu_xmm1;
       case X86Encoding::xmm2:  return &context->float_.__fpu_xmm2;
       case X86Encoding::xmm3:  return &context->float_.__fpu_xmm3;
       case X86Encoding::xmm4:  return &context->float_.__fpu_xmm4;
       case X86Encoding::xmm5:  return &context->float_.__fpu_xmm5;
@@ -698,17 +612,17 @@ AddressOfFPRegisterSlot(EMULATOR_CONTEXT
       case X86Encoding::xmm14: return &context->float_.__fpu_xmm14;
       case X86Encoding::xmm15: return &context->float_.__fpu_xmm15;
       default: break;
     }
     MOZ_CRASH();
 }
 
 MOZ_COLD static void*
-AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
+AddressOfGPRegisterSlot(CONTEXT* context, Registers::Code code)
 {
     switch (code) {
       case X86Encoding::rax: return &context->thread.__rax;
       case X86Encoding::rcx: return &context->thread.__rcx;
       case X86Encoding::rdx: return &context->thread.__rdx;
       case X86Encoding::rbx: return &context->thread.__rbx;
       case X86Encoding::rsp: return &context->thread.__rsp;
       case X86Encoding::rbp: return &context->thread.__rbp;
@@ -724,69 +638,69 @@ AddressOfGPRegisterSlot(EMULATOR_CONTEXT
       case X86Encoding::r15: return &context->thread.__r15;
       default: break;
     }
     MOZ_CRASH();
 }
 # endif  // !XP_DARWIN
 #elif defined(JS_CODEGEN_ARM64)
 MOZ_COLD static void*
-AddressOfFPRegisterSlot(EMULATOR_CONTEXT* context, FloatRegisters::Encoding encoding)
+AddressOfFPRegisterSlot(CONTEXT* context, FloatRegisters::Encoding encoding)
 {
     MOZ_CRASH("NYI - asm.js not supported yet on this platform");
 }
 
 MOZ_COLD static void*
-AddressOfGPRegisterSlot(EMULATOR_CONTEXT* context, Registers::Code code)
+AddressOfGPRegisterSlot(CONTEXT* context, Registers::Code code)
 {
     MOZ_CRASH("NYI - asm.js not supported yet on this platform");
 }
 #endif
 
 MOZ_COLD static void
-SetRegisterToCoercedUndefined(EMULATOR_CONTEXT* context, size_t size,
+SetRegisterToCoercedUndefined(CONTEXT* context, size_t size,
                               const Disassembler::OtherOperand& value)
 {
     if (value.kind() == Disassembler::OtherOperand::FPR)
         SetFPRegToNaN(size, AddressOfFPRegisterSlot(context, value.fpr()));
     else
         SetGPRegToZero(AddressOfGPRegisterSlot(context, value.gpr()));
 }
 
 MOZ_COLD static void
-SetRegisterToLoadedValue(EMULATOR_CONTEXT* context, SharedMem<void*> addr, size_t size,
+SetRegisterToLoadedValue(CONTEXT* context, SharedMem<void*> addr, size_t size,
                          const Disassembler::OtherOperand& value)
 {
     if (value.kind() == Disassembler::OtherOperand::FPR)
         SetFPRegToLoadedValue(addr, size, AddressOfFPRegisterSlot(context, value.fpr()));
     else
         SetGPRegToLoadedValue(addr, size, AddressOfGPRegisterSlot(context, value.gpr()));
 }
 
 MOZ_COLD static void
-SetRegisterToLoadedValueSext32(EMULATOR_CONTEXT* context, SharedMem<void*> addr, size_t size,
+SetRegisterToLoadedValueSext32(CONTEXT* context, SharedMem<void*> addr, size_t size,
                                const Disassembler::OtherOperand& value)
 {
     SetGPRegToLoadedValueSext32(addr, size, AddressOfGPRegisterSlot(context, value.gpr()));
 }
 
 MOZ_COLD static void
-StoreValueFromRegister(EMULATOR_CONTEXT* context, SharedMem<void*> addr, size_t size,
+StoreValueFromRegister(CONTEXT* context, SharedMem<void*> addr, size_t size,
                        const Disassembler::OtherOperand& value)
 {
     if (value.kind() == Disassembler::OtherOperand::FPR)
         StoreValueFromFPReg(addr, size, AddressOfFPRegisterSlot(context, value.fpr()));
     else if (value.kind() == Disassembler::OtherOperand::GPR)
         StoreValueFromGPReg(addr, size, AddressOfGPRegisterSlot(context, value.gpr()));
     else
         StoreValueFromGPImm(addr, size, value.imm());
 }
 
 MOZ_COLD static uint8_t*
-ComputeAccessAddress(EMULATOR_CONTEXT* context, const Disassembler::ComplexAddress& address)
+ComputeAccessAddress(CONTEXT* context, const Disassembler::ComplexAddress& address)
 {
     MOZ_RELEASE_ASSERT(!address.isPCRelative(), "PC-relative addresses not supported yet");
 
     uintptr_t result = address.disp();
 
     if (address.hasBase()) {
         uintptr_t base;
         StoreValueFromGPReg(SharedMem<void*>::unshared(&base), sizeof(uintptr_t),
@@ -801,29 +715,29 @@ ComputeAccessAddress(EMULATOR_CONTEXT* c
         MOZ_ASSERT(address.scale() < 32, "address shift overflow");
         result += index * (uintptr_t(1) << address.scale());
     }
 
     return reinterpret_cast<uint8_t*>(result);
 }
 
 MOZ_COLD static void
-HandleMemoryAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddress,
+HandleMemoryAccess(CONTEXT* context, uint8_t* pc, uint8_t* faultingAddress,
                    const ModuleSegment* segment, const Instance& instance, JitActivation* activation,
                    uint8_t** ppc)
 {
     MOZ_RELEASE_ASSERT(instance.code().containsCodePC(pc));
 
     const MemoryAccess* memoryAccess = instance.code().lookupMemoryAccess(pc);
     if (!memoryAccess) {
         // If there is no associated MemoryAccess for the faulting PC, this must be
         // experimental SIMD.js or Atomics. When these are converted to
         // non-experimental wasm features, this case, as well as outOfBoundsCode,
         // can be removed.
-        MOZ_ALWAYS_TRUE(activation->startWasmInterrupt(ToRegisterState(context)));
+        activation->startWasmTrap(wasm::Trap::OutOfBounds, 0, ToRegisterState(context));
         *ppc = segment->outOfBoundsCode();
         return;
     }
 
     MOZ_RELEASE_ASSERT(memoryAccess->insnOffset() == (pc - segment->base()));
 
     // On WASM_HUGE_MEMORY platforms, asm.js code may fault. asm.js does not
     // trap on fault and so has no trap out-of-line path. Instead, stores are
@@ -957,26 +871,26 @@ HandleMemoryAccess(EMULATOR_CONTEXT* con
     }
 
     *ppc = end;
 }
 
 #else // WASM_HUGE_MEMORY
 
 MOZ_COLD static void
-HandleMemoryAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddress,
+HandleMemoryAccess(CONTEXT* context, uint8_t* pc, uint8_t* faultingAddress,
                    const ModuleSegment* segment, const Instance& instance, JitActivation* activation,
                    uint8_t** ppc)
 {
     MOZ_RELEASE_ASSERT(instance.code().containsCodePC(pc));
 
     const MemoryAccess* memoryAccess = instance.code().lookupMemoryAccess(pc);
     if (!memoryAccess) {
         // See explanation in the WASM_HUGE_MEMORY HandleMemoryAccess.
-        MOZ_ALWAYS_TRUE(activation->startWasmInterrupt(ToRegisterState(context)));
+        activation->startWasmTrap(wasm::Trap::OutOfBounds, 0, ToRegisterState(context));
         *ppc = segment->outOfBoundsCode();
         return;
     }
 
     MOZ_RELEASE_ASSERT(memoryAccess->hasTrapOutOfLineCode());
     *ppc = memoryAccess->trapOutOfLineCode(segment->base());
 }
 
@@ -1014,43 +928,18 @@ HandleFault(PEXCEPTION_POINTERS exceptio
         return false;
 
     const ModuleSegment* moduleSegment = codeSegment->asModule();
 
     JitActivation* activation = TlsContext.get()->activation()->asJit();
     MOZ_ASSERT(activation);
 
     const Instance* instance = LookupFaultingInstance(*moduleSegment, pc, ContextToFP(context));
-    if (!instance) {
-        // On Windows, it is possible for InterruptRunningJitCode to execute
-        // between a faulting instruction and the handling of the fault due
-        // to InterruptRunningJitCode's use of SuspendThread. When this happens,
-        // after ResumeThread, the exception handler is called with pc equal to
-        // ModuleSegment.interrupt, which is logically wrong. The Right Thing would
-        // be for the OS to make fault-handling atomic (so that CONTEXT.pc was
-        // always the logically-faulting pc). Fortunately, we can detect this
-        // case and silence the exception ourselves (the exception will
-        // retrigger after the interrupt jumps back to resumePC).
-        return activation->isWasmInterrupted() &&
-               pc == moduleSegment->interruptCode() &&
-               moduleSegment->containsCodePC(activation->wasmInterruptResumePC());
-    }
-
-    // In the same race-with-interrupt situation above, it's *also* possible
-    // that the reported 'pc' is the pre-interrupt pc, not post-interrupt
-    // moduleSegment->interruptCode (this may be windows-version-specific). In
-    // this case, lookupTrap()/lookupMemoryAccess() will all succeed causing the
-    // pc to be redirected *again* (to a trap stub), leading to the interrupt
-    // stub never being called. Since the goal of the async interrupt is to break
-    // out iloops and trapping does just that, this is fine, we just clear the
-    // "interrupted" state.
-    if (activation->isWasmInterrupted()) {
-        MOZ_ASSERT(activation->wasmInterruptResumePC() == pc);
-        activation->finishWasmInterrupt();
-    }
+    if (!instance)
+        return false;
 
     if (record->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
         Trap trap;
         BytecodeOffset bytecode;
         if (!moduleSegment->code().lookupTrap(pc, &trap, &bytecode))
             return false;
 
         activation->startWasmTrap(trap, bytecode.offset, ToRegisterState(context));
@@ -1120,17 +1009,17 @@ struct ExceptionRequest
 
 static bool
 HandleMachException(JSContext* cx, const ExceptionRequest& request)
 {
     // Get the port of the JSContext's thread from the message.
     mach_port_t cxThread = request.body.thread.name;
 
     // Read out the JSRuntime thread's register state.
-    EMULATOR_CONTEXT context;
+    CONTEXT context;
 # if defined(__x86_64__)
     unsigned int thread_state_count = x86_THREAD_STATE64_COUNT;
     unsigned int float_state_count = x86_FLOAT_STATE64_COUNT;
     int thread_state = x86_THREAD_STATE64;
     int float_state = x86_FLOAT_STATE64;
 # elif defined(__i386__)
     unsigned int thread_state_count = x86_THREAD_STATE_COUNT;
     unsigned int float_state_count = x86_FLOAT_STATE_COUNT;
@@ -1441,17 +1330,17 @@ HandleFault(int signum, siginfo_t* info,
     }
 
 #ifdef JS_CODEGEN_ARM
     if (signum == SIGBUS) {
         // TODO: We may see a bus error for something that is an unaligned access that
         // partly overlaps the end of the heap.  In this case, it is an out-of-bounds
         // error and we should signal that properly, but to do so we must inspect
         // the operand of the failed access.
-        MOZ_ALWAYS_TRUE(activation->startWasmInterrupt(ToRegisterState(context)));
+        activation->startWasmTrap(wasm::Trap::UnalignedAccess, 0, ToRegisterState(context));
         *ppc = moduleSegment->unalignedAccessCode();
         return true;
     }
 #endif
 
     HandleMemoryAccess(context, pc, faultingAddress, moduleSegment, *instance, activation, ppc);
     return true;
 }
@@ -1490,240 +1379,91 @@ WasmFaultHandler(int signum, siginfo_t* 
         previousSignal->sa_sigaction(signum, info, context);
     else if (previousSignal->sa_handler == SIG_DFL || previousSignal->sa_handler == SIG_IGN)
         sigaction(signum, previousSignal, nullptr);
     else
         previousSignal->sa_handler(signum);
 }
 # endif // XP_WIN || XP_DARWIN || assume unix
 
-static void
-RedirectIonBackedgesToInterruptCheck(JSContext* cx)
-{
-    if (!cx->runtime()->hasJitRuntime())
-        return;
-    jit::JitRuntime* jitRuntime = cx->runtime()->jitRuntime();
-    Zone* zone = cx->zoneRaw();
-    if (zone && !zone->isAtomsZone()) {
-        // If the backedge list is being mutated, the pc must be in C++ code and
-        // thus not in a JIT iloop. We assume that the interrupt flag will be
-        // checked at least once before entering JIT code (if not, no big deal;
-        // the browser will just request another interrupt in a second).
-        if (!jitRuntime->preventBackedgePatching()) {
-            jit::JitZoneGroup* jzg = zone->group()->jitZoneGroup;
-            jzg->patchIonBackedges(cx, jit::JitZoneGroup::BackedgeInterruptCheck);
-        }
-    }
-}
-
-bool
-wasm::InInterruptibleCode(JSContext* cx, uint8_t* pc, const ModuleSegment** ms)
-{
-    // Only interrupt in function code so that the frame iterators have the
-    // invariant that resumePC always has a function CodeRange and we can't
-    // get into any weird interrupt-during-interrupt-stub cases.
-
-    if (!cx->compartment())
-        return false;
-
-    const CodeSegment* cs = LookupCodeSegment(pc);
-    if (!cs || !cs->isModule())
-        return false;
-
-    *ms = cs->asModule();
-    return !!(*ms)->code().lookupFuncRange(pc);
-}
-
-// The return value indicates whether the PC was changed, not whether there was
-// a failure.
-static bool
-RedirectJitCodeToInterruptCheck(JSContext* cx, CONTEXT* context)
-{
-    // Jitcode may only be modified on the runtime's active thread.
-    if (cx != cx->runtime()->activeContext())
-        return false;
-
-    // The faulting thread is suspended so we can access cx fields that can
-    // normally only be accessed by the cx's active thread.
-    AutoNoteSingleThreadedRegion anstr;
-
-    RedirectIonBackedgesToInterruptCheck(cx);
-
-#ifdef JS_SIMULATOR
-    uint8_t* pc = cx->simulator()->get_pc_as<uint8_t*>();
-#else
-    uint8_t* pc = *ContextToPC(context);
-#endif
-
-    const ModuleSegment* moduleSegment = nullptr;
-    if (!InInterruptibleCode(cx, pc, &moduleSegment))
-        return false;
-
-#ifdef JS_SIMULATOR
-    // The checks performed by the !JS_SIMULATOR path happen in
-    // Simulator::handleWasmInterrupt.
-    cx->simulator()->trigger_wasm_interrupt();
-#else
-    // Only probe cx->activation() after we know the pc is in wasm code. This
-    // way we don't depend on signal-safe update of cx->activation().
-    JitActivation* activation = cx->activation()->asJit();
-
-    // The out-of-bounds/unaligned trap paths which call startWasmInterrupt() go
-    // through function code, so test if already interrupted. These paths are
-    // temporary though, so this case can be removed later.
-    if (activation->isWasmInterrupted())
-        return false;
-
-    if (!activation->startWasmInterrupt(ToRegisterState(context)))
-        return false;
-
-    *ContextToPC(context) = moduleSegment->interruptCode();
-#endif
-
-    return true;
-}
-
-#if !defined(XP_WIN)
-// For the interrupt signal, pick a signal number that:
-//  - is not otherwise used by mozilla or standard libraries
-//  - defaults to nostop and noprint on gdb/lldb so that noone is bothered
-// SIGVTALRM a relative of SIGALRM, so intended for user code, but, unlike
-// SIGALRM, not used anywhere else in Mozilla.
-static const int sInterruptSignal = SIGVTALRM;
-
-static void
-JitInterruptHandler(int signum, siginfo_t* info, void* context)
-{
-    if (JSContext* cx = TlsContext.get()) {
-
-#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
-        SimulatorProcess::ICacheCheckingDisableCount++;
-#endif
-
-        RedirectJitCodeToInterruptCheck(cx, (CONTEXT*)context);
-
-#if defined(JS_SIMULATOR_ARM) || defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
-        SimulatorProcess::cacheInvalidatedBySignalHandler_ = true;
-        SimulatorProcess::ICacheCheckingDisableCount--;
-#endif
-
-        cx->finishHandlingJitInterrupt();
-    }
-}
+#if defined(ANDROID) && defined(MOZ_LINKER)
+extern "C" MFBT_API bool IsSignalHandlingBroken();
 #endif
 
 static bool sTriedInstallSignalHandlers = false;
 static bool sHaveSignalHandlers = false;
 
 static bool
 ProcessHasSignalHandlers()
 {
     // We assume that there are no races creating the first JSRuntime of the process.
     if (sTriedInstallSignalHandlers)
         return sHaveSignalHandlers;
     sTriedInstallSignalHandlers = true;
 
-#if defined(ANDROID)
-# if !defined(__aarch64__)
-    // Before Android 4.4 (SDK version 19), there is a bug
-    //   https://android-review.googlesource.com/#/c/52333
-    // in Bionic's pthread_join which causes pthread_join to return early when
-    // pthread_kill is used (on any thread). Nobody expects the pthread_cond_wait
-    // EINTRquisition.
-    char version_string[PROP_VALUE_MAX];
-    PodArrayZero(version_string);
-    if (__system_property_get("ro.build.version.sdk", version_string) > 0) {
-        if (atol(version_string) < 19)
-            return false;
-    }
-# endif
-# if defined(MOZ_LINKER)
+#if defined(ANDROID) && defined(MOZ_LINKER)
     // Signal handling is broken on some android systems.
     if (IsSignalHandlingBroken())
         return false;
-# endif
 #endif
 
-    // The interrupt handler allows the active thread to be paused from another
-    // thread (see InterruptRunningJitCode).
-#if defined(XP_WIN)
-    // Windows uses SuspendThread to stop the active thread from another thread.
-#else
-    struct sigaction interruptHandler;
-    interruptHandler.sa_flags = SA_SIGINFO;
-    interruptHandler.sa_sigaction = &JitInterruptHandler;
-    sigemptyset(&interruptHandler.sa_mask);
-    struct sigaction prev;
-    if (sigaction(sInterruptSignal, &interruptHandler, &prev))
-        MOZ_CRASH("unable to install interrupt handler");
-
-    // There shouldn't be any other handlers installed for sInterruptSignal. If
-    // there are, we could always forward, but we need to understand what we're
-    // doing to avoid problematic interference.
-    if ((prev.sa_flags & SA_SIGINFO && prev.sa_sigaction) ||
-        (prev.sa_handler != SIG_DFL && prev.sa_handler != SIG_IGN))
-    {
-        MOZ_CRASH("contention for interrupt signal");
-    }
-#endif // defined(XP_WIN)
-
     // Initalize ThreadLocal flag used by WasmFaultHandler
     sAlreadyInSignalHandler.infallibleInit();
 
     // Install a SIGSEGV handler to handle safely-out-of-bounds asm.js heap
     // access and/or unaligned accesses.
-# if defined(XP_WIN)
-#  if defined(MOZ_ASAN)
+#if defined(XP_WIN)
+# if defined(MOZ_ASAN)
     // Under ASan we need to let the ASan runtime's ShadowExceptionHandler stay
     // in the first handler position. This requires some coordination with
     // MemoryProtectionExceptionHandler::isDisabled().
     const bool firstHandler = false;
-#  else
+# else
     // Otherwise, WasmFaultHandler needs to go first, so that we can recover
     // from wasm faults and continue execution without triggering handlers
     // such as MemoryProtectionExceptionHandler that assume we are crashing.
     const bool firstHandler = true;
-#  endif
+# endif
     if (!AddVectoredExceptionHandler(firstHandler, WasmFaultHandler))
         return false;
-# elif defined(XP_DARWIN)
+#elif defined(XP_DARWIN)
     // OSX handles seg faults via the Mach exception handler above, so don't
     // install WasmFaultHandler.
-# else
+#else
     // SA_NODEFER allows us to reenter the signal handler if we crash while
     // handling the signal, and fall through to the Breakpad handler by testing
     // handlingSegFault.
 
     // Allow handling OOB with signals on all architectures
     struct sigaction faultHandler;
     faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
     faultHandler.sa_sigaction = WasmFaultHandler;
     sigemptyset(&faultHandler.sa_mask);
     if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler))
         MOZ_CRASH("unable to install segv handler");
 
-#  if defined(JS_CODEGEN_ARM)
+# if defined(JS_CODEGEN_ARM)
     // On Arm Handle Unaligned Accesses
     struct sigaction busHandler;
     busHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
     busHandler.sa_sigaction = WasmFaultHandler;
     sigemptyset(&busHandler.sa_mask);
     if (sigaction(SIGBUS, &busHandler, &sPrevSIGBUSHandler))
         MOZ_CRASH("unable to install sigbus handler");
-#  endif
+# endif
 
     // Install a handler to handle the instructions that are emitted to implement
     // wasm traps.
     struct sigaction wasmTrapHandler;
     wasmTrapHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK;
     wasmTrapHandler.sa_sigaction = WasmFaultHandler;
     sigemptyset(&wasmTrapHandler.sa_mask);
     if (sigaction(kWasmTrapSignal, &wasmTrapHandler, &sPrevWasmTrapHandler))
         MOZ_CRASH("unable to install wasm trap handler");
-# endif
+#endif
 
     sHaveSignalHandlers = true;
     return true;
 }
 
 bool
 wasm::EnsureSignalHandlers(JSContext* cx)
 {
@@ -1741,66 +1481,8 @@ wasm::EnsureSignalHandlers(JSContext* cx
 }
 
 bool
 wasm::HaveSignalHandlers()
 {
     MOZ_ASSERT(sTriedInstallSignalHandlers);
     return sHaveSignalHandlers;
 }
-
-// JSRuntime::requestInterrupt sets interrupt_ (which is checked frequently by
-// C++ code at every Baseline JIT loop backedge) and jitStackLimit_ (which is
-// checked at every Baseline and Ion JIT function prologue). The remaining
-// sources of potential iloops (Ion loop backedges and all wasm code) are
-// handled by this function:
-//  1. Ion loop backedges are patched to instead point to a stub that handles
-//     the interrupt;
-//  2. if the active thread's pc is inside wasm code, the pc is updated to point
-//     to a stub that handles the interrupt.
-void
-js::InterruptRunningJitCode(JSContext* cx)
-{
-    // If signal handlers weren't installed, then Ion and wasm emit normal
-    // interrupt checks and don't need asynchronous interruption.
-    if (!HaveSignalHandlers())
-        return;
-
-    // Do nothing if we're already handling an interrupt here, to avoid races
-    // below and in JitRuntime::patchIonBackedges.
-    if (!cx->startHandlingJitInterrupt())
-        return;
-
-    // If we are on context's thread, then: pc is not in wasm code (so nothing
-    // to do for wasm) and we can patch Ion backedges without any special
-    // synchronization.
-    if (cx == TlsContext.get()) {
-        RedirectIonBackedgesToInterruptCheck(cx);
-        cx->finishHandlingJitInterrupt();
-        return;
-    }
-
-    // We are not on the runtime's active thread, so to do 1 and 2 above, we need
-    // to halt the runtime's active thread first.
-#if defined(XP_WIN)
-    // On Windows, we can simply suspend the active thread and work directly on
-    // its context from this thread. SuspendThread can sporadically fail if the
-    // thread is in the middle of a syscall. Rather than retrying in a loop,
-    // just wait for the next request for interrupt.
-    HANDLE thread = (HANDLE)cx->threadNative();
-    if (SuspendThread(thread) != (DWORD)-1) {
-        CONTEXT context;
-        context.ContextFlags = CONTEXT_FULL;
-        if (GetThreadContext(thread, &context)) {
-            if (RedirectJitCodeToInterruptCheck(cx, &context))
-                SetThreadContext(thread, &context);
-        }
-        ResumeThread(thread);
-    }
-    cx->finishHandlingJitInterrupt();
-#else
-    // On Unix, we instead deliver an async signal to the active thread which
-    // halts the thread and callers our JitInterruptHandler (which has already
-    // been installed by EnsureSignalHandlersInstalled).
-    pthread_t thread = (pthread_t)cx->threadNative();
-    pthread_kill(thread, sInterruptSignal);
-#endif
-}
--- a/js/src/wasm/WasmSignalHandlers.h
+++ b/js/src/wasm/WasmSignalHandlers.h
@@ -25,41 +25,29 @@
 # include <mach/mach.h>
 #endif
 
 #include "js/TypeDecls.h"
 #include "threading/Thread.h"
 #include "wasm/WasmTypes.h"
 
 namespace js {
-
-// Force any currently-executing asm.js/ion code to call HandleExecutionInterrupt.
-extern void
-InterruptRunningJitCode(JSContext* cx);
-
 namespace wasm {
 
 // Ensure the given JSRuntime is set up to use signals. Failure to enable signal
 // handlers indicates some catastrophic failure and creation of the runtime must
 // fail.
 MOZ_MUST_USE bool
 EnsureSignalHandlers(JSContext* cx);
 
-// Return whether signals can be used in this process for interrupts or
-// asm.js/wasm out-of-bounds.
+// Return whether signals can be used in this process for asm.js/wasm
+// out-of-bounds.
 bool
 HaveSignalHandlers();
 
-class ModuleSegment;
-
-// Returns true if wasm code is on top of the activation stack (and fills out
-// the code segment outparam in this case), or false otherwise.
-bool
-InInterruptibleCode(JSContext* cx, uint8_t* pc, const ModuleSegment** ms);
-
 #if defined(XP_DARWIN)
 // On OSX we are forced to use the lower-level Mach exception mechanism instead
 // of Unix signals. Mach exceptions are not handled on the victim's stack but
 // rather require an extra thread. For simplicity, we create one such thread
 // per JSContext (upon the first use of wasm in the JSContext). This thread
 // and related resources are owned by AsmJSMachExceptionHandler which is owned
 // by JSContext.
 class MachExceptionHandler
@@ -74,41 +62,22 @@ class MachExceptionHandler
     MachExceptionHandler();
     ~MachExceptionHandler() { uninstall(); }
     mach_port_t port() const { return port_; }
     bool installed() const { return installed_; }
     bool install(JSContext* cx);
 };
 #endif
 
-// Typed wrappers encapsulating the data saved by the signal handler on async
-// interrupt or trap. On interrupt, the PC at which to resume is saved. On trap,
-// the bytecode offset to be reported in callstacks is saved.
-
-struct InterruptData
-{
-    // The pc to use for unwinding purposes which is kept consistent with fp at
-    // call boundaries.
-    void* unwindPC;
-
-    // The pc at which we should return if the interrupt doesn't stop execution.
-    void* resumePC;
-
-    InterruptData(void* unwindPC, void* resumePC)
-      : unwindPC(unwindPC), resumePC(resumePC)
-    {}
-};
+// On trap, the bytecode offset to be reported in callstacks is saved.
 
 struct TrapData
 {
-    void* pc;
+    void* resumePC;
+    void* unwoundPC;
     Trap trap;
     uint32_t bytecodeOffset;
-
-    TrapData(void* pc, Trap trap, uint32_t bytecodeOffset)
-      : pc(pc), trap(trap), bytecodeOffset(bytecodeOffset)
-    {}
 };
 
 } // namespace wasm
 } // namespace js
 
 #endif // wasm_signal_handlers_h
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -267,25 +267,26 @@ static const unsigned FramePushedBeforeA
 static void
 AssertExpectedSP(const MacroAssembler& masm)
 {
 #ifdef JS_CODEGEN_ARM64
     MOZ_ASSERT(sp.Is(masm.GetStackPointer64()));
 #endif
 }
 
+template <class Operand>
 static void
-WasmPush(MacroAssembler& masm, Register r)
+WasmPush(MacroAssembler& masm, const Operand& op)
 {
 #ifdef JS_CODEGEN_ARM64
     // Allocate a pad word so that SP can remain properly aligned.
     masm.reserveStack(16);
-    masm.storePtr(r, Address(masm.getStackPointer(), 0));
+    masm.storePtr(op, Address(masm.getStackPointer(), 0));
 #else
-    masm.Push(r);
+    masm.Push(op);
 #endif
 }
 
 static void
 WasmPop(MacroAssembler& masm, Register r)
 {
 #ifdef JS_CODEGEN_ARM64
     // Also pop the pad word allocated by WasmPush.
@@ -957,21 +958,22 @@ FillArgumentArray(MacroAssembler& masm, 
 //  - a table entry, so JS imports can be put into tables
 //  - normal entries, so that, if the import is re-exported, an entry stub can
 //    be generated and called without any special cases
 static bool
 GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, SigIdDesc sigId,
                        FuncOffsets* offsets)
 {
     AssertExpectedSP(masm);
-    masm.setFramePushed(0);
+
+    GenerateFunctionPrologue(masm, sigId, Nothing(), offsets);
 
     unsigned framePushed = StackDecrementForCall(masm, WasmStackAlignment, fi.sig().args());
-
-    GenerateFunctionPrologue(masm, framePushed, IsLeaf(false), sigId,  BytecodeOffset(0), offsets);
+    masm.wasmReserveStackChecked(framePushed, BytecodeOffset(0));
+    MOZ_ASSERT(masm.framePushed() == framePushed);
 
     // The argument register state is already setup by our caller. We just need
     // to be sure not to clobber it before the call.
     Register scratch = ABINonArgReg0;
 
     // Copy our frame's stack arguments to the callee frame's stack argument.
     unsigned offsetToCallerStackArgs = sizeof(Frame) + masm.framePushed();
     ABIArgValTypeIter i(fi.sig().args());
@@ -1245,18 +1247,16 @@ GenerateImportJitExit(MacroAssembler& ma
 #endif
 
     // Note that there might be a GC thing in the JSReturnOperand now.
     // In all the code paths from here:
     // - either the value is unboxed because it was a primitive and we don't
     //   need to worry about rooting anymore.
     // - or the value needs to be rooted, but nothing can cause a GC between
     //   here and CoerceInPlace, which roots before coercing to a primitive.
-    //   In particular, this is true because wasm::InInterruptibleCode will
-    //   return false when PC is in the jit exit.
 
     // The JIT callee clobbers all registers, including WasmTlsReg and
     // FramePointer, so restore those here. During this sequence of
     // instructions, FP can't be trusted by the profiling frame iterator.
     offsets->untrustedFPStart = masm.currentOffset();
     AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr + frameAlignExtra);
 
     masm.loadWasmTlsRegFromFrame();
@@ -1482,36 +1482,93 @@ wasm::GenerateBuiltinThunk(MacroAssemble
     if (!UseHardFpABI() && IsFloatingPointType(retType))
         masm.ma_vxfer(r0, r1, d0);
 #endif
 
     GenerateExitEpilogue(masm, framePushed, exitReason, offsets);
     return FinishOffsets(masm, offsets);
 }
 
+#if defined(JS_CODEGEN_ARM)
+static const LiveRegisterSet RegsToPreserve(
+    GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::sp) |
+                                              (uint32_t(1) << Registers::pc))),
+    FloatRegisterSet(FloatRegisters::AllDoubleMask));
+static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too.");
+#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+static const LiveRegisterSet RegsToPreserve(
+    GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::k0) |
+                                              (uint32_t(1) << Registers::k1) |
+                                              (uint32_t(1) << Registers::sp) |
+                                              (uint32_t(1) << Registers::zero))),
+    FloatRegisterSet(FloatRegisters::AllDoubleMask));
+static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too.");
+#elif defined(JS_CODEGEN_ARM64)
+// We assume that traps do not happen while lr is live. This both ensures that
+// the size of RegsToPreserve is a multiple of 2 (preserving WasmStackAlignment)
+// and gives us a register to clobber in the return path.
+static const LiveRegisterSet RegsToPreserve(
+    GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::StackPointer) |
+                                              (uint32_t(1) << Registers::lr))),
+    FloatRegisterSet(FloatRegisters::AllMask));
+#else
+static const LiveRegisterSet RegsToPreserve(
+    GeneralRegisterSet(Registers::AllMask & ~(uint32_t(1) << Registers::StackPointer)),
+    FloatRegisterSet(FloatRegisters::AllMask));
+#endif
+
 // Generate a stub which calls WasmReportTrap() and can be executed by having
 // the signal handler redirect PC from any trapping instruction.
 static bool
 GenerateTrapExit(MacroAssembler& masm, Label* throwLabel, Offsets* offsets)
 {
     AssertExpectedSP(masm);
     masm.haltingAlign(CodeAlignment);
 
+    masm.setFramePushed(0);
+
     offsets->begin = masm.currentOffset();
 
+    // Traps can only happen at well-defined program points. However, since
+    // traps may resume and the optimal assumption for the surrounding code is
+    // that registers are not clobbered, we need to preserve all registers in
+    // the trap exit. One simplifying assumption is that flags may be clobbered.
+    // Push a dummy word to use as return address below.
+    WasmPush(masm, ImmWord(0));
+    unsigned framePushedBeforePreserve = masm.framePushed();
+    masm.PushRegsInMask(RegsToPreserve);
+    unsigned offsetOfReturnWord = masm.framePushed() - framePushedBeforePreserve;
+
     // We know that StackPointer is word-aligned, but not necessarily
     // stack-aligned, so we need to align it dynamically.
+    Register preAlignStackPointer = ABINonVolatileReg;
+    masm.moveStackPtrTo(preAlignStackPointer);
     masm.andToStackPtr(Imm32(~(ABIStackAlignment - 1)));
     if (ShadowStackSpace)
         masm.subFromStackPtr(Imm32(ShadowStackSpace));
 
     masm.assertStackAlignment(ABIStackAlignment);
-    masm.call(SymbolicAddress::ReportTrap);
+    masm.call(SymbolicAddress::HandleTrap);
+
+    // WasmHandleTrap returns null if control should transfer to the throw stub.
+    masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
 
-    masm.jump(throwLabel);
+    // Otherwise, the return value is the TrapData::resumePC we must jump to.
+    // We must restore register state before jumping, which will clobber
+    // ReturnReg, so store ReturnReg in the above-reserved stack slot which we
+    // use to jump to via ret.
+    masm.moveToStackPtr(preAlignStackPointer);
+    masm.storePtr(ReturnReg, Address(masm.getStackPointer(), offsetOfReturnWord));
+    masm.PopRegsInMask(RegsToPreserve);
+#ifdef JS_CODEGEN_ARM64
+    WasmPop(masm, lr);
+    masm.abiret();
+#else
+    masm.ret();
+#endif
 
     return FinishOffsets(masm, offsets);
 }
 
 // Generate a stub that calls into WasmOldReportTrap with the right trap reason.
 // This stub is called with ABIStackAlignment by a trap out-of-line path. An
 // exit prologue/epilogue is used so that stack unwinding picks up the
 // current JitActivation. Unwinding will begin at the caller of this trap exit.
@@ -1587,274 +1644,31 @@ GenerateOutOfBoundsExit(MacroAssembler& 
 
 static bool
 GenerateUnalignedExit(MacroAssembler& masm, Label* throwLabel, Offsets* offsets)
 {
     return GenerateGenericMemoryAccessTrap(masm, SymbolicAddress::ReportUnalignedAccess, throwLabel,
                                            offsets);
 }
 
-#if defined(JS_CODEGEN_ARM)
-static const LiveRegisterSet AllRegsExceptPCSP(
-    GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::sp) |
-                                              (uint32_t(1) << Registers::pc))),
-    FloatRegisterSet(FloatRegisters::AllDoubleMask));
-static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too.");
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-static const LiveRegisterSet AllUserRegsExceptSP(
-    GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::k0) |
-                                              (uint32_t(1) << Registers::k1) |
-                                              (uint32_t(1) << Registers::sp) |
-                                              (uint32_t(1) << Registers::zero))),
-    FloatRegisterSet(FloatRegisters::AllDoubleMask));
-static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too.");
-#elif defined(JS_CODEGEN_ARM64)
-static const LiveRegisterSet AllRegsExceptSPLR(
-    GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::StackPointer) |
-                                              (uint32_t(1) << Registers::lr))),
-    FloatRegisterSet(FloatRegisters::AllMask));
-#else
-static const LiveRegisterSet AllRegsExceptSP(
-    GeneralRegisterSet(Registers::AllMask & ~(uint32_t(1) << Registers::StackPointer)),
-    FloatRegisterSet(FloatRegisters::AllMask));
-#endif
-
-// The async interrupt-callback exit is called from arbitrarily-interrupted wasm
-// code. It calls into the WasmHandleExecutionInterrupt to determine whether we must
-// really halt execution which can reenter the VM (e.g., to display the slow
-// script dialog). If execution is not interrupted, this stub must carefully
-// preserve *all* register state. If execution is interrupted, the entire
-// activation will be popped by the throw stub, so register state does not need
-// to be restored.
-static bool
-GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel, Offsets* offsets)
-{
-    AssertExpectedSP(masm);
-    masm.haltingAlign(CodeAlignment);
-
-    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 used as return address, updated below