merge mozilla-inbound to mozilla-central. r=merge a=merge FIREFOX_BETA_57_BASE
authorSebastian Hengst <archaeopteryx@coole-files.de>
Thu, 14 Sep 2017 23:58:56 +0200
changeset 665088 8e818b5e9b6bef0fc1a5c527ecf30b0d56a02f14
parent 665087 b778b6cb49c8ed1dab244c00dc4dc3cf88b25ffe (current diff)
parent 665000 38e7e0bba03684d37c8331667f6a1b2df2030670 (diff)
child 665089 d206a230dda04c28a2a30bf7dbf082cd39f1f5de
child 665113 6088ee92ec3989796bc27100f643dfc074c7833e
child 665118 7c28d7dbb127f2f8021b4fe7d47fddd3de287127
child 665121 db3171195b998a6988c832615e00589614b20f49
child 665130 2c8167739b824c8189636f9966704e23eea4feab
child 665163 c006eaf460bb5bf3120913fa154106ebaded8069
child 665168 c8d9125a098e4df5ea3bd60462163f9994b1fdb6
child 665175 12f6f7ab39462e95b8b7ccefc00268692ab9329f
child 665202 094f63d3a9aada12684853999aab66c7e778dd77
child 665204 8a56e4ffca6d03c5945c478565350373963bbd34
child 665205 360a59579e7345c789af3fc74a9a67d5f09704a0
child 665207 01bc721e07bac1fa66e8579eec4a157b45490be9
child 665209 319e388a61d93af020350c9b11745f8fddb22296
child 665210 ee2a20921a17b9091b60a5d9e389a6c6f2fa192b
child 665211 089cd36d749408f220da3f9411e8d56ae72379a3
child 665212 dba152c3bc94cfed2d4a3220c3163933ee145002
child 665213 4cbcb32c7ebe221a94eb2f534d8ca5da7eba1324
child 665214 d2f955cdec480eb30020c5a3fe652c8ad7b8ac3b
child 665215 dc015362919465c4b92846584971abe7d1eb1183
child 665226 1963705e8f8486899015d09e3a2f0b47ccbec53b
child 665227 6cc708a0dcdac34524216d167ddaf673ed8acae4
child 665228 c335d974c977f0efa87c9c6f14bf368aa2a0b70d
child 665230 6f6c9bd993f158588d3e1705b1ffc6ec5c42a360
child 665238 8d8a89a8b087a7e23882fcdd5e343e17e31e9c3d
child 665239 f66eeff36f7d19a3e4e17e32457df313f5068e43
child 665240 71d22f0c682fdea9212d5999b728ce6046c24805
child 665248 bb321c7a4b698943e8fde92470855852a7abf410
child 665250 da3407c304ccdebcc4d7240da4eb88aa5b5b0f90
child 665251 26d8461a90128795c9b6e675734a3c907886710b
child 665254 400825b3934e9470e48cca5e540cb582d2d9a09a
child 665255 3d688fd1a7ba1cd93a1e9c285a0186c92460397b
child 665256 c637be90b220070f0b10c3e22719c19468ad6561
child 665257 d07d11e9663031ba7bab3eb3a209049c199f5e83
child 665261 ef93435e85a4febf8874148d85350f48cf7c8429
child 665293 ef5f715ffaeb4d5427ae50044427abc2a7936911
child 665302 a9287b2a630d4aaa258f6ce572e23adb83a2f1b3
child 665305 e255f9ba3ee89c587d05b5af3dcfacb209ba7af8
child 665310 7444b29eb883d3a919d01ade39d4eb7d93f10c85
child 665311 e63441f604c807d9af9e7765213034a94cc3aa4a
child 665312 81dc24caba30c28bad18d84f68547958f527b122
child 665314 1a9e430a019a038f18edff9710703cefe015ad0b
child 665318 f4bad99b6b30f404c5ff8d0a3cf754b512fea99b
child 665326 ba31238e6605a789620a98f8c6a4639d8f79b432
child 665336 1571fe1de01ff96aa439d6af1ec3ea8d9a79cce7
child 665363 442cc0fe3bec0c24499aedbeea051053bb30d1e3
child 665393 b08775954468981a1cc7138e17ad0300b4b16f9e
child 665398 41f3da2d873f1a8c491414f2ed7319c1399fd6eb
child 665410 a4f56347c0af892a72f1d7d9716d07e90cd194f6
child 665413 ed53c1dfabc07698c546546d92b015021bc82c4c
child 665415 8891e9d00fb2863a735734cd4d5bbd8b18e4fe90
child 665417 0dac5e4a71c21df43131f35332a0bb8e1e8facc6
child 665420 705fb24bb2496d546152111d0c7704727e29dcdb
child 665425 90c8da0261a2af936fd80638ee8cf1477605bb16
child 665442 20fac6aa9bc023db40f544bc040b7fd54c42e632
child 665446 ba1d6fe5443a467840d63cf550661cd0fef071ab
child 665470 0b9616ad399d833d2e8b267053f659532b71b9ea
child 665511 2dbfd4b622fcfe7d4af972aad81ad25e3cac682a
child 665515 0a57830b299b9295c0dd7fab170eaa47bc8c9579
child 665535 fdeb02df842f36165c22f2e1772ddeab5e759dd2
child 665599 a966e2ee0dae223cbdf14679938d1db5ad0a126f
child 665622 2fc5069dfb86f53c6bc0b9e664dc7385ed77111a
child 665650 9ae509d6a6944111c3bc027071c56703bfc75d81
child 665651 fe6f507e2a2daf66e7f255423351fca1ef74ccfc
child 665819 d51cb4beef7f55ca4798088386442e4d9f9b612c
child 665823 566889991b1c4bdf8d310b9c87dc3055c1f083b6
child 665837 bad4ad3cdd0ce880d97773ab05d25c0d18f05e60
child 665951 c147a2881b5295b6fb6271e010ea9dcd9f218757
child 666022 8b1612f1bb9940ab810555ee17cbf4365b7d2153
child 666059 3cf2a2eda23d94f8107e2f23ca3e0fe273d91239
child 666132 b05ec80117bb7fd1e176e9c37533a3ce3e90a925
child 666226 9ac6caa611eafcf98bc026762a5038f56c851e06
child 666286 5c6e1e909339f58ada48285294d97f3a4de46c28
child 666292 e5a6cc3aafccde8c9e8cd175aafc7e641ca17031
child 666886 f7c7f7a5571ceec9c77066874f9f366204f7facf
child 666965 34ee12009dc2a85eea0cdb54dcf39dd2a57bbce0
child 666996 a880fca784b03798269ae1361db38dfa3aa61f94
child 666999 7f63a71f572723c137c6c324bdeea345d1d7c0da
child 667566 5b69e2cc69dfc848c1c8058eea73258e57389a68
child 667691 bc6be1655c210a9f5a80378950e9ed5604f7bede
child 668208 299b622beeb4a074376469e32181756229fee998
child 668246 4da76d1821734932a717c13df4e1e42f9d9b296e
child 668985 b9b6086ca00beb3993814cf62bef0cf01954e8c9
child 669173 a1463ff255f4bd76e179b763f8bac6f5c9e8f035
child 669736 6b999a664665550c3b3d45e5a37e5c667638d9cd
child 670886 80ca5570aa21c21d8a269ee9144b1598e4350c4f
child 671047 d6c152ac7a9b9862520c96f85ece7040a9d5fb9e
push id79917
push userbmo:edilee@mozilla.com
push dateThu, 14 Sep 2017 22:09:23 +0000
reviewersmerge, merge
milestone57.0a1
merge mozilla-inbound to mozilla-central. r=merge a=merge MozReview-Commit-ID: JHeyFz4rx1v
devtools/client/themes/rules.css
modules/libpref/init/all.js
netwerk/protocol/http/nsHttpChannel.cpp
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -402,25 +402,27 @@ var ClickEventHandler = {
 
     let originalTarget = event.originalTarget;
     let ownerDoc = originalTarget.ownerDocument;
     if (!ownerDoc) {
       return;
     }
 
     // Handle click events from about pages
-    if (ownerDoc.documentURI.startsWith("about:certerror")) {
-      this.onCertError(originalTarget, ownerDoc);
-      return;
-    } else if (ownerDoc.documentURI.startsWith("about:blocked")) {
-      this.onAboutBlocked(originalTarget, ownerDoc);
-      return;
-    } else if (ownerDoc.documentURI.startsWith("about:neterror")) {
-      this.onAboutNetError(event, ownerDoc.documentURI);
-      return;
+    if (event.button == 0) {
+      if (ownerDoc.documentURI.startsWith("about:certerror")) {
+        this.onCertError(originalTarget, ownerDoc);
+        return;
+      } else if (ownerDoc.documentURI.startsWith("about:blocked")) {
+        this.onAboutBlocked(originalTarget, ownerDoc);
+        return;
+      } else if (ownerDoc.documentURI.startsWith("about:neterror")) {
+        this.onAboutNetError(event, ownerDoc.documentURI);
+        return;
+      }
     }
 
     let [href, node, principal] = this._hrefAndLinkNodeForClickEvent(event);
 
     // get referrer attribute from clicked link and parse it
     // if per element referrer is enabled, the element referrer overrules
     // the document wide referrer
     let referrerPolicy = ownerDoc.referrerPolicy;
--- a/browser/extensions/onboarding/content/onboarding-tour-agent.js
+++ b/browser/extensions/onboarding/content/onboarding-tour-agent.js
@@ -62,16 +62,17 @@ let onClick = evt => {
   // On keyboard navigation the target would be .onboarding-tour-item.
   // On mouse clicking the target would be .onboarding-tour-item-container.
   if (classList.contains("onboarding-tour-item") || classList.contains("onboarding-tour-item-container")) {
     Mozilla.UITour.hideHighlight(); // Clean up UITour if a user tries to change to other tours.
   }
 };
 
 let overlay = document.getElementById("onboarding-overlay");
+overlay.addEventListener("submit", e => e.preventDefault());
 overlay.addEventListener("click", onClick);
 overlay.addEventListener("keypress", e => {
   let { target, key } = e;
   let classList = target.classList;
   if ((key == " " || key == "Enter") &&
       // On keyboard navigation the target would be .onboarding-tour-item.
       // On mouse clicking the target would be .onboarding-tour-item-container.
       (classList.contains("onboarding-tour-item") || classList.contains("onboarding-tour-item-container"))) {
--- a/devtools/client/shared/components/tabs/tabs.css
+++ b/devtools/client/shared/components/tabs/tabs.css
@@ -23,16 +23,17 @@
   position: relative;
 }
 
 .tabs .tabs-menu-item a {
   display: flex;
   justify-content: center;
   padding: 4px 8px;
   border: 1px solid transparent;
+  font-size: 12px;
   text-decoration: none;
   white-space: nowrap;
 }
 
 .tabs .tabs-menu-item .tab-badge {
   color: var(--theme-highlight-blue);
   font-size: 80%;
   font-style: italic;
@@ -91,43 +92,29 @@
 
 .theme-dark .tabs .tabs-menu-item:last-child,
 .theme-light:not(.theme-firebug) .tabs .tabs-menu-item:last-child {
   border-inline-end-width: 1px;
 }
 
 .theme-dark .tabs .tabs-menu-item a,
 .theme-light .tabs .tabs-menu-item a {
-  padding: 3px 15px;
+  padding: 3px 10px;
 }
 
 .theme-dark .tabs .tabs-menu-item:hover,
 .theme-light .tabs .tabs-menu-item:hover {
   background-color: var(--theme-toolbar-hover);
 }
 
 .theme-dark .tabs .tabs-menu-item:hover:active:not(.is-active),
 .theme-light .tabs .tabs-menu-item:hover:active:not(.is-active) {
   background-color: var(--theme-toolbar-hover-active);
 }
 
-/* Dark Theme */
-
-.theme-dark .tabs .tabs-menu-item {
-  color: var(--theme-body-color-alt);
-}
-
-.theme-dark .tabs .tabs-menu-item:hover:not(.is-active) {
-  color: var(--theme-focus-outline-color);
-}
-
-.theme-dark .tabs .tabs-menu-item:hover:active {
-  color: var(--theme-selection-color);
-}
-
 /* Firebug Theme */
 
 .theme-firebug .tabs .tabs-navigation {
   padding-top: 3px;
   padding-left: 3px;
 }
 
 .theme-firebug .tabs .tabs-menu {
--- a/devtools/client/themes/light-theme.css
+++ b/devtools/client/themes/light-theme.css
@@ -36,17 +36,17 @@ body {
 .theme-bg-contrast,
 .variable-or-property:not([overridden])[changed] {
   background: var(--theme-contrast-background);
 }
 
 .theme-link,
 .cm-s-mozilla .cm-link,
 .CodeMirror-Tern-type {
-  color: var(--theme-highlight-purple);
+  color: var(--theme-comment);
 }
 
 /*
  * FIXME: http://bugzil.la/575675 CSS links without :visited set cause assertion
  * failures in debug builds.
  */
 .theme-link:visited,
 .cm-s-mozilla .cm-link:visited {
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -158,16 +158,17 @@
 }
 
 .ruleview-propertyvaluecontainer {
   cursor: text;
   padding-right: 5px;
 }
 
 .ruleview-propertyvaluecontainer a {
+  color: var(--theme-highlight-purple);
   cursor: pointer;
 }
 
 .ruleview-computedlist,
 .ruleview-expandable-container[hidden],
 .ruleview-overridden-items[hidden],
 .ruleview-overridden-rule-filter[hidden],
 .ruleview-warning[hidden],
--- a/devtools/server/actors/errordocs.js
+++ b/devtools/server/actors/errordocs.js
@@ -77,16 +77,18 @@ const ErrorDocs = {
   JSMSG_RESERVED_ID: "Reserved_identifier",
   JSMSG_BAD_CONST_ASSIGN: "Invalid_const_assignment",
   JSMSG_BAD_CONST_DECL: "Missing_initializer_in_const",
   JSMSG_OF_AFTER_FOR_LOOP_DECL: "Invalid_for-of_initializer",
   JSMSG_BAD_URI: "Malformed_URI",
   JSMSG_DEPRECATED_DELETE_OPERAND: "Delete_in_strict_mode",
   JSMSG_MISSING_FORMAL: "Missing_formal_parameter",
   JSMSG_CANT_TRUNCATE_ARRAY: "Non_configurable_array_element",
+  JSMSG_INCOMPATIBLE_PROTO: "Called_on_incompatible_type",
+  JSMSG_INCOMPATIBLE_METHOD: "Called_on_incompatible_type",
 };
 
 const MIXED_CONTENT_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Mixed_content";
 const TRACKING_PROTECTION_LEARN_MORE = "https://developer.mozilla.org/Firefox/Privacy/Tracking_Protection";
 const INSECURE_PASSWORDS_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Insecure_passwords";
 const PUBLIC_KEY_PINS_LEARN_MORE = "https://developer.mozilla.org/docs/Web/HTTP/Public_Key_Pinning";
 const STRICT_TRANSPORT_SECURITY_LEARN_MORE = "https://developer.mozilla.org/docs/Web/HTTP/Headers/Strict-Transport-Security";
 const WEAK_SIGNATURE_ALGORITHM_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Weak_Signature_Algorithm";
--- a/dom/file/ipc/IPCBlobInputStream.cpp
+++ b/dom/file/ipc/IPCBlobInputStream.cpp
@@ -3,47 +3,50 @@
 /* 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 "IPCBlobInputStream.h"
 #include "IPCBlobInputStreamChild.h"
 #include "IPCBlobInputStreamStorage.h"
 #include "mozilla/ipc/InputStreamParams.h"
+#include "IPCBlobInputStreamThread.h"
 #include "nsIAsyncInputStream.h"
-#include "nsIStreamTransportService.h"
-#include "nsITransport.h"
-#include "nsNetCID.h"
+#include "nsIAsyncOutputStream.h"
+#include "nsIPipe.h"
+#include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "SlicedInputStream.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
-static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
-
 class InputStreamCallbackRunnable final : public CancelableRunnable
 {
 public:
+  // Note that the execution can be synchronous in case the event target is
+  // null.
   static void
   Execute(nsIInputStreamCallback* aCallback,
           nsIEventTarget* aEventTarget,
           IPCBlobInputStream* aStream)
   {
+    MOZ_ASSERT(aCallback);
+
     RefPtr<InputStreamCallbackRunnable> runnable =
       new InputStreamCallbackRunnable(aCallback, aStream);
 
     nsCOMPtr<nsIEventTarget> target = aEventTarget;
-    if (!target) {
-      target = NS_GetCurrentThread();
+    if (aEventTarget) {
+      target->Dispatch(runnable, NS_DISPATCH_NORMAL);
+    } else {
+      runnable->Run();
     }
-
-    target->Dispatch(runnable, NS_DISPATCH_NORMAL);
   }
 
   NS_IMETHOD
   Run() override
   {
     mCallback->OnInputStreamReady(mStream);
     mCallback = nullptr;
     mStream = nullptr;
@@ -68,24 +71,23 @@ private:
 class FileMetadataCallbackRunnable final : public CancelableRunnable
 {
 public:
   static void
   Execute(nsIFileMetadataCallback* aCallback,
           nsIEventTarget* aEventTarget,
           IPCBlobInputStream* aStream)
   {
+    MOZ_ASSERT(aCallback);
+    MOZ_ASSERT(aEventTarget);
+
     RefPtr<FileMetadataCallbackRunnable> runnable =
       new FileMetadataCallbackRunnable(aCallback, aStream);
 
     nsCOMPtr<nsIEventTarget> target = aEventTarget;
-    if (!target) {
-      target = NS_GetCurrentThread();
-    }
-
     target->Dispatch(runnable, NS_DISPATCH_NORMAL);
   }
 
   NS_IMETHOD
   Run() override
   {
     mCallback->OnFileMetadataReady(mStream);
     mCallback = nullptr;
@@ -503,17 +505,19 @@ IPCBlobInputStream::OnInputStreamReady(n
     return NS_OK;
   }
 
   nsCOMPtr<nsIInputStreamCallback> callback;
   callback.swap(mInputStreamCallback);
 
   nsCOMPtr<nsIEventTarget> callbackEventTarget;
   callbackEventTarget.swap(mInputStreamCallbackEventTarget);
- 
+
+  // This must be the last operation because the execution of the callback can
+  // be synchronous.
   InputStreamCallbackRunnable::Execute(callback, callbackEventTarget, this);
   return NS_OK;
 }
 
 // nsIIPCSerializableInputStream
 
 void
 IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
@@ -542,16 +546,23 @@ IPCBlobInputStream::ExpectedSerializedLe
 }
 
 // nsIAsyncFileMetadata
 
 NS_IMETHODIMP
 IPCBlobInputStream::AsyncWait(nsIFileMetadataCallback* aCallback,
                               nsIEventTarget* aEventTarget)
 {
+  MOZ_ASSERT(!!aCallback == !!aEventTarget);
+
+  // If we have the callback, we must have the event target.
+  if (NS_WARN_IF(!!aCallback != !!aEventTarget)) {
+    return NS_ERROR_FAILURE;
+  }
+
   // See IPCBlobInputStream.h for more information about this state machine.
 
   switch (mState) {
   // First call, we need to retrieve the stream from the parent actor.
   case eInit:
     MOZ_ASSERT(mActor);
 
     mFileMetadataCallback = aCallback;
@@ -634,42 +645,40 @@ IPCBlobInputStream::EnsureAsyncRemoteStr
   bool nonBlocking = false;
   nsresult rv = mRemoteStream->IsNonBlocking(&nonBlocking);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mRemoteStream);
   if (!asyncStream || !nonBlocking) {
-    nsCOMPtr<nsIStreamTransportService> sts =
-      do_GetService(kStreamTransportServiceCID, &rv);
+    // Let's make the stream async using the DOMFile thread.
+    nsCOMPtr<nsIAsyncInputStream> pipeIn;
+    nsCOMPtr<nsIAsyncOutputStream> pipeOut;
+    rv = NS_NewPipe2(getter_AddRefs(pipeIn),
+                     getter_AddRefs(pipeOut),
+                     true, true);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    nsCOMPtr<nsITransport> transport;
-    rv = sts->CreateInputTransport(mRemoteStream,
-                                   /* aStartOffset */ 0,
-                                   /* aReadLimit */ -1,
-                                   /* aCloseWhenDone */ true,
-                                   getter_AddRefs(transport));
+    RefPtr<IPCBlobInputStreamThread> thread =
+      IPCBlobInputStreamThread::GetOrCreate();
+    if (NS_WARN_IF(!thread)) {
+      return NS_ERROR_FAILURE;
+    }
+
+    nsCOMPtr<nsIEventTarget> target = thread->EventTarget();
+    rv = NS_AsyncCopy(mRemoteStream, pipeOut, target,
+                      NS_ASYNCCOPY_VIA_WRITESEGMENTS);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    nsCOMPtr<nsIInputStream> wrapper;
-    rv = transport->OpenInputStream(/* aFlags */ 0,
-                                    /* aSegmentSize */ 0,
-                                    /* aSegmentCount */ 0,
-                                    getter_AddRefs(wrapper));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    asyncStream = do_QueryInterface(wrapper);
+    asyncStream = pipeIn;
   }
 
   MOZ_ASSERT(asyncStream);
   mAsyncRemoteStream = asyncStream;
   mRemoteStream = nullptr;
 
   return NS_OK;
 }
--- a/dom/file/ipc/IPCBlobInputStreamChild.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamChild.cpp
@@ -182,16 +182,18 @@ IPCBlobInputStreamChild::ActorDestroy(IP
     mState = migrating ? eInactiveMigrating : eInactive;
   }
 
   if (migrating) {
     // We were waiting for this! Now we can migrate the actor in the correct
     // thread.
     RefPtr<IPCBlobInputStreamThread> thread =
       IPCBlobInputStreamThread::GetOrCreate();
+    MOZ_ASSERT(thread, "We cannot continue without DOMFile thread.");
+
     ResetManager();
     thread->MigrateActor(this);
     return;
   }
 
   // Let's cleanup the workerHolder and the pending operation queue.
   Shutdown();
 }
@@ -272,17 +274,17 @@ IPCBlobInputStreamChild::StreamNeeded(IP
   if (mState == eInactive) {
     return;
   }
 
   MOZ_ASSERT(mStreams.Contains(aStream));
 
   PendingOperation* opt = mPendingOperations.AppendElement();
   opt->mStream = aStream;
-  opt->mEventTarget = aEventTarget ? aEventTarget : NS_GetCurrentThread();
+  opt->mEventTarget = aEventTarget;
 
   if (mState == eActiveMigrating || mState == eInactiveMigrating) {
     // This operation will be continued when the migration is completed.
     return;
   }
 
   MOZ_ASSERT(mState == eActive);
 
@@ -311,17 +313,26 @@ IPCBlobInputStreamChild::RecvStreamReady
     pendingStream = mPendingOperations[0].mStream;
     eventTarget = mPendingOperations[0].mEventTarget;
 
     mPendingOperations.RemoveElementAt(0);
   }
 
   RefPtr<StreamReadyRunnable> runnable =
     new StreamReadyRunnable(pendingStream, stream);
-  eventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
+
+  // If IPCBlobInputStream::AsyncWait() has been executed without passing an
+  // event target, we run the callback synchronous because any thread could be
+  // result to be the wrong one. See more in nsIAsyncInputStream::asyncWait
+  // documentation.
+  if (eventTarget) {
+    eventTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
+  } else {
+    runnable->Run();
+  }
 
   return IPC_OK();
 }
 
 void
 IPCBlobInputStreamChild::Migrated()
 {
   MutexAutoLock lock(mMutex);
--- a/dom/file/ipc/IPCBlobInputStreamThread.cpp
+++ b/dom/file/ipc/IPCBlobInputStreamThread.cpp
@@ -31,17 +31,17 @@ class ThreadInitializeRunnable final : p
 public:
   ThreadInitializeRunnable() : Runnable("dom::ThreadInitializeRunnable") {}
 
   NS_IMETHOD
   Run() override
   {
      mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
      MOZ_ASSERT(gIPCBlobThread);
-     gIPCBlobThread->Initialize();
+     gIPCBlobThread->InitializeOnMainThread();
      return NS_OK;
   }
 };
 
 class MigrateActorRunnable final : public Runnable
                                  , public nsIIPCBackgroundChildCreateCallback
 {
 public:
@@ -110,57 +110,74 @@ IPCBlobInputStreamThread::GetOrCreate()
   mozilla::StaticMutexAutoLock lock(gIPCBlobThreadMutex);
 
   if (gShutdownHasStarted) {
     return nullptr;
   }
 
   if (!gIPCBlobThread) {
     gIPCBlobThread = new IPCBlobInputStreamThread();
-    gIPCBlobThread->Initialize();
+    if (!gIPCBlobThread->Initialize()) {
+      return nullptr;
+    }
   }
 
   return gIPCBlobThread;
 }
 
-void
+bool
 IPCBlobInputStreamThread::Initialize()
 {
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = NS_NewNamedThread("DOM File", getter_AddRefs(thread));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  mThread = thread;
+
+  if (!mPendingActors.IsEmpty()) {
+    for (uint32_t i = 0; i < mPendingActors.Length(); ++i) {
+      MigrateActorInternal(mPendingActors[i]);
+    }
+
+    mPendingActors.Clear();
+  }
+
   if (!NS_IsMainThread()) {
     RefPtr<Runnable> runnable = new ThreadInitializeRunnable();
     SystemGroup::Dispatch(TaskCategory::Other, runnable.forget());
-    return;
+    return true;
   }
 
+  InitializeOnMainThread();
+  return true;
+}
+
+void
+IPCBlobInputStreamThread::InitializeOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   if (NS_WARN_IF(!obs)) {
     return;
   }
 
   nsresult rv =
     obs->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
-
-  nsCOMPtr<nsIThread> thread;
-  rv = NS_NewNamedThread("DOM File", getter_AddRefs(thread));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return;
-  }
+}
 
-  mThread = thread;
-
-  if (!mPendingActors.IsEmpty()) {
-    for (uint32_t i = 0; i < mPendingActors.Length(); ++i) {
-      MigrateActorInternal(mPendingActors[i]);
-    }
-
-    mPendingActors.Clear();
-  }
+nsIEventTarget*
+IPCBlobInputStreamThread::EventTarget() const
+{
+  return mThread;
 }
 
 NS_IMETHODIMP
 IPCBlobInputStreamThread::Observe(nsISupports* aSubject,
                                   const char* aTopic,
                                   const char16_t* aData)
 {
   MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID));
--- a/dom/file/ipc/IPCBlobInputStreamThread.h
+++ b/dom/file/ipc/IPCBlobInputStreamThread.h
@@ -26,18 +26,24 @@ public:
   IsOnFileEventTarget(nsIEventTarget* aEventTarget);
 
   static IPCBlobInputStreamThread*
   GetOrCreate();
 
   void
   MigrateActor(IPCBlobInputStreamChild* aActor);
 
+  bool
+  Initialize();
+
   void
-  Initialize();
+  InitializeOnMainThread();
+
+  nsIEventTarget*
+  EventTarget() const;
 
 private:
   ~IPCBlobInputStreamThread() = default;
 
   void
   MigrateActorInternal(IPCBlobInputStreamChild* aActor);
 
   nsCOMPtr<nsIThread> mThread;
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -156,16 +156,17 @@ skip-if = (android_version <= '17' || an
 skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_errorCallbacks.html]
 [test_peerConnection_iceFailure.html]
 skip-if = os == 'linux' || os == 'mac' || os == 'win' || toolkit == 'android' # (Bug 1180388 for win, mac and linux), android(Bug 1189784, timeouts on 4.3 emulator), Bug 1180388
 [test_peerConnection_insertDTMF.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_forwarding_basicAudioVideoCombined.html]
 skip-if = toolkit == 'android'  # Bug 1189784
+[test_peerConnection_maxFsConstraint.html]
 [test_peerConnection_noTrickleAnswer.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_noTrickleOffer.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_noTrickleOfferAnswer.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_offerRequiresReceiveAudio.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_peerConnection_maxFsConstraint.html
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <script type="application/javascript" src="pc.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+  createHTML({
+    bug: "1393687",
+    title: "Enforce max-fs constraint on a PeerConnection",
+    visible: true
+  });
+
+  const pushPrefs = (...p) => SpecialPowers.pushPrefEnv({set: p});
+
+  var mustRejectWith = (msg, reason, f) =>
+    f().then(() => ok(false, msg),
+             e => is(e.name, reason, msg));
+
+  var removeAllButCodec = (d, codec) =>
+    (d.sdp = d.sdp.replace(/m=video (\w) UDP\/TLS\/RTP\/SAVPF \w.*\r\n/,
+                           "m=video $1 UDP/TLS/RTP/SAVPF " + codec + "\r\n"), d);
+
+  var mungeSDP = (d, forceH264) => {
+    if (forceH264) {
+      removeAllButCodec(d, 126);
+      d.sdp = d.sdp.replace(/a=fmtp:126 (.*);packetization-mode=1/, "a=fmtp:126 $1;packetization-mode=1;max-fs=100");
+    } else {
+      d.sdp = d.sdp.replace(/max-fs=\d+/, "max-fs=100");
+    }
+    return d;
+  };
+
+  function testScale(codec) {
+    var v1 = createMediaElement('video', 'v1');
+    var v2 = createMediaElement('video', 'v2');
+
+    var pc1 = new RTCPeerConnection();
+    var pc2 = new RTCPeerConnection();
+
+    var add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed);
+    pc1.onicecandidate = e => add(pc2, e.candidate, generateErrorCallback());
+    pc2.onicecandidate = e => add(pc1, e.candidate, generateErrorCallback());
+
+    info("testing max-fs with" + codec);
+
+    pc1.onnegotiationneeded = e =>
+      pc1.createOffer()
+      .then(d => pc1.setLocalDescription(mungeSDP(d, codec == "H264")))
+      .then(() => pc2.setRemoteDescription(pc1.localDescription))
+      .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(mungeSDP(d, codec =="H264")))
+      .then(() => pc1.setRemoteDescription(pc2.localDescription))
+      .catch(generateErrorCallback());
+
+    pc2.ontrack = e => {
+      v2.srcObject = e.streams[0];
+    };
+
+    var stream;
+
+    return navigator.mediaDevices.getUserMedia({ video: true })
+      .then(s => {
+        stream = s;
+        v1.srcObject = stream;
+        let track = stream.getVideoTracks()[0];
+        let sender = pc1.addTrack(track, stream);
+        is(v2.currentTime, 0, "v2.currentTime is zero at outset");
+      })
+      .then(() => wait(5000))
+      .then(() => {
+        if (v2.videoWidth == 0 && v2.videoHeight == 0) {
+          info("Skipping test, insufficient time for video to start.");
+        } else {
+          is(v2.videoWidth, 160, "sink width should be 160 for " + codec);
+          is(v2.videoHeight, 120, "sink height should be 120 for " + codec);
+        }})
+      .then(() => {
+        stream.getTracks().forEach(track => track.stop());
+        v1.srcObject = v2.srcObject = null;
+      }).catch(generateErrorCallback());
+  }
+
+  pushPrefs(['media.peerconnection.video.lock_scaling', true]).then(() => {
+    if (!navigator.appVersion.includes("Android")) {
+      runNetworkTest(() => testScale("VP8").then(() => testScale("H264"))
+                    .then(networkTestFinished));
+    } else {
+      // No support for H.264 on Android in automation, see Bug 1355786
+      runNetworkTest(() => testScale("VP8").then(networkTestFinished));
+    }
+  });
+</script>
+</pre>
+</body>
+</html>
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -49,16 +49,20 @@ nsContentSecurityManager::AllowTopLevelN
   }
   // Whitelist data: images as long as they are not SVGs
   nsAutoCString filePath;
   aURI->GetFilePath(filePath);
   if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/")) &&
       !StringBeginsWith(filePath, NS_LITERAL_CSTRING("image/svg+xml"))) {
     return true;
   }
+  // Whitelist data: PDFs
+  if (StringBeginsWith(filePath, NS_LITERAL_CSTRING("application/pdf"))) {
+    return true;
+  }
   if (!aLoadFromExternal &&
       nsContentUtils::IsSystemPrincipal(aTriggeringPrincipal)) {
     return true;
   }
   nsAutoCString dataSpec;
   aURI->GetSpec(dataSpec);
   if (dataSpec.Length() > 50) {
     dataSpec.Truncate(50);
--- a/dom/security/test/general/mochitest.ini
+++ b/dom/security/test/general/mochitest.ini
@@ -10,8 +10,10 @@ support-files =
 
 [test_contentpolicytype_targeted_link_iframe.html]
 [test_nosniff.html]
 [test_block_script_wrong_mime.html]
 [test_block_toplevel_data_navigation.html]
 skip-if = toolkit == 'android' # intermittent failure
 [test_block_toplevel_data_img_navigation.html]
 skip-if = toolkit == 'android' # intermittent failure
+[test_allow_opening_data_pdf.html]
+skip-if = toolkit == 'android'
new file mode 100644
--- /dev/null
+++ b/dom/security/test/general/test_allow_opening_data_pdf.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Bug 1398692: Allow toplevel navigation to a data:application/pdf</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function test_toplevel_data_pdf() {
+  // The PDF contains one page and it is a 3/72" square, the minimum allowed by the spec
+  const DATA_PDF =
+    "data:application/pdf;base64,JVBERi0xLjANCjEgMCBvYmo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PmVuZG9iaiAyIDAgb2JqPDwvVHlwZS9QYWdlcy9LaWRzWzMgMCBSXS9Db3VudCAxPj5lbmRvYmogMyAwIG9iajw8L1R5cGUvUGFnZS9NZWRpYUJveFswIDAgMyAzXT4+ZW5kb2JqDQp4cmVmDQowIDQNCjAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxMCAwMDAwMCBuDQowMDAwMDAwMDUzIDAwMDAwIG4NCjAwMDAwMDAxMDIgMDAwMDAgbg0KdHJhaWxlcjw8L1NpemUgNC9Sb290IDEgMCBSPj4NCnN0YXJ0eHJlZg0KMTQ5DQolRU9G";
+
+  let win = window.open(DATA_PDF);
+  let wrappedWin = SpecialPowers.wrap(win);
+
+  // Unfortunately we can't detect whether the PDF has loaded or not using some
+  // event, hence we are constantly polling location.href till we see that
+  // the data: URI appears. Test times out on failure.
+  var pdfLoaded = setInterval(function() {
+    if (wrappedWin.document.location.href.startsWith("data:application/pdf")) {
+      clearInterval(pdfLoaded);
+      ok(true, "navigating to data:application/pdf allowed");
+      wrappedWin.close();
+      SimpleTest.finish();
+    }
+  }, 200);
+}
+
+SpecialPowers.pushPrefEnv({
+  set: [["security.data_uri.block_toplevel_data_uri_navigations", true]]
+}, test_toplevel_data_pdf);
+
+</script>
+</body>
+</html>
--- a/gfx/2d/DrawCommand.h
+++ b/gfx/2d/DrawCommand.h
@@ -32,16 +32,17 @@ enum class CommandType : int8_t {
   MASK,
   MASKSURFACE,
   PUSHCLIP,
   PUSHCLIPRECT,
   PUSHLAYER,
   POPCLIP,
   POPLAYER,
   SETTRANSFORM,
+  SETPERMITSUBPIXELAA,
   FLUSH
 };
 
 class DrawingCommand
 {
 public:
   virtual ~DrawingCommand() {}
 
@@ -670,16 +671,35 @@ public:
       aDT->SetTransform(mTransform);
     }
   }
 
 private:
   Matrix mTransform;
 };
 
+class SetPermitSubpixelAACommand : public DrawingCommand
+{
+  friend class DrawTargetCaptureImpl;
+public:
+  explicit SetPermitSubpixelAACommand(bool aPermitSubpixelAA)
+    : DrawingCommand(CommandType::SETPERMITSUBPIXELAA)
+    , mPermitSubpixelAA(aPermitSubpixelAA)
+  {
+  }
+
+  virtual void ExecuteOnDT(DrawTarget* aDT, const Matrix* aMatrix) const
+  {
+    aDT->SetPermitSubpixelAA(mPermitSubpixelAA);
+  }
+
+private:
+  bool mPermitSubpixelAA;
+};
+
 class FlushCommand : public DrawingCommand
 {
 public:
   explicit FlushCommand()
     : DrawingCommand(CommandType::FLUSH)
   {
   }
 
--- a/gfx/2d/DrawTargetCapture.cpp
+++ b/gfx/2d/DrawTargetCapture.cpp
@@ -73,16 +73,27 @@ DrawTargetCaptureImpl::Snapshot()
 
 void
 DrawTargetCaptureImpl::DetachAllSnapshots()
 {}
 
 #define AppendCommand(arg) new (AppendToCommandList<arg>()) arg
 
 void
+DrawTargetCaptureImpl::SetPermitSubpixelAA(bool aPermitSubpixelAA)
+{
+  AppendCommand(SetPermitSubpixelAACommand)(aPermitSubpixelAA);
+
+  // Have to update mPermitSubpixelAA for this DT
+  // because some code paths query the current setting
+  // to determine subpixel AA eligibility.
+  DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA);
+}
+
+void
 DrawTargetCaptureImpl::DrawSurface(SourceSurface *aSurface,
                                    const Rect &aDest,
                                    const Rect &aSource,
                                    const DrawSurfaceOptions &aSurfOptions,
                                    const DrawOptions &aOptions)
 {
   aSurface->GuaranteePersistance();
   AppendCommand(DrawSurfaceCommand)(aSurface, aDest, aSource, aSurfOptions, aOptions);
--- a/gfx/2d/DrawTargetCapture.h
+++ b/gfx/2d/DrawTargetCapture.h
@@ -22,16 +22,17 @@ public:
   DrawTargetCaptureImpl(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat);
 
   bool Init(const IntSize& aSize, DrawTarget* aRefDT);
 
   virtual BackendType GetBackendType() const override { return mRefDT->GetBackendType(); }
   virtual DrawTargetType GetType() const override { return mRefDT->GetType(); }
   virtual bool IsCaptureDT() const override { return true; }
   virtual already_AddRefed<SourceSurface> Snapshot() override;
+  virtual void SetPermitSubpixelAA(bool aPermitSubpixelAA) override;
   virtual void DetachAllSnapshots() override;
   virtual IntSize GetSize() override { return mSize; }
   virtual void Flush() override {}
   virtual void DrawSurface(SourceSurface *aSurface,
                            const Rect &aDest,
                            const Rect &aSource,
                            const DrawSurfaceOptions &aSurfOptions,
                            const DrawOptions &aOptions) override;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -2155,16 +2155,17 @@ BorderLayer::PrintInfo(std::stringstream
 void
 BorderLayer::DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent)
 {
   Layer::DumpPacket(aPacket, aParent);
 }
 
 CanvasLayer::CanvasLayer(LayerManager* aManager, void* aImplData)
   : Layer(aManager, aImplData)
+  , mSamplingFilter(SamplingFilter::GOOD)
 {
 }
 
 CanvasLayer::~CanvasLayer() = default;
 
 void
 CanvasLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
--- a/gfx/layers/ipc/CompositorManagerParent.cpp
+++ b/gfx/layers/ipc/CompositorManagerParent.cpp
@@ -4,22 +4,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/CompositorManagerParent.h"
 #include "mozilla/gfx/GPUParent.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CrossProcessCompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
+#include "nsAutoPtr.h"
 #include "VsyncSource.h"
 
 namespace mozilla {
 namespace layers {
 
 StaticRefPtr<CompositorManagerParent> CompositorManagerParent::sInstance;
+StaticAutoPtr<nsTArray<CompositorManagerParent*>> CompositorManagerParent::sActiveActors;
 StaticMutex CompositorManagerParent::sMutex;
 
 /* static */ already_AddRefed<CompositorManagerParent>
 CompositorManagerParent::CreateSameProcess()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(NS_IsMainThread());
   StaticMutexAutoLock lock(sMutex);
@@ -39,16 +41,21 @@ CompositorManagerParent::CreateSameProce
   parent->mCompositorThreadHolder =
     new CompositorThreadHolderDebug("CompositorManagerSame");
   parent->SetOtherProcessId(base::GetCurrentProcId());
 
   // CompositorManagerParent::Bind would normally add a reference for IPDL but
   // we don't use that in the same process case.
   parent.get()->AddRef();
   sInstance = parent;
+
+  if (!sActiveActors) {
+    sActiveActors = new nsTArray<CompositorManagerParent*>();
+  }
+  sActiveActors->AppendElement(parent);
   return parent.forget();
 }
 
 /* static */ void
 CompositorManagerParent::Create(Endpoint<PCompositorManagerParent>&& aEndpoint)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -122,16 +129,22 @@ CompositorManagerParent::Bind(Endpoint<P
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   if (NS_WARN_IF(!aEndpoint.Bind(this))) {
     return;
   }
 
   // Add the IPDL reference to ourself, so we can't get freed until IPDL is
   // done with us.
   AddRef();
+
+  StaticMutexAutoLock lock(sMutex);
+  if (!sActiveActors) {
+    sActiveActors = new nsTArray<CompositorManagerParent*>();
+  }
+  sActiveActors->AppendElement(this);
 }
 
 void
 CompositorManagerParent::ActorDestroy(ActorDestroyReason aReason)
 {
   StaticMutexAutoLock lock(sMutex);
   if (sInstance == this) {
     sInstance = nullptr;
@@ -141,25 +154,59 @@ CompositorManagerParent::ActorDestroy(Ac
 void
 CompositorManagerParent::DeallocPCompositorManagerParent()
 {
   MessageLoop::current()->PostTask(
           NewRunnableMethod("layers::CompositorManagerParent::DeferredDestroy",
                             this,
                             &CompositorManagerParent::DeferredDestroy));
 
+  StaticMutexAutoLock lock(sMutex);
+  if (sActiveActors) {
+    sActiveActors->RemoveElement(this);
+  }
   Release();
 }
 
 void
 CompositorManagerParent::DeferredDestroy()
 {
   mCompositorThreadHolder = nullptr;
 }
 
+/* static */ void
+CompositorManagerParent::ShutdownInternal()
+{
+  nsAutoPtr<nsTArray<CompositorManagerParent*>> actors;
+
+  // We move here because we may attempt to acquire the same lock during the
+  // destroy to remove the reference in sActiveActors.
+  {
+    StaticMutexAutoLock lock(sMutex);
+    actors = sActiveActors.forget();
+  }
+
+  if (actors) {
+    for (auto& actor : *actors) {
+      actor->Close();
+    }
+  }
+}
+
+/* static */ void
+CompositorManagerParent::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  CompositorThreadHolder::Loop()->PostTask(
+      NS_NewRunnableFunction("layers::CompositorManagerParent::Shutdown", []() -> void {
+        CompositorManagerParent::ShutdownInternal();
+      }));
+}
+
 PCompositorBridgeParent*
 CompositorManagerParent::AllocPCompositorBridgeParent(const CompositorBridgeOptions& aOpt)
 {
   switch (aOpt.type()) {
     case CompositorBridgeOptions::TContentCompositorOptions: {
       CrossProcessCompositorBridgeParent* bridge =
         new CrossProcessCompositorBridgeParent(this);
       bridge->AddRef();
--- a/gfx/layers/ipc/CompositorManagerParent.h
+++ b/gfx/layers/ipc/CompositorManagerParent.h
@@ -22,32 +22,36 @@ class CompositorThreadHolderDebug;
 
 class CompositorManagerParent final : public PCompositorManagerParent
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorManagerParent)
 
 public:
   static already_AddRefed<CompositorManagerParent> CreateSameProcess();
   static void Create(Endpoint<PCompositorManagerParent>&& aEndpoint);
+  static void Shutdown();
 
   static already_AddRefed<CompositorBridgeParent>
   CreateSameProcessWidgetCompositorBridge(CSSToLayoutDeviceScale aScale,
                                           const CompositorOptions& aOptions,
                                           bool aUseExternalSurfaceSize,
                                           const gfx::IntSize& aSurfaceSize);
 
   void ActorDestroy(ActorDestroyReason aReason) override;
 
   bool DeallocPCompositorBridgeParent(PCompositorBridgeParent* aActor) override;
   PCompositorBridgeParent* AllocPCompositorBridgeParent(const CompositorBridgeOptions& aOpt) override;
 
 private:
   static StaticRefPtr<CompositorManagerParent> sInstance;
+  static StaticAutoPtr<nsTArray<CompositorManagerParent*>> sActiveActors;
   static StaticMutex sMutex;
 
+  static void ShutdownInternal();
+
   CompositorManagerParent();
   ~CompositorManagerParent() override;
 
   void Bind(Endpoint<PCompositorManagerParent>&& aEndpoint);
 
   void DeallocPCompositorManagerParent() override;
 
   void DeferredDestroy();
--- a/gfx/layers/ipc/CompositorThread.cpp
+++ b/gfx/layers/ipc/CompositorThread.cpp
@@ -154,16 +154,17 @@ void
 CompositorThreadHolder::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
   MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
 
   ReleaseImageBridgeParentSingleton();
   gfx::ReleaseVRManagerParentSingleton();
   MediaSystemResourceService::Shutdown();
+  CompositorManagerParent::Shutdown();
 
   sCompositorThreadHolder = nullptr;
 
   // No locking is needed around sFinishedCompositorShutDown because it is only
   // ever accessed on the main thread.
   SpinEventLoopUntil([&]() { return sFinishedCompositorShutDown; });
 
   CompositorBridgeParent::FinishShutdown();
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1568,17 +1568,17 @@ js::RegExpPrototypeOptimizable(JSContext
 
     args.rval().setBoolean(RegExpPrototypeOptimizableRaw(cx, &args[0].toObject()));
     return true;
 }
 
 bool
 js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
     AutoAssertNoPendingException aanpe(cx);
     if (!proto->isNative())
         return false;
 
     NativeObject* nproto = static_cast<NativeObject*>(proto);
 
     Shape* shape = cx->compartment()->regExps.getOptimizableRegExpPrototypeShape();
     if (shape == nproto->lastProperty())
@@ -1661,17 +1661,17 @@ js::RegExpInstanceOptimizable(JSContext*
     args.rval().setBoolean(RegExpInstanceOptimizableRaw(cx, &args[0].toObject(),
                                                         &args[1].toObject()));
     return true;
 }
 
 bool
 js::RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* obj, JSObject* proto)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
     AutoAssertNoPendingException aanpe(cx);
 
     RegExpObject* rx = &obj->as<RegExpObject>();
 
     Shape* shape = cx->compartment()->regExps.getOptimizableRegExpInstanceShape();
     if (shape == rx->lastProperty())
         return true;
 
--- a/js/src/irregexp/RegExpMacroAssembler.cpp
+++ b/js/src/irregexp/RegExpMacroAssembler.cpp
@@ -35,16 +35,18 @@
 using namespace js;
 using namespace js::irregexp;
 
 template <typename CharT>
 int
 irregexp::CaseInsensitiveCompareStrings(const CharT* substring1, const CharT* substring2,
 					size_t byteLength)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     MOZ_ASSERT(byteLength % sizeof(CharT) == 0);
     size_t length = byteLength / sizeof(CharT);
 
     for (size_t i = 0; i < length; i++) {
         char16_t c1 = substring1[i];
         char16_t c2 = substring2[i];
         if (c1 != c2) {
             c1 = unicode::ToLowerCase(c1);
@@ -65,16 +67,18 @@ template int
 irregexp::CaseInsensitiveCompareStrings(const char16_t* substring1, const char16_t* substring2,
 					size_t byteLength);
 
 template <typename CharT>
 int
 irregexp::CaseInsensitiveCompareUCStrings(const CharT* substring1, const CharT* substring2,
                                           size_t byteLength)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     MOZ_ASSERT(byteLength % sizeof(CharT) == 0);
     size_t length = byteLength / sizeof(CharT);
 
     for (size_t i = 0; i < length; i++) {
         char16_t c1 = substring1[i];
         char16_t c2 = substring2[i];
         if (c1 != c2) {
             c1 = unicode::FoldCase(c1);
--- a/js/src/irregexp/RegExpStack.cpp
+++ b/js/src/irregexp/RegExpStack.cpp
@@ -42,16 +42,17 @@ RegExpStackScope::RegExpStackScope(JSCon
 RegExpStackScope::~RegExpStackScope()
 {
     regexp_stack->reset();
 }
 
 int
 irregexp::GrowBacktrackStack(JSRuntime* rt)
 {
+    AutoUnsafeCallWithABI unsafe;
     return TlsContext.get()->regexpStack.ref().grow();
 }
 
 RegExpStack::RegExpStack()
   : base_(nullptr), size(0), limit_(nullptr)
 {}
 
 RegExpStack::~RegExpStack()
--- a/js/src/jit-test/tests/wasm/integer.js
+++ b/js/src/jit-test/tests/wasm/integer.js
@@ -148,16 +148,21 @@ testComparison32('lt_s', 40, 40, 0);
 testComparison32('lt_u', 40, 40, 0);
 testComparison32('le_s', 40, 40, 1);
 testComparison32('le_u', 40, 40, 1);
 testComparison32('gt_s', 40, 40, 0);
 testComparison32('gt_u', 40, 40, 0);
 testComparison32('ge_s', 40, 40, 1);
 testComparison32('ge_u', 40, 40, 1);
 
+// On 32-bit debug builds, with --ion-eager, this test can run into our
+// per-process JIT code limits and OOM. Trigger a GC to discard code.
+if (getJitCompilerOptions()["ion.warmup.trigger"] === 0)
+    gc();
+
 // Test MTest's GVN branch inversion.
 var testTrunc = wasmEvalText(`(module (func (param f32) (result i32) (if i32 (i32.eqz (i32.trunc_s/f32 (get_local 0))) (i32.const 0) (i32.const 1))) (export "" 0))`).exports[""];
 assertEq(testTrunc(0), 0);
 assertEq(testTrunc(13.37), 1);
 
 {
     setJitCompilerOption('wasm.test-mode', 1);
 
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -24,16 +24,18 @@
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsInRange;
 
 uint32_t
 jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     JSContext* cx = TlsContext.get();
     MOZ_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_EXITFP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_EXITFP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
                "Fake exitfp pointer should be within the first page.");
 
@@ -99,16 +101,18 @@ jit::Bailout(BailoutStack* sp, BaselineB
 
     return retval;
 }
 
 uint32_t
 jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
                          BaselineBailoutInfo** bailoutInfo)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     sp->checkInvariants();
 
     JSContext* cx = TlsContext.get();
 
     // We don't have an exit frame.
     cx->activation()->asJit()->setExitFP(FAKE_EXITFP_FOR_BAILOUT);
 
     JitActivationIterator jitActivations(cx);
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -983,16 +983,17 @@ EmitBranchIsReturningFromCallVM(MacroAss
     EmitBranchICEntryKind(masm, entry, ICEntry::Kind_WarmupCounter, label);
     EmitBranchICEntryKind(masm, entry, ICEntry::Kind_StackCheck, label);
     EmitBranchICEntryKind(masm, entry, ICEntry::Kind_EarlyStackCheck, label);
 }
 
 static void
 SyncBaselineDebugModeOSRInfo(BaselineFrame* frame, Value* vp, bool rv)
 {
+    AutoUnsafeCallWithABI unsafe;
     BaselineDebugModeOSRInfo* info = frame->debugModeOSRInfo();
     MOZ_ASSERT(info);
     MOZ_ASSERT(frame->script()->baselineScript()->containsCodeAddress(info->resumeAddr));
 
     if (HasForcedReturn(info, rv)) {
         // Load the frame's rval and overwrite the resume address to go to the
         // epilogue.
         MOZ_ASSERT(R0 == JSReturnOperand);
@@ -1017,16 +1018,17 @@ SyncBaselineDebugModeOSRInfo(BaselineFra
 
     // Scale stackAdjust.
     info->stackAdjust *= sizeof(Value);
 }
 
 static void
 FinishBaselineDebugModeOSR(BaselineFrame* frame)
 {
+    AutoUnsafeCallWithABI unsafe;
     frame->deleteDebugModeOSRInfo();
 
     // We will return to JIT code now so we have to clear the override pc.
     frame->clearOverridePc();
 }
 
 void
 BaselineFrame::deleteDebugModeOSRInfo()
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -1586,22 +1586,24 @@ CreateDependentString::generate(MacroAss
     }
 
     masm.bind(&done);
 }
 
 static void*
 AllocateString(JSContext* cx)
 {
+    AutoUnsafeCallWithABI unsafe;
     return js::Allocate<JSString, NoGC>(cx);
 }
 
 static void*
 AllocateFatInlineString(JSContext* cx)
 {
+    AutoUnsafeCallWithABI unsafe;
     return js::Allocate<JSFatInlineString, NoGC>(cx);
 }
 
 void
 CreateDependentString::generateFallback(MacroAssembler& masm, LiveRegisterSet regsToSave)
 {
     regsToSave.take(string_);
     regsToSave.take(temp_);
@@ -1624,16 +1626,17 @@ CreateDependentString::generateFallback(
 
         masm.jump(&joins_[kind]);
     }
 }
 
 static void*
 CreateMatchResultFallbackFunc(JSContext* cx, gc::AllocKind kind, size_t nDynamicSlots)
 {
+    AutoUnsafeCallWithABI unsafe;
     return js::Allocate<JSObject, NoGC>(cx, kind, nDynamicSlots, gc::DefaultHeap,
                                         &ArrayObject::class_);
 }
 
 static void
 CreateMatchResultFallback(MacroAssembler& masm, LiveRegisterSet regsToSave,
                           Register object, Register temp2, Register temp5,
                           ArrayObject* templateObj, Label* fail)
@@ -3995,17 +3998,18 @@ CodeGenerator::visitCallNative(LCallNati
     masm.passABIArg(argUintNReg);
     masm.passABIArg(argVpReg);
     JSNative native = target->native();
     if (call->ignoresReturnValue()) {
         const JSJitInfo* jitInfo = target->jitInfo();
         if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative)
             native = jitInfo->ignoresReturnValueMethod;
     }
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, native));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, native), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     emitTracelogStopEvent(TraceLogger_Call);
 
     // Test for failure.
     masm.branchIfFalseBool(ReturnReg, masm.failureLabel());
 
     // Load the outparam vp[0] into output register(s).
     masm.loadValue(Address(masm.getStackPointer(), NativeExitFrameLayout::offsetOfResult()), JSReturnOperand);
@@ -4118,17 +4122,18 @@ CodeGenerator::visitCallDOMNative(LCallD
 
     // Construct and execute call.
     masm.setupUnalignedABICall(argJSContext);
     masm.loadJSContext(argJSContext);
     masm.passABIArg(argJSContext);
     masm.passABIArg(argObj);
     masm.passABIArg(argPrivate);
     masm.passABIArg(argArgs);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->jitInfo()->method));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->jitInfo()->method), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (target->jitInfo()->isInfallible) {
         masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()),
                        JSReturnOperand);
     } else {
         // Test for failure.
         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
@@ -7052,25 +7057,34 @@ CodeGenerator::visitMathFunctionF(LMathF
     Register temp = ToRegister(ins->temp());
     FloatRegister input = ToFloatRegister(ins->input());
     MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnFloat32Reg);
 
     masm.setupUnalignedABICall(temp);
     masm.passABIArg(input, MoveOp::FLOAT32);
 
     void* funptr = nullptr;
+    CheckUnsafeCallWithABI check = CheckUnsafeCallWithABI::Check;
     switch (ins->mir()->function()) {
-      case MMathFunction::Floor: funptr = JS_FUNC_TO_DATA_PTR(void*, floorf);           break;
-      case MMathFunction::Round: funptr = JS_FUNC_TO_DATA_PTR(void*, math_roundf_impl); break;
-      case MMathFunction::Ceil:  funptr = JS_FUNC_TO_DATA_PTR(void*, ceilf);            break;
+      case MMathFunction::Floor:
+        funptr = JS_FUNC_TO_DATA_PTR(void*, floorf);
+        check = CheckUnsafeCallWithABI::DontCheckOther;
+        break;
+      case MMathFunction::Round:
+        funptr = JS_FUNC_TO_DATA_PTR(void*, math_roundf_impl);
+        break;
+      case MMathFunction::Ceil:
+        funptr = JS_FUNC_TO_DATA_PTR(void*, ceilf);
+        check = CheckUnsafeCallWithABI::DontCheckOther;
+        break;
       default:
         MOZ_CRASH("Unknown or unsupported float32 math function");
     }
 
-    masm.callWithABI(funptr, MoveOp::FLOAT32);
+    masm.callWithABI(funptr, MoveOp::FLOAT32, check);
 }
 
 void
 CodeGenerator::visitModD(LModD* ins)
 {
     FloatRegister lhs = ToFloatRegister(ins->lhs());
     FloatRegister rhs = ToFloatRegister(ins->rhs());
 
@@ -7953,17 +7967,18 @@ JitRuntime::generateFreeStub(JSContext* 
     LiveRegisterSet save(regs.asLiveSet());
     masm.PushRegsInMask(save);
 
     const Register regTemp = regs.takeAnyGeneral();
     MOZ_ASSERT(regTemp != regSlots);
 
     masm.setupUnalignedABICall(regTemp);
     masm.passABIArg(regSlots);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js_free));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js_free), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckOther);
 
     masm.PopRegsInMask(save);
 
     masm.ret();
 
     Linker linker(masm);
     AutoFlushICache afc("FreeStub");
     JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
@@ -7991,17 +8006,18 @@ JitRuntime::generateLazyLinkStub(JSConte
     Register temp0 = regs.takeAny();
 
     masm.loadJSContext(temp0);
     masm.enterFakeExitFrame(temp0, temp0, ExitFrameToken::LazyLink);
     masm.PushStubCode();
 
     masm.setupUnalignedABICall(temp0);
     masm.passABIArg(temp0);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, LazyLinkTopActivation));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, LazyLinkTopActivation), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     masm.leaveExitFrame(/* stub code */ sizeof(JitCode*));
 
 #ifdef JS_USE_LINK_REGISTER
     // Restore the return address such that the emitPrologue function of the
     // CodeGenerator can push it back on the stack with pushReturnAddress.
     masm.popReturnAddress();
 #endif
@@ -11792,17 +11808,18 @@ CodeGenerator::visitGetDOMProperty(LGetD
     markSafepointAt(safepointOffset, ins);
 
     masm.setupUnalignedABICall(JSContextReg);
     masm.loadJSContext(JSContextReg);
     masm.passABIArg(JSContextReg);
     masm.passABIArg(ObjectReg);
     masm.passABIArg(PrivateReg);
     masm.passABIArg(ValueReg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (ins->mir()->isInfallible()) {
         masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
                        JSReturnOperand);
     } else {
         masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
         masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
@@ -11890,17 +11907,18 @@ CodeGenerator::visitSetDOMProperty(LSetD
     markSafepointAt(safepointOffset, ins);
 
     masm.setupUnalignedABICall(JSContextReg);
     masm.loadJSContext(JSContextReg);
     masm.passABIArg(JSContextReg);
     masm.passABIArg(ObjectReg);
     masm.passABIArg(PrivateReg);
     masm.passABIArg(ValueReg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ins->mir()->fun()), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
     masm.adjustStack(IonDOMExitFrameLayout::Size());
 
     MOZ_ASSERT(masm.framePushed() == initialStack);
 }
 
--- a/js/src/jit/IonCacheIRCompiler.cpp
+++ b/js/src/jit/IonCacheIRCompiler.cpp
@@ -1073,17 +1073,18 @@ IonCacheIRCompiler::emitCallNativeGetter
         return false;
     masm.enterFakeExitFrame(argJSContext, scratch, ExitFrameToken::IonOOLNative);
 
     // Construct and execute call.
     masm.setupUnalignedABICall(scratch);
     masm.passABIArg(argJSContext);
     masm.passABIArg(argUintN);
     masm.passABIArg(argVp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native()));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native()), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     // Test for failure.
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
     // Load the outparam vp[0] into output register(s).
     Address outparam(masm.getStackPointer(), IonOOLNativeExitFrameLayout::offsetOfResult());
     masm.loadValue(outparam, output.valueReg());
 
@@ -1131,17 +1132,18 @@ IonCacheIRCompiler::emitCallProxyGetResu
     masm.enterFakeExitFrame(argJSContext, scratch, ExitFrameToken::IonOOLProxy);
 
     // Make the call.
     masm.setupUnalignedABICall(scratch);
     masm.passABIArg(argJSContext);
     masm.passABIArg(argProxy);
     masm.passABIArg(argId);
     masm.passABIArg(argVp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ProxyGetProperty));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ProxyGetProperty), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     // Test for failure.
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
     // Load the outparam vp[0] into output register(s).
     Address outparam(masm.getStackPointer(), IonOOLProxyExitFrameLayout::offsetOfResult());
     masm.loadValue(outparam, output.valueReg());
 
@@ -1319,16 +1321,17 @@ IonCacheIRCompiler::emitCallStringSplitR
 
     masm.storeCallResultValue(output);
     return true;
 }
 
 static bool
 GroupHasPropertyTypes(ObjectGroup* group, jsid* id, Value* v)
 {
+    AutoUnsafeCallWithABI unsafe;
     if (group->unknownProperties())
         return true;
     HeapTypeSet* propTypes = group->maybeGetProperty(*id);
     if (!propTypes)
         return true;
     if (!propTypes->nonConstantProperty())
         return false;
     return propTypes->hasType(TypeSet::GetValueType(*v));
@@ -1986,17 +1989,18 @@ IonCacheIRCompiler::emitCallNativeSetter
         return false;
     masm.enterFakeExitFrame(argJSContext, scratch, ExitFrameToken::IonOOLNative);
 
     // Make the call.
     masm.setupUnalignedABICall(scratch);
     masm.passABIArg(argJSContext);
     masm.passABIArg(argUintN);
     masm.passABIArg(argVp);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native()));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native()), MoveOp::GENERAL,
+                     CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     // Test for failure.
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
     masm.adjustStack(IonOOLNativeExitFrameLayout::Size(1));
     return true;
 }
 
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -121,18 +121,32 @@ MacroAssembler::passABIArg(Register reg)
 }
 
 void
 MacroAssembler::passABIArg(FloatRegister reg, MoveOp::Type type)
 {
     passABIArg(MoveOperand(reg), type);
 }
 
-template <typename T> void
-MacroAssembler::callWithABI(const T& fun, MoveOp::Type result)
+void
+MacroAssembler::callWithABI(void* fun, MoveOp::Type result, CheckUnsafeCallWithABI check)
+{
+    AutoProfilerCallInstrumentation profiler(*this);
+    callWithABINoProfiler(fun, result, check);
+}
+
+void
+MacroAssembler::callWithABI(Register fun, MoveOp::Type result)
+{
+    AutoProfilerCallInstrumentation profiler(*this);
+    callWithABINoProfiler(fun, result);
+}
+
+void
+MacroAssembler::callWithABI(const Address& fun, MoveOp::Type result)
 {
     AutoProfilerCallInstrumentation profiler(*this);
     callWithABINoProfiler(fun, result);
 }
 
 void
 MacroAssembler::appendSignatureType(MoveOp::Type type)
 {
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -1038,17 +1038,17 @@ FindStartOfUninitializedAndUndefinedSlot
     } else {
         *startOfUninitialized = *startOfUndefined;
     }
 }
 
 static void
 AllocateObjectBufferWithInit(JSContext* cx, TypedArrayObject* obj, int32_t count)
 {
-    JS::AutoCheckCannotGC nogc(cx);
+    AutoUnsafeCallWithABI unsafe;
 
     obj->initPrivate(nullptr);
 
     // Negative numbers or zero will bail out to the slow path, which in turn will raise
     // an invalid argument exception or create a correct object with zero elements.
     if (count <= 0 || uint32_t(count) >= INT32_MAX / obj->bytesPerElement()) {
         obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(0));
         return;
@@ -1545,17 +1545,18 @@ MacroAssembler::generateBailoutTail(Regi
     branch32(Equal, ReturnReg, Imm32(BAILOUT_RETURN_OK), &baseline);
     branch32(Equal, ReturnReg, Imm32(BAILOUT_RETURN_FATAL_ERROR), exceptionLabel());
 
     // Fall-through: overrecursed.
     {
         loadJSContext(ReturnReg);
         setupUnalignedABICall(scratch);
         passABIArg(ReturnReg);
-        callWithABI(JS_FUNC_TO_DATA_PTR(void*, BailoutReportOverRecursed));
+        callWithABI(JS_FUNC_TO_DATA_PTR(void*, BailoutReportOverRecursed), MoveOp::GENERAL,
+                    CheckUnsafeCallWithABI::DontCheckHasExitFrame);
         jump(exceptionLabel());
     }
 
     bind(&baseline);
     {
         // Prepare a register set for use in this case.
         AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
         MOZ_ASSERT(!regs.has(getStackPointer()));
@@ -1610,17 +1611,18 @@ MacroAssembler::generateBailoutTail(Regi
             pushValue(Address(bailoutInfo, offsetof(BaselineBailoutInfo, valueR0)));
             push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeFramePtr)));
             push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr)));
             push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, monitorStub)));
 
             // Call a stub to free allocated memory and create arguments objects.
             setupUnalignedABICall(temp);
             passABIArg(bailoutInfo);
-            callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBailoutToBaseline));
+            callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBailoutToBaseline),
+                        MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
             branchTest32(Zero, ReturnReg, ReturnReg, exceptionLabel());
 
             // Restore values where they need to be and resume execution.
             AllocatableGeneralRegisterSet enterMonRegs(GeneralRegisterSet::All());
             enterMonRegs.take(R0);
             enterMonRegs.take(ICStubReg);
             enterMonRegs.take(BaselineFrameReg);
             enterMonRegs.takeUnchecked(ICTailCallReg);
@@ -1648,17 +1650,18 @@ MacroAssembler::generateBailoutTail(Regi
             pushValue(Address(bailoutInfo, offsetof(BaselineBailoutInfo, valueR0)));
             pushValue(Address(bailoutInfo, offsetof(BaselineBailoutInfo, valueR1)));
             push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeFramePtr)));
             push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr)));
 
             // Call a stub to free allocated memory and create arguments objects.
             setupUnalignedABICall(temp);
             passABIArg(bailoutInfo);
-            callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBailoutToBaseline));
+            callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBailoutToBaseline),
+                        MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
             branchTest32(Zero, ReturnReg, ReturnReg, exceptionLabel());
 
             // Restore values where they need to be and resume execution.
             AllocatableGeneralRegisterSet enterRegs(GeneralRegisterSet::All());
             enterRegs.take(R0);
             enterRegs.take(R1);
             enterRegs.take(BaselineFrameReg);
             Register jitcodeReg = enterRegs.takeAny();
@@ -1724,17 +1727,19 @@ MacroAssembler::assumeUnreachable(const 
         AllocatableRegisterSet regs(RegisterSet::Volatile());
         LiveRegisterSet save(regs.asLiveSet());
         PushRegsInMask(save);
         Register temp = regs.takeAnyGeneral();
 
         setupUnalignedABICall(temp);
         movePtr(ImmPtr(output), temp);
         passABIArg(temp);
-        callWithABI(JS_FUNC_TO_DATA_PTR(void*, AssumeUnreachable_));
+        callWithABI(JS_FUNC_TO_DATA_PTR(void*, AssumeUnreachable_),
+                    MoveOp::GENERAL,
+                    CheckUnsafeCallWithABI::DontCheckOther);
 
         PopRegsInMask(save);
     }
 #endif
 
     breakpoint();
 }
 
@@ -1748,17 +1753,20 @@ MacroAssembler::assertTestInt32(Conditio
     assumeUnreachable(output);
     bind(&ok);
 #endif
 }
 
 template void MacroAssembler::assertTestInt32(Condition, const Address&, const char*);
 
 static void
-Printf0_(const char* output) {
+Printf0_(const char* output)
+{
+    AutoUnsafeCallWithABI unsafe;
+
     // Use stderr instead of stdout because this is only used for debug
     // output. stderr is less likely to interfere with the program's normal
     // output, and it's always unbuffered.
     fprintf(stderr, "%s", output);
 }
 
 void
 MacroAssembler::printf(const char* output)
@@ -1773,17 +1781,19 @@ MacroAssembler::printf(const char* outpu
     movePtr(ImmPtr(output), temp);
     passABIArg(temp);
     callWithABI(JS_FUNC_TO_DATA_PTR(void*, Printf0_));
 
     PopRegsInMask(save);
 }
 
 static void
-Printf1_(const char* output, uintptr_t value) {
+Printf1_(const char* output, uintptr_t value)
+{
+    AutoUnsafeCallWithABI unsafe;
     AutoEnterOOMUnsafeRegion oomUnsafe;
     js::UniqueChars line = JS_sprintf_append(nullptr, output, value);
     if (!line)
         oomUnsafe.crash("OOM at masm.printf");
     fprintf(stderr, "%s", line.get());
 }
 
 void
@@ -1819,17 +1829,18 @@ MacroAssembler::tracelogStartId(Register
     regs.takeUnchecked(logger);
 
     Register temp = regs.takeAnyGeneral();
 
     setupUnalignedABICall(temp);
     passABIArg(logger);
     move32(Imm32(textId), temp);
     passABIArg(temp);
-    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStartEventPrivate));
+    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStartEventPrivate), MoveOp::GENERAL,
+                CheckUnsafeCallWithABI::DontCheckOther);
 
     PopRegsInMask(save);
 }
 
 void
 MacroAssembler::tracelogStartId(Register logger, Register textId)
 {
     AllocatableRegisterSet regs(RegisterSet::Volatile());
@@ -1838,17 +1849,18 @@ MacroAssembler::tracelogStartId(Register
     regs.takeUnchecked(logger);
     regs.takeUnchecked(textId);
 
     Register temp = regs.takeAnyGeneral();
 
     setupUnalignedABICall(temp);
     passABIArg(logger);
     passABIArg(textId);
-    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStartEventPrivate));
+    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStartEventPrivate), MoveOp::GENERAL,
+                CheckUnsafeCallWithABI::DontCheckOther);
 
     PopRegsInMask(save);
 }
 
 void
 MacroAssembler::tracelogStartEvent(Register logger, Register event)
 {
     void (&TraceLogFunc)(TraceLoggerThread*, const TraceLoggerEvent&) = TraceLogStartEvent;
@@ -1859,17 +1871,18 @@ MacroAssembler::tracelogStartEvent(Regis
     regs.takeUnchecked(logger);
     regs.takeUnchecked(event);
 
     Register temp = regs.takeAnyGeneral();
 
     setupUnalignedABICall(temp);
     passABIArg(logger);
     passABIArg(event);
-    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogFunc));
+    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogFunc), MoveOp::GENERAL,
+                CheckUnsafeCallWithABI::DontCheckOther);
 
     PopRegsInMask(save);
 }
 
 void
 MacroAssembler::tracelogStopId(Register logger, uint32_t textId, bool force)
 {
     if (!force && !TraceLogTextIdEnabled(textId))
@@ -1882,17 +1895,18 @@ MacroAssembler::tracelogStopId(Register 
 
     Register temp = regs.takeAnyGeneral();
 
     setupUnalignedABICall(temp);
     passABIArg(logger);
     move32(Imm32(textId), temp);
     passABIArg(temp);
 
-    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStopEventPrivate));
+    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStopEventPrivate), MoveOp::GENERAL,
+                CheckUnsafeCallWithABI::DontCheckOther);
 
     PopRegsInMask(save);
 }
 
 void
 MacroAssembler::tracelogStopId(Register logger, Register textId)
 {
     AllocatableRegisterSet regs(RegisterSet::Volatile());
@@ -1901,17 +1915,18 @@ MacroAssembler::tracelogStopId(Register 
     regs.takeUnchecked(logger);
     regs.takeUnchecked(textId);
 
     Register temp = regs.takeAnyGeneral();
 
     setupUnalignedABICall(temp);
     passABIArg(logger);
     passABIArg(textId);
-    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStopEventPrivate));
+    callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStopEventPrivate), MoveOp::GENERAL,
+                CheckUnsafeCallWithABI::DontCheckOther);
 
     PopRegsInMask(save);
 }
 #endif
 
 void
 MacroAssembler::convertInt32ValueToDouble(const Address& address, Register scratch, Label* done)
 {
@@ -2102,17 +2117,18 @@ MacroAssembler::outOfLineTruncateSlow(Fl
 
     if (compilingWasm) {
         setupWasmABICall();
         passABIArg(src, MoveOp::DOUBLE);
         callWithABI(callOffset, wasm::SymbolicAddress::ToInt32);
     } else {
         setupUnalignedABICall(dest);
         passABIArg(src, MoveOp::DOUBLE);
-        callWithABI(mozilla::BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32));
+        callWithABI(mozilla::BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32),
+                    MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckOther);
     }
     storeCallWordResult(dest);
 
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
     defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     // Nothing
 #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     if (widenFloatToDouble)
@@ -2796,27 +2812,52 @@ MacroAssembler::passABIArg(const MoveOpe
         return;
 
     if (oom())
         return;
     propagateOOM(moveResolver_.addMove(from, to, type));
 }
 
 void
-MacroAssembler::callWithABINoProfiler(void* fun, MoveOp::Type result)
+MacroAssembler::callWithABINoProfiler(void* fun, MoveOp::Type result, CheckUnsafeCallWithABI check)
 {
     appendSignatureType(result);
 #ifdef JS_SIMULATOR
     fun = Simulator::RedirectNativeFunction(fun, signature());
 #endif
 
     uint32_t stackAdjust;
     callWithABIPre(&stackAdjust);
+
+#ifdef DEBUG
+    if (check == CheckUnsafeCallWithABI::Check) {
+        push(ReturnReg);
+        loadJSContext(ReturnReg);
+        Address flagAddr(ReturnReg, JSContext::offsetOfInUnsafeCallWithABI());
+        store32(Imm32(1), flagAddr);
+        pop(ReturnReg);
+    }
+#endif
+
     call(ImmPtr(fun));
+
     callWithABIPost(stackAdjust, result);
+
+#ifdef DEBUG
+    if (check == CheckUnsafeCallWithABI::Check) {
+        Label ok;
+        push(ReturnReg);
+        loadJSContext(ReturnReg);
+        Address flagAddr(ReturnReg, JSContext::offsetOfInUnsafeCallWithABI());
+        branch32(Assembler::Equal, flagAddr, Imm32(0), &ok);
+        assumeUnreachable("callWithABI: callee did not use AutoInUnsafeCallWithABI");
+        bind(&ok);
+        pop(ReturnReg);
+    }
+#endif
 }
 
 void
 MacroAssembler::callWithABI(wasm::BytecodeOffset callOffset, wasm::SymbolicAddress imm,
                             MoveOp::Type result)
 {
     MOZ_ASSERT(wasm::NeedsBuiltinThunk(imm));
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -188,16 +188,30 @@ using mozilla::FloatingPoint;
 namespace js {
 namespace jit {
 
 // Defined in JitFrames.h
 enum class ExitFrameToken : uint8_t;
 
 class AutoSaveLiveRegisters;
 
+enum class CheckUnsafeCallWithABI {
+    // Require the callee to use AutoUnsafeCallWithABI.
+    Check,
+
+    // We pushed an exit frame so this callWithABI can safely GC and walk the
+    // stack.
+    DontCheckHasExitFrame,
+
+    // Don't check this callWithABI uses AutoUnsafeCallWithABI, for instance
+    // because we're calling a simple helper function (like malloc or js_free)
+    // that we can't change and/or that we know won't GC.
+    DontCheckOther,
+};
+
 // The public entrypoint for emitting assembly. Note that a MacroAssembler can
 // use cx->lifoAlloc, so take care not to interleave masm use with other
 // lifoAlloc use if one will be destroyed before the other.
 class MacroAssembler : public MacroAssemblerSpecific
 {
     MacroAssembler* thisFromCtor() {
         return this;
     }
@@ -560,32 +574,34 @@ class MacroAssembler : public MacroAssem
     // temporarily use more stack, in which case esp-relative addresses will be
     // automatically adjusted. It is extremely important that esp-relative
     // addresses are computed *after* setupABICall(). Furthermore, no
     // operations should be emitted while setting arguments.
     void passABIArg(const MoveOperand& from, MoveOp::Type type);
     inline void passABIArg(Register reg);
     inline void passABIArg(FloatRegister reg, MoveOp::Type type);
 
-    template <typename T>
-    inline void callWithABI(const T& fun, MoveOp::Type result = MoveOp::GENERAL);
+    inline void callWithABI(void* fun, MoveOp::Type result = MoveOp::GENERAL,
+                            CheckUnsafeCallWithABI check = CheckUnsafeCallWithABI::Check);
+    inline void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
+    inline void callWithABI(const Address& fun, MoveOp::Type result = MoveOp::GENERAL);
 
     void callWithABI(wasm::BytecodeOffset offset, wasm::SymbolicAddress fun,
                      MoveOp::Type result = MoveOp::GENERAL);
 
   private:
     // Reinitialize the variables which have to be cleared before making a call
     // with callWithABI.
     void setupABICall();
 
     // Reserve the stack and resolve the arguments move.
     void callWithABIPre(uint32_t* stackAdjust, bool callFromWasm = false) PER_ARCH;
 
     // Emits a call to a C/C++ function, resolving all argument moves.
-    void callWithABINoProfiler(void* fun, MoveOp::Type result);
+    void callWithABINoProfiler(void* fun, MoveOp::Type result, CheckUnsafeCallWithABI check);
     void callWithABINoProfiler(Register fun, MoveOp::Type result) PER_ARCH;
     void callWithABINoProfiler(const Address& fun, MoveOp::Type result) PER_ARCH;
 
     // Restore the stack to its state before the setup function call.
     void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result, bool callFromWasm = false) PER_ARCH;
 
     // Create the signature to be able to decode the arguments of a native
     // function, when calling a function within the simulator.
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -1200,17 +1200,18 @@ ICBinaryArith_DoubleWithInt32::Compiler:
         Label truncateABICall;
         masm.branchTruncateDoubleMaybeModUint32(FloatReg0, scratchReg, &truncateABICall);
         masm.jump(&doneTruncate);
 
         masm.bind(&truncateABICall);
         masm.push(intReg);
         masm.setupUnalignedABICall(scratchReg);
         masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
-        masm.callWithABI(mozilla::BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32));
+        masm.callWithABI(mozilla::BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32),
+                         MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckOther);
         masm.storeCallWordResult(scratchReg);
         masm.pop(intReg);
 
         masm.bind(&doneTruncate);
     }
 
     Register intReg2 = scratchReg;
     // All handled ops commute, so no need to worry about ordering.
@@ -1353,17 +1354,18 @@ ICUnaryArith_Double::Compiler::generateS
         Label doneTruncate;
         Label truncateABICall;
         masm.branchTruncateDoubleMaybeModUint32(FloatReg0, scratchReg, &truncateABICall);
         masm.jump(&doneTruncate);
 
         masm.bind(&truncateABICall);
         masm.setupUnalignedABICall(scratchReg);
         masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
-        masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32));
+        masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32),
+                         MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckOther);
         masm.storeCallWordResult(scratchReg);
 
         masm.bind(&doneTruncate);
         masm.not32(scratchReg);
         masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
     }
 
     EmitReturnFromIC(masm);
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -539,16 +539,17 @@ InterruptCheck(JSContext* cx)
     }
 
     return CheckForInterrupt(cx);
 }
 
 void*
 MallocWrapper(JSRuntime* rt, size_t nbytes)
 {
+    AutoUnsafeCallWithABI unsafe;
     return rt->pod_malloc<uint8_t>(nbytes);
 }
 
 JSObject*
 NewCallObject(JSContext* cx, HandleShape shape, HandleObjectGroup group)
 {
     JSObject* obj = CallObject::create(cx, shape, group);
     if (!obj)
@@ -644,16 +645,18 @@ CreateThis(JSContext* cx, HandleObject c
 
 void
 GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp)
 {
     // Lookup a string on the env chain, returning either the value found or
     // undefined through rval. This function is infallible, and cannot GC or
     // invalidate.
 
+    AutoUnsafeCallWithABI unsafe;
+
     JSAtom* atom;
     if (str->isAtom()) {
         atom = &str->asAtom();
     } else {
         atom = AtomizeString(cx, str);
         if (!atom) {
             vp->setUndefined();
             return;
@@ -674,28 +677,28 @@ GetDynamicName(JSContext* cx, JSObject* 
     }
 
     vp->setUndefined();
 }
 
 void
 PostWriteBarrier(JSRuntime* rt, JSObject* obj)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
     MOZ_ASSERT(!IsInsideNursery(obj));
     rt->gc.storeBuffer().putWholeCell(obj);
 }
 
 static const size_t MAX_WHOLE_CELL_BUFFER_SIZE = 4096;
 
 template <IndexInBounds InBounds>
 void
 PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(!IsInsideNursery(obj));
 
     if (InBounds == IndexInBounds::Yes) {
         MOZ_ASSERT(uint32_t(index) < obj->as<NativeObject>().getDenseInitializedLength());
     } else {
         if (MOZ_UNLIKELY(!obj->is<NativeObject>()) ||
             uint32_t(index) >= obj->as<NativeObject>().getDenseInitializedLength())
@@ -739,33 +742,33 @@ PostGlobalWriteBarrier(JSRuntime* rt, JS
         obj->compartment()->globalWriteBarriered = 1;
     }
 }
 
 int32_t
 GetIndexFromString(JSString* str)
 {
     // We shouldn't GC here as this is called directly from IC code.
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     if (!str->isFlat())
         return -1;
 
     uint32_t index;
     if (!str->asFlat().isIndex(&index) || index > INT32_MAX)
         return -1;
 
     return int32_t(index);
 }
 
 JSObject*
 WrapObjectPure(JSContext* cx, JSObject* obj)
 {
     // IC code calls this directly so we shouldn't GC.
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(obj);
     MOZ_ASSERT(cx->compartment() != obj->compartment());
 
     // From: JSCompartment::getNonWrapperObjectForCurrentCompartment
     // Note that if the object is same-compartment, but has been wrapped into a
     // different compartment, we need to unwrap it and return the bare same-
     // compartment object. Note again that windows are always wrapped by a
@@ -859,16 +862,17 @@ DebugEpilogue(JSContext* cx, BaselineFra
     // builds after each callVM, to ensure this flag is not set.
     frame->clearOverridePc();
     return true;
 }
 
 void
 FrameIsDebuggeeCheck(BaselineFrame* frame)
 {
+    AutoUnsafeCallWithABI unsafe;
     if (frame->script()->isDebuggee())
         frame->setIsDebuggee();
 }
 
 JSObject*
 CreateGenerator(JSContext* cx, BaselineFrame* frame)
 {
     return GeneratorObject::create(cx, frame);
@@ -1135,16 +1139,17 @@ OnDebuggerStatement(JSContext* cx, Basel
       default:
         MOZ_CRASH("Invalid trap status");
     }
 }
 
 bool
 GlobalHasLiveOnDebuggerStatement(JSContext* cx)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cx->compartment()->isDebuggee() &&
            Debugger::hasLiveHook(cx->global(), Debugger::OnDebuggerStatement);
 }
 
 bool
 PushLexicalEnv(JSContext* cx, BaselineFrame* frame, Handle<LexicalScope*> scope)
 {
     return frame->pushLexicalEnvironment(cx, scope);
@@ -1227,16 +1232,17 @@ LeaveWith(JSContext* cx, BaselineFrame* 
     frame->popOffEnvironmentChain<WithEnvironmentObject>();
     return true;
 }
 
 bool
 InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame,
                         uint32_t numStackValues)
 {
+    AutoUnsafeCallWithABI unsafe;
     return frame->initForOsr(interpFrame, numStackValues);
 }
 
 JSObject*
 CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
                       HandleObject owner, int32_t offset)
 {
     MOZ_ASSERT(descr->is<TypeDescr>());
@@ -1313,16 +1319,17 @@ void
 AutoDetectInvalidation::setReturnOverride()
 {
     cx_->setIonReturnOverride(rval_.get());
 }
 
 void
 AssertValidObjectPtr(JSContext* cx, JSObject* obj)
 {
+    AutoUnsafeCallWithABI unsafe;
 #ifdef DEBUG
     // Check what we can, so that we'll hopefully assert/crash if we get a
     // bogus object (pointer).
     MOZ_ASSERT(obj->compartment() == cx->compartment());
     MOZ_ASSERT(obj->runtimeFromActiveCooperatingThread() == cx->runtime());
 
     MOZ_ASSERT_IF(!obj->hasLazyGroup() && obj->maybeShape(),
                   obj->group()->clasp() == obj->maybeShape()->getObjectClass());
@@ -1334,23 +1341,25 @@ AssertValidObjectPtr(JSContext* cx, JSOb
         MOZ_ASSERT(obj->asTenured().zone() == cx->zone());
     }
 #endif
 }
 
 void
 AssertValidObjectOrNullPtr(JSContext* cx, JSObject* obj)
 {
+    AutoUnsafeCallWithABI unsafe;
     if (obj)
         AssertValidObjectPtr(cx, obj);
 }
 
 void
 AssertValidStringPtr(JSContext* cx, JSString* str)
 {
+    AutoUnsafeCallWithABI unsafe;
 #ifdef DEBUG
     // We can't closely inspect strings from another runtime.
     if (str->runtimeFromAnyThread() != cx->runtime()) {
         MOZ_ASSERT(str->isPermanentAtom());
         return;
     }
 
     if (str->isAtom())
@@ -1377,16 +1386,18 @@ AssertValidStringPtr(JSContext* cx, JSSt
         MOZ_ASSERT(kind == gc::AllocKind::STRING);
     }
 #endif
 }
 
 void
 AssertValidSymbolPtr(JSContext* cx, JS::Symbol* sym)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     // We can't closely inspect symbols from another runtime.
     if (sym->runtimeFromAnyThread() != cx->runtime()) {
         MOZ_ASSERT(sym->isWellKnownSymbol());
         return;
     }
 
     MOZ_ASSERT(sym->zone()->isAtomsZone());
     MOZ_ASSERT(sym->isAligned());
@@ -1396,65 +1407,73 @@ AssertValidSymbolPtr(JSContext* cx, JS::
     }
 
     MOZ_ASSERT(sym->getAllocKind() == gc::AllocKind::SYMBOL);
 }
 
 void
 AssertValidValue(JSContext* cx, Value* v)
 {
+    AutoUnsafeCallWithABI unsafe;
     if (v->isObject())
         AssertValidObjectPtr(cx, &v->toObject());
     else if (v->isString())
         AssertValidStringPtr(cx, v->toString());
     else if (v->isSymbol())
         AssertValidSymbolPtr(cx, v->toSymbol());
 }
 
 bool
 ObjectIsCallable(JSObject* obj)
 {
+    AutoUnsafeCallWithABI unsafe;
     return obj->isCallable();
 }
 
 bool
 ObjectIsConstructor(JSObject* obj)
 {
+    AutoUnsafeCallWithABI unsafe;
     return obj->isConstructor();
 }
 
 void
 MarkValueFromIon(JSRuntime* rt, Value* vp)
 {
+    AutoUnsafeCallWithABI unsafe;
     TraceManuallyBarrieredEdge(&rt->gc.marker, vp, "write barrier");
 }
 
 void
 MarkStringFromIon(JSRuntime* rt, JSString** stringp)
 {
+    AutoUnsafeCallWithABI unsafe;
     MOZ_ASSERT(*stringp);
     TraceManuallyBarrieredEdge(&rt->gc.marker, stringp, "write barrier");
 }
 
 void
 MarkObjectFromIon(JSRuntime* rt, JSObject** objp)
 {
+    AutoUnsafeCallWithABI unsafe;
     MOZ_ASSERT(*objp);
     TraceManuallyBarrieredEdge(&rt->gc.marker, objp, "write barrier");
 }
 
 void
 MarkShapeFromIon(JSRuntime* rt, Shape** shapep)
 {
+    AutoUnsafeCallWithABI unsafe;
     TraceManuallyBarrieredEdge(&rt->gc.marker, shapep, "write barrier");
 }
 
 void
 MarkObjectGroupFromIon(JSRuntime* rt, ObjectGroup** groupp)
 {
+    AutoUnsafeCallWithABI unsafe;
     TraceManuallyBarrieredEdge(&rt->gc.marker, groupp, "write barrier");
 }
 
 bool
 ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber)
 {
     ScriptFrameIter iter(cx);
     RootedScript script(cx, iter.script());
@@ -1546,17 +1565,17 @@ CallNativeSetter(JSContext* cx, HandleFu
 
     return natfun(cx, 1, vp.begin());
 }
 
 bool
 EqualStringsHelper(JSString* str1, JSString* str2)
 {
     // IC code calls this directly so we shouldn't GC.
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(str1->isAtom());
     MOZ_ASSERT(!str2->isAtom());
     MOZ_ASSERT(str1->length() == str2->length());
 
     JSLinearString* str2Linear = str2->ensureLinear(nullptr);
     if (!str2Linear)
         return false;
@@ -1576,17 +1595,17 @@ CheckIsCallable(JSContext* cx, HandleVal
 template <bool HandleMissing>
 static MOZ_ALWAYS_INLINE bool
 GetNativeDataProperty(JSContext* cx, NativeObject* obj, jsid id, Value* vp)
 {
     // Fast path used by megamorphic IC stubs. Unlike our other property
     // lookup paths, this is optimized to be as fast as possible for simple
     // data property lookups.
 
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(JSID_IS_ATOM(id) || JSID_IS_SYMBOL(id));
 
     while (true) {
         if (Shape* shape = obj->lastProperty()->search(cx, id)) {
             if (!shape->hasSlot() || !shape->hasDefaultGetter())
                 return false;
 
@@ -1628,17 +1647,17 @@ template bool
 GetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
 
 template bool
 GetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* vp);
 
 static MOZ_ALWAYS_INLINE bool
 ValueToAtomOrSymbol(JSContext* cx, Value& idVal, jsid* id)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     if (MOZ_LIKELY(idVal.isString())) {
         JSString* s = idVal.toString();
         JSAtom* atom;
         if (s->isAtom()) {
             atom = &s->asAtom();
         } else {
             atom = AtomizeString(cx, s);
@@ -1661,17 +1680,17 @@ ValueToAtomOrSymbol(JSContext* cx, Value
 
     return true;
 }
 
 template <bool HandleMissing>
 bool
 GetNativeDataPropertyByValue(JSContext* cx, JSObject* obj, Value* vp)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     // Condition checked by caller.
     MOZ_ASSERT(obj->isNative());
 
     // vp[0] contains the id, result will be stored in vp[1].
     Value idVal = vp[0];
     jsid id;
     if (!ValueToAtomOrSymbol(cx, idVal, &id))
@@ -1686,17 +1705,17 @@ GetNativeDataPropertyByValue<true>(JSCon
 
 template bool
 GetNativeDataPropertyByValue<false>(JSContext* cx, JSObject* obj, Value* vp);
 
 template <bool NeedsTypeBarrier>
 bool
 SetNativeDataProperty(JSContext* cx, JSObject* obj, PropertyName* name, Value* val)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     if (MOZ_UNLIKELY(!obj->isNative()))
         return false;
 
     NativeObject* nobj = &obj->as<NativeObject>();
     Shape* shape = nobj->lastProperty()->search(cx, NameToId(name));
     if (!shape ||
         !shape->hasSlot() ||
@@ -1718,17 +1737,17 @@ template bool
 SetNativeDataProperty<true>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
 
 template bool
 SetNativeDataProperty<false>(JSContext* cx, JSObject* obj, PropertyName* name, Value* val);
 
 bool
 ObjectHasGetterSetter(JSContext* cx, JSObject* objArg, Shape* propShape)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(propShape->hasGetterObject() || propShape->hasSetterObject());
 
     // Window objects may require outerizing (passing the WindowProxy to the
     // getter/setter), so we don't support them here.
     if (MOZ_UNLIKELY(!objArg->isNative() || IsWindow(objArg)))
         return false;
 
@@ -1761,17 +1780,17 @@ ObjectHasGetterSetter(JSContext* cx, JSO
             return false;
         nobj = &proto->as<NativeObject>();
     }
 }
 
 bool
 HasOwnNativeDataProperty(JSContext* cx, JSObject* obj, Value* vp)
 {
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     // vp[0] contains the id, result will be stored in vp[1].
     Value idVal = vp[0];
     jsid id;
     if (!ValueToAtomOrSymbol(cx, idVal, &id))
         return false;
 
     if (!obj->isNative()) {
@@ -1798,16 +1817,17 @@ HasOwnNativeDataProperty(JSContext* cx, 
     // Missing property.
     vp[1].setBoolean(false);
     return true;
 }
 
 JSString*
 TypeOfObject(JSObject* obj, JSRuntime* rt)
 {
+    AutoUnsafeCallWithABI unsafe;
     JSType type = js::TypeOfObject(obj);
     return TypeName(type, *rt->commonNames);
 }
 
 bool
 GetPrototypeOf(JSContext* cx, HandleObject target, MutableHandleValue rval)
 {
     MOZ_ASSERT(target->hasDynamicPrototype());
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -625,17 +625,18 @@ CodeGeneratorARM::visitSoftDivI(LSoftDiv
         masm.setupWasmABICall();
         masm.passABIArg(lhs);
         masm.passABIArg(rhs);
         masm.callWithABI(mir->bytecodeOffset(), wasm::SymbolicAddress::aeabi_idivmod);
     } else {
         masm.setupAlignedABICall();
         masm.passABIArg(lhs);
         masm.passABIArg(rhs);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckOther);
     }
 
     // idivmod returns the quotient in r0, and the remainder in r1.
     if (!mir->canTruncateRemainder()) {
         MOZ_ASSERT(mir->fallible());
         masm.as_cmp(r1, Imm8(0));
         bailoutIf(Assembler::NonZero, ins->snapshot());
     }
@@ -814,17 +815,18 @@ CodeGeneratorARM::visitSoftModI(LSoftMod
         masm.setupWasmABICall();
         masm.passABIArg(lhs);
         masm.passABIArg(rhs);
         masm.callWithABI(mir->bytecodeOffset(), wasm::SymbolicAddress::aeabi_idivmod);
     } else {
         masm.setupAlignedABICall();
         masm.passABIArg(lhs);
         masm.passABIArg(rhs);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckOther);
     }
 
     MOZ_ASSERT(r1 != output);
     masm.move32(r1, output);
 
     // If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0
     if (mir->canBeNegativeDividend()) {
         if (mir->isTruncated()) {
@@ -2836,17 +2838,18 @@ CodeGeneratorARM::visitSoftUDivOrMod(LSo
         masm.passABIArg(lhs);
         masm.passABIArg(rhs);
         wasm::BytecodeOffset bytecodeOffset = (div ? div->bytecodeOffset() : mod->bytecodeOffset());
         masm.callWithABI(bytecodeOffset, wasm::SymbolicAddress::aeabi_uidivmod);
     } else {
         masm.setupAlignedABICall();
         masm.passABIArg(lhs);
         masm.passABIArg(rhs);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_uidivmod));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_uidivmod), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckOther);
     }
 
     if (mod) {
         MOZ_ASSERT(output == r0, "output should not be r1 for mod");
         masm.move32(r1, output);
     }
 
     // uidivmod returns the quotient in r0, and the remainder in r1.
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3593,17 +3593,17 @@ MacroAssemblerARMCompat::handleFailureWi
 
     Imm8 size8(size);
     as_sub(sp, sp, size8);
     ma_mov(sp, r0);
 
     // Call the handler.
     asMasm().setupUnalignedABICall(r1);
     asMasm().passABIArg(r0);
-    asMasm().callWithABI(handler);
+    asMasm().callWithABI(handler, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     Label entryFrame;
     Label catch_;
     Label finally;
     Label return_;
     Label bailout;
 
     {
--- a/js/src/jit/arm/SharedIC-arm.cpp
+++ b/js/src/jit/arm/SharedIC-arm.cpp
@@ -89,17 +89,18 @@ ICBinaryArith_Int32::Compiler::generateS
         // register.
         MOZ_ASSERT(R1 == ValueOperand(r5, r4));
         MOZ_ASSERT(R0 == ValueOperand(r3, r2));
         masm.moveValue(R0, savedValue);
 
         masm.setupAlignedABICall();
         masm.passABIArg(R0.payloadReg());
         masm.passABIArg(R1.payloadReg());
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod));
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod), MoveOp::GENERAL,
+                         CheckUnsafeCallWithABI::DontCheckOther);
 
         // idivmod returns the quotient in r0, and the remainder in r1.
         if (op_ == JSOP_DIV) {
             // Result is a double if the remainder != 0.
             masm.branch32(Assembler::NotEqual, r1, Imm32(0), &revertRegister);
             masm.tagValue(JSVAL_TYPE_INT32, r0, R0);
         } else {
             // If X % Y == 0 and X < 0, the result is -0.
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -877,17 +877,17 @@ JitRuntime::generateVMWrapper(JSContext*
             break;
         }
     }
 
     // Copy the implicit outparam, if any.
     if (outReg != InvalidReg)
         masm.passABIArg(outReg);
 
-    masm.callWithABI(f.wrapped);
+    masm.callWithABI(f.wrapped, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (!generateTLExitVM(cx, masm, f))
         return nullptr;
 
     // Test for failure.
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, r0, r0, masm.failureLabel());
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -140,17 +140,17 @@ MacroAssemblerCompat::handleFailureWithH
     if (!GetStackPointer64().Is(sp))
         Mov(sp, GetStackPointer64());
 
     Mov(x0, GetStackPointer64());
 
     // Call the handler.
     asMasm().setupUnalignedABICall(r1);
     asMasm().passABIArg(r0);
-    asMasm().callWithABI(handler);
+    asMasm().callWithABI(handler, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     Label entryFrame;
     Label catch_;
     Label finally;
     Label return_;
     Label bailout;
 
     MOZ_ASSERT(GetStackPointer64().Is(x28)); // Lets the code below be a little cleaner.
--- a/js/src/jit/arm64/Trampoline-arm64.cpp
+++ b/js/src/jit/arm64/Trampoline-arm64.cpp
@@ -672,17 +672,17 @@ JitRuntime::generateVMWrapper(JSContext*
 
     // Copy the semi-implicit outparam, if any.
     // It is not a C++-abi outparam, which would get passed in the
     // outparam register, but a real parameter to the function, which
     // was stack-allocated above.
     if (outReg != InvalidReg)
         masm.passABIArg(outReg);
 
-    masm.callWithABI(f.wrapped);
+    masm.callWithABI(f.wrapped, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (!generateTLExitVM(cx, masm, f))
         return nullptr;
 
     // SP is used to transfer stack across call boundaries.
     if (!masm.GetStackPointer64().Is(vixl::sp))
         masm.Mov(masm.GetStackPointer64(), vixl::sp);
 
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -1843,17 +1843,17 @@ MacroAssemblerMIPSCompat::handleFailureW
     // Reserve space for exception information.
     int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1);
     asMasm().subPtr(Imm32(size), StackPointer);
     ma_move(a0, StackPointer); // Use a0 since it is a first function argument
 
     // Call the handler.
     asMasm().setupUnalignedABICall(a1);
     asMasm().passABIArg(a0);
-    asMasm().callWithABI(handler);
+    asMasm().callWithABI(handler, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     Label entryFrame;
     Label catch_;
     Label finally;
     Label return_;
     Label bailout;
 
     // Already clobbered a0, so use it...
--- a/js/src/jit/mips32/Trampoline-mips32.cpp
+++ b/js/src/jit/mips32/Trampoline-mips32.cpp
@@ -842,17 +842,17 @@ JitRuntime::generateVMWrapper(JSContext*
                   doubleArgDisp + sizeof(double) == outParamOffset + outParamSize);
 
     // Copy the implicit outparam, if any.
     if (f.outParam != Type_Void) {
         masm.passABIArg(MoveOperand(doubleArgs, outParamOffset, MoveOperand::EFFECTIVE_ADDRESS),
                             MoveOp::GENERAL);
     }
 
-    masm.callWithABI(f.wrapped);
+    masm.callWithABI(f.wrapped, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (!generateTLExitVM(cx, masm, f))
         return nullptr;
 
     // Test for failure.
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, v0, v0, masm.failureLabel());
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -2025,17 +2025,17 @@ MacroAssemblerMIPS64Compat::handleFailur
     // Reserve space for exception information.
     int size = (sizeof(ResumeFromException) + ABIStackAlignment) & ~(ABIStackAlignment - 1);
     asMasm().subPtr(Imm32(size), StackPointer);
     ma_move(a0, StackPointer); // Use a0 since it is a first function argument
 
     // Call the handler.
     asMasm().setupUnalignedABICall(a1);
     asMasm().passABIArg(a0);
-    asMasm().callWithABI(handler);
+    asMasm().callWithABI(handler, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     Label entryFrame;
     Label catch_;
     Label finally;
     Label return_;
     Label bailout;
 
     // Already clobbered a0, so use it...
--- a/js/src/jit/mips64/Trampoline-mips64.cpp
+++ b/js/src/jit/mips64/Trampoline-mips64.cpp
@@ -788,17 +788,17 @@ JitRuntime::generateVMWrapper(JSContext*
             break;
         }
     }
 
     // Copy the implicit outparam, if any.
     if (InvalidReg != outReg)
         masm.passABIArg(outReg);
 
-    masm.callWithABI(f.wrapped);
+    masm.callWithABI(f.wrapped, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (!generateTLExitVM(cx, masm, f))
         return nullptr;
 
     // Test for failure.
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, v0, v0, masm.failureLabel());
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -302,17 +302,17 @@ MacroAssemblerX64::handleFailureWithHand
 {
     // Reserve space for exception information.
     subq(Imm32(sizeof(ResumeFromException)), rsp);
     movq(rsp, rax);
 
     // Call the handler.
     asMasm().setupUnalignedABICall(rcx);
     asMasm().passABIArg(rax);
-    asMasm().callWithABI(handler);
+    asMasm().callWithABI(handler, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     Label entryFrame;
     Label catch_;
     Label finally;
     Label return_;
     Label bailout;
 
     load32(Address(rsp, offsetof(ResumeFromException, kind)), rax);
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -760,17 +760,17 @@ JitRuntime::generateVMWrapper(JSContext*
             MOZ_CRASH("NYI: x64 callVM should not be used with 128bits values.");
         }
     }
 
     // Copy the implicit outparam, if any.
     if (outReg != InvalidReg)
         masm.passABIArg(outReg);
 
-    masm.callWithABI(f.wrapped);
+    masm.callWithABI(f.wrapped, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (!generateTLExitVM(cx, masm, f))
         return nullptr;
 
     // Test for failure.
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, rax, rax, masm.failureLabel());
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -739,17 +739,18 @@ CodeGeneratorX86::visitOutOfLineTruncate
 
         if (gen->compilingWasm()) {
             masm.setupWasmABICall();
             masm.passABIArg(input, MoveOp::DOUBLE);
             masm.callWithABI(ins->mir()->bytecodeOffset(), wasm::SymbolicAddress::ToInt32);
         } else {
             masm.setupUnalignedABICall(output);
             masm.passABIArg(input, MoveOp::DOUBLE);
-            masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32));
+            masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32), MoveOp::GENERAL,
+                             CheckUnsafeCallWithABI::DontCheckOther);
         }
         masm.storeCallWordResult(output);
 
         restoreVolatile(output);
     }
 
     masm.jump(ool->rejoin());
 }
@@ -826,20 +827,22 @@ CodeGeneratorX86::visitOutOfLineTruncate
         if (gen->compilingWasm())
             masm.setupWasmABICall();
         else
             masm.setupUnalignedABICall(output);
 
         masm.vcvtss2sd(input, input, input);
         masm.passABIArg(input.asDouble(), MoveOp::DOUBLE);
 
-        if (gen->compilingWasm())
+        if (gen->compilingWasm()) {
             masm.callWithABI(ins->mir()->bytecodeOffset(), wasm::SymbolicAddress::ToInt32);
-        else
-            masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32));
+        } else {
+            masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32), MoveOp::GENERAL,
+                             CheckUnsafeCallWithABI::DontCheckOther);
+        }
 
         masm.storeCallWordResult(output);
         masm.Pop(input);
 
         restoreVolatile(output);
     }
 
     masm.jump(ool->rejoin());
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -201,17 +201,17 @@ MacroAssemblerX86::handleFailureWithHand
 {
     // Reserve space for exception information.
     subl(Imm32(sizeof(ResumeFromException)), esp);
     movl(esp, eax);
 
     // Call the handler.
     asMasm().setupUnalignedABICall(ecx);
     asMasm().passABIArg(eax);
-    asMasm().callWithABI(handler);
+    asMasm().callWithABI(handler, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     Label entryFrame;
     Label catch_;
     Label finally;
     Label return_;
     Label bailout;
 
     loadPtr(Address(esp, offsetof(ResumeFromException, kind)), eax);
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -790,17 +790,17 @@ JitRuntime::generateVMWrapper(JSContext*
             break;
         }
     }
 
     // Copy the implicit outparam, if any.
     if (outReg != InvalidReg)
         masm.passABIArg(outReg);
 
-    masm.callWithABI(f.wrapped);
+    masm.callWithABI(f.wrapped, MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckHasExitFrame);
 
     if (!generateTLExitVM(cx, masm, f))
         return nullptr;
 
     // Test for failure.
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, eax, eax, masm.failureLabel());
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1152,17 +1152,21 @@ class JS_PUBLIC_API(ContextOptions) {
         nativeRegExp_(true),
         unboxedArrays_(false),
         asyncStack_(true),
         throwOnDebuggeeWouldRun_(true),
         dumpStackOnDebuggeeWouldRun_(false),
         werror_(false),
         strictMode_(false),
         extraWarnings_(false),
-        forEachStatement_(false)
+        forEachStatement_(false),
+        streams_(false)
+#ifdef FUZZING
+        , fuzzing_(false)
+#endif
     {
     }
 
     bool baseline() const { return baseline_; }
     ContextOptions& setBaseline(bool flag) {
         baseline_ = flag;
         return *this;
     }
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2419,16 +2419,17 @@ ShiftMoveBoxedOrUnboxedDenseElements(JSO
     return DenseElementResult::Success;
 }
 
 DefineBoxedOrUnboxedFunctor1(ShiftMoveBoxedOrUnboxedDenseElements, JSObject*);
 
 void
 js::ArrayShiftMoveElements(JSObject* obj)
 {
+    AutoUnsafeCallWithABI unsafe;
     MOZ_ASSERT_IF(obj->is<ArrayObject>(), obj->as<ArrayObject>().lengthIsWritable());
 
     ShiftMoveBoxedOrUnboxedDenseElementsFunctor functor(obj);
     JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success);
 }
 
 template <JSValueType Type>
 DenseElementResult
--- a/js/src/jsboolinlines.h
+++ b/js/src/jsboolinlines.h
@@ -4,25 +4,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jsboolinlines_h
 #define jsboolinlines_h
 
 #include "jsbool.h"
 
+#include "jscntxt.h"
+
 #include "vm/BooleanObject.h"
 #include "vm/WrapperObject.h"
 
 namespace js {
 
 inline bool
 EmulatesUndefined(JSObject* obj)
 {
     // This may be called off the main thread. It's OK not to expose the object
     // here as it doesn't escape.
+    AutoUnsafeCallWithABI unsafe;
     JSObject* actual = MOZ_LIKELY(!obj->is<WrapperObject>()) ? obj : UncheckedUnwrapWithoutExpose(obj);
     return actual->getClass()->emulatesUndefined();
 }
 
 } /* namespace js */
 
 #endif /* jsboolinlines_h */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1288,16 +1288,18 @@ JSContext::JSContext(JSRuntime* runtime,
     entryMonitor(nullptr),
     noExecuteDebuggerTop(nullptr),
     handlingSegFault(false),
     activityCallback(nullptr),
     activityCallbackArg(nullptr),
     requestDepth(0),
 #ifdef DEBUG
     checkRequestDepth(0),
+    inUnsafeCallWithABI(false),
+    hasAutoUnsafeCallWithABI(false),
 #endif
 #ifdef JS_SIMULATOR
     simulator_(nullptr),
 #endif
 #ifdef JS_TRACE_LOGGING
     traceLogger(nullptr),
 #endif
     autoFlushICache_(nullptr),
@@ -1663,8 +1665,26 @@ AutoEnterOOMUnsafeRegion::crash(size_t s
 {
     {
         JS::AutoSuppressGCAnalysis suppress;
         if (annotateOOMSizeCallback)
             annotateOOMSizeCallback(size);
     }
     crash(reason);
 }
+
+#ifdef DEBUG
+AutoUnsafeCallWithABI::AutoUnsafeCallWithABI()
+  : cx_(TlsContext.get()),
+    nested_(cx_->hasAutoUnsafeCallWithABI)
+{
+    cx_->hasAutoUnsafeCallWithABI = true;
+}
+
+AutoUnsafeCallWithABI::~AutoUnsafeCallWithABI()
+{
+    MOZ_ASSERT(cx_->hasAutoUnsafeCallWithABI);
+    if (!nested_) {
+        cx_->hasAutoUnsafeCallWithABI = false;
+        cx_->inUnsafeCallWithABI = false;
+    }
+}
+#endif
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -374,16 +374,22 @@ struct JSContext : public JS::RootingCon
 
     js::Activation* profilingActivation() const {
         return profilingActivation_;
     }
     static size_t offsetOfProfilingActivation() {
         return offsetof(JSContext, profilingActivation_);
      }
 
+#ifdef DEBUG
+    static size_t offsetOfInUnsafeCallWithABI() {
+        return offsetof(JSContext, inUnsafeCallWithABI);
+    }
+#endif
+
   private:
     /* Space for interpreter frames. */
     js::ThreadLocalData<js::InterpreterStack> interpreterStack_;
 
   public:
     js::InterpreterStack& interpreterStack() {
         return interpreterStack_.ref();
     }
@@ -414,16 +420,18 @@ struct JSContext : public JS::RootingCon
     js::ThreadLocalData<void*>                activityCallbackArg;
     void triggerActivityCallback(bool active);
 
     /* The request depth for this thread. */
     js::ThreadLocalData<unsigned> requestDepth;
 
 #ifdef DEBUG
     js::ThreadLocalData<unsigned> checkRequestDepth;
+    js::ThreadLocalData<uint32_t> inUnsafeCallWithABI;
+    js::ThreadLocalData<bool> hasAutoUnsafeCallWithABI;
 #endif
 
 #ifdef JS_SIMULATOR
   private:
     js::ThreadLocalData<js::jit::Simulator*> simulator_;
   public:
     js::jit::Simulator* simulator() const;
     uintptr_t* addressOfSimulatorStackLimit();
@@ -1281,16 +1289,33 @@ class MOZ_RAII AutoEnterIonCompilation
         cx->ionCompiling = false;
         cx->ionCompilingSafeForMinorGC = false;
 #endif
     }
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
+// Should be used in functions called directly from JIT code (with
+// masm.callWithABI) to assert invariants in debug builds.
+class MOZ_RAII AutoUnsafeCallWithABI
+{
+    JS::AutoCheckCannotGC nogc;
+#ifdef DEBUG
+    JSContext* cx_;
+    bool nested_;
+#endif
+
+  public:
+#ifdef DEBUG
+    AutoUnsafeCallWithABI();
+    ~AutoUnsafeCallWithABI();
+#endif
+};
+
 namespace gc {
 
 // In debug builds, set/unset the performing GC flag for the current thread.
 struct MOZ_RAII AutoSetThreadIsPerformingGC
 {
 #ifdef DEBUG
     AutoSetThreadIsPerformingGC()
       : cx(TlsContext.get())
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -349,49 +349,47 @@ class JSFunction : public js::NativeObje
         return atom_;
     }
 
     void setCompileTimeName(JSAtom* atom) {
         MOZ_ASSERT(!atom_);
         MOZ_ASSERT(atom);
         MOZ_ASSERT(!hasGuessedAtom());
         MOZ_ASSERT(!isClassConstructor());
-        MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
-        atom_ = atom;
+        setAtom(atom);
         flags_ |= HAS_COMPILE_TIME_NAME;
     }
     JSAtom* compileTimeName() const {
         MOZ_ASSERT(hasCompileTimeName());
         MOZ_ASSERT(atom_);
         return atom_;
     }
 
     void setGuessedAtom(JSAtom* atom) {
         MOZ_ASSERT(!atom_);
         MOZ_ASSERT(atom);
         MOZ_ASSERT(!hasCompileTimeName());
         MOZ_ASSERT(!hasGuessedAtom());
         MOZ_ASSERT(!isBoundFunction());
-        MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
-        atom_ = atom;
+        setAtom(atom);
         flags_ |= HAS_GUESSED_ATOM;
     }
     void clearGuessedAtom() {
         MOZ_ASSERT(hasGuessedAtom());
         MOZ_ASSERT(!isBoundFunction());
         MOZ_ASSERT(atom_);
-        atom_ = nullptr;
+        setAtom(nullptr);
         flags_ &= ~HAS_GUESSED_ATOM;
     }
 
     void setPrefixedBoundFunctionName(JSAtom* atom) {
         MOZ_ASSERT(!hasBoundFunctionNamePrefix());
         MOZ_ASSERT(atom);
         flags_ |= HAS_BOUND_FUNCTION_NAME_PREFIX;
-        atom_ = atom;
+        setAtom(atom);
     }
 
     /* uint16_t representation bounds number of call object dynamic slots. */
     enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
 
     /*
      * For an interpreted function, accessors for the initial scope object of
      * activations (stack frames) of the function.
--- a/js/src/jslibmath.h
+++ b/js/src/jslibmath.h
@@ -6,16 +6,17 @@
 
 #ifndef jslibmath_h
 #define jslibmath_h
 
 #include "mozilla/FloatingPoint.h"
 
 #include <math.h>
 
+#include "jscntxt.h"
 #include "jsnum.h"
 
 /*
  * Use system provided math routines.
  */
 
 /* The right copysign function is not always named the same thing. */
 #ifdef __GNUC__
@@ -43,16 +44,17 @@ js_fmod(double d, double d2)
     return fmod(d, d2);
 }
 
 namespace js {
 
 inline double
 NumberDiv(double a, double b)
 {
+    AutoUnsafeCallWithABI unsafe;
     if (b == 0) {
         if (a == 0 || mozilla::IsNaN(a)
 #ifdef XP_WIN
             || mozilla::IsNaN(b) /* XXX MSVC miscompiles such that (NaN == 0) */
 #endif
         )
             return JS::GenericNaN();
 
@@ -60,17 +62,19 @@ NumberDiv(double a, double b)
             return mozilla::NegativeInfinity<double>();
         return mozilla::PositiveInfinity<double>();
     }
 
     return a / b;
 }
 
 inline double
-NumberMod(double a, double b) {
+NumberMod(double a, double b)
+{
+    AutoUnsafeCallWithABI unsafe;
     if (b == 0)
         return JS::GenericNaN();
     return js_fmod(a, b);
 }
 
 } // namespace js
 
 #endif /* jslibmath_h */
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -178,22 +178,24 @@ js::math_abs(JSContext* cx, unsigned arg
     }
 
     return math_abs_handle(cx, args[0], args.rval());
 }
 
 double
 js::math_acos_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::acos, x, MathCache::Acos);
 }
 
 double
 js::math_acos_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::acos(x);
 }
 
 bool
 js::math_acos(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -213,22 +215,24 @@ js::math_acos(JSContext* cx, unsigned ar
     double z = math_acos_impl(mathCache, x);
     args.rval().setDouble(z);
     return true;
 }
 
 double
 js::math_asin_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::asin, x, MathCache::Asin);
 }
 
 double
 js::math_asin_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::asin(x);
 }
 
 bool
 js::math_asin(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -248,22 +252,24 @@ js::math_asin(JSContext* cx, unsigned ar
     double z = math_asin_impl(mathCache, x);
     args.rval().setDouble(z);
     return true;
 }
 
 double
 js::math_atan_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::atan, x, MathCache::Atan);
 }
 
 double
 js::math_atan_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::atan(x);
 }
 
 bool
 js::math_atan(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -283,16 +289,17 @@ js::math_atan(JSContext* cx, unsigned ar
     double z = math_atan_impl(mathCache, x);
     args.rval().setDouble(z);
     return true;
 }
 
 double
 js::ecmaAtan2(double y, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::atan2(y, x);
 }
 
 bool
 js::math_atan2_handle(JSContext* cx, HandleValue y, HandleValue x, MutableHandleValue res)
 {
     double dy;
     if (!ToNumber(cx, y, &dy))
@@ -313,16 +320,17 @@ js::math_atan2(JSContext* cx, unsigned a
     CallArgs args = CallArgsFromVp(argc, vp);
 
     return math_atan2_handle(cx, args.get(0), args.get(1), args.rval());
 }
 
 double
 js::math_ceil_impl(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::ceil(x);
 }
 
 bool
 js::math_ceil_handle(JSContext* cx, HandleValue v, MutableHandleValue res)
 {
     double d;
     if(!ToNumber(cx, v, &d))
@@ -367,22 +375,24 @@ js::math_clz32(JSContext* cx, unsigned a
 
     args.rval().setInt32(mozilla::CountLeadingZeroes32(n));
     return true;
 }
 
 double
 js::math_cos_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(cos, x, MathCache::Cos);
 }
 
 double
 js::math_cos_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cos(x);
 }
 
 bool
 js::math_cos(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -402,22 +412,24 @@ js::math_cos(JSContext* cx, unsigned arg
     double z = math_cos_impl(mathCache, x);
     args.rval().setDouble(z);
     return true;
 }
 
 double
 js::math_exp_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::exp, x, MathCache::Exp);
 }
 
 double
 js::math_exp_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::exp(x);
 }
 
 bool
 js::math_exp(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -437,16 +449,17 @@ js::math_exp(JSContext* cx, unsigned arg
     double z = math_exp_impl(mathCache, x);
     args.rval().setNumber(z);
     return true;
 }
 
 double
 js::math_floor_impl(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::floor(x);
 }
 
 bool
 js::math_floor_handle(JSContext* cx, HandleValue v, MutableHandleValue r)
 {
     double d;
     if (!ToNumber(cx, v, &d))
@@ -527,22 +540,24 @@ js::math_fround(JSContext* cx, unsigned 
     }
 
     return RoundFloat32(cx, args[0], args.rval());
 }
 
 double
 js::math_log_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(math_log_uncached, x, MathCache::Log);
 }
 
 double
 js::math_log_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::log(x);
 }
 
 bool
 js::math_log_handle(JSContext* cx, HandleValue val, MutableHandleValue res)
 {
     double in;
     if (!ToNumber(cx, val, &in))
@@ -568,16 +583,18 @@ js::math_log(JSContext* cx, unsigned arg
     }
 
     return math_log_handle(cx, args[0], args.rval());
 }
 
 double
 js::math_max_impl(double x, double y)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     // Math.max(num, NaN) => NaN, Math.max(-0, +0) => +0
     if (x > y || IsNaN(x) || (x == y && IsNegative(y)))
         return x;
     return y;
 }
 
 bool
 js::math_max(JSContext* cx, unsigned argc, Value* vp)
@@ -593,16 +610,18 @@ js::math_max(JSContext* cx, unsigned arg
     }
     args.rval().setNumber(maxval);
     return true;
 }
 
 double
 js::math_min_impl(double x, double y)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     // Math.min(num, NaN) => NaN, Math.min(-0, +0) => -0
     if (x < y || IsNaN(x) || (x == y && IsNegativeZero(x)))
         return x;
     return y;
 }
 
 bool
 js::math_min(JSContext* cx, unsigned argc, Value* vp)
@@ -636,16 +655,17 @@ js::minmax_impl(JSContext* cx, bool max,
         res.setNumber(math_min_impl(x, y));
 
     return true;
 }
 
 double
 js::powi(double x, int y)
 {
+    AutoUnsafeCallWithABI unsafe;
     unsigned n = (y < 0) ? -y : y;
     double m = x;
     double p = 1;
     while (true) {
         if ((n & 1) != 0) p *= m;
         n >>= 1;
         if (n == 0) {
             if (y < 0) {
@@ -664,16 +684,18 @@ js::powi(double x, int y)
         }
         m *= m;
     }
 }
 
 double
 js::ecmaPow(double x, double y)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     /*
      * Use powi if the exponent is an integer-valued double. We don't have to
      * check for NaN since a comparison with NaN is always false.
      */
     int32_t yi;
     if (NumberEqualsInt32(y, &yi))
         return powi(x, yi);
 
@@ -820,31 +842,35 @@ js::GetBiggestNumberLessThan(T x)
 }
 
 template double js::GetBiggestNumberLessThan<>(double x);
 template float js::GetBiggestNumberLessThan<>(float x);
 
 double
 js::math_round_impl(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     int32_t ignored;
     if (NumberIsInt32(x, &ignored))
         return x;
 
     /* Some numbers are so big that adding 0.5 would give the wrong number. */
     if (ExponentComponent(x) >= int_fast16_t(FloatingPoint<double>::kExponentShift))
         return x;
 
     double add = (x >= 0) ? GetBiggestNumberLessThan(0.5) : 0.5;
     return js_copysign(fdlibm::floor(x + add), x);
 }
 
 float
 js::math_roundf_impl(float x)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     int32_t ignored;
     if (NumberIsInt32(x, &ignored))
         return x;
 
     /* Some numbers are so big that adding 0.5 would give the wrong number. */
     if (ExponentComponent(x) >= int_fast16_t(FloatingPoint<float>::kExponentShift))
         return x;
 
@@ -863,22 +889,24 @@ js::math_round(JSContext* cx, unsigned a
     }
 
     return math_round_handle(cx, args[0], args.rval());
 }
 
 double
 js::math_sin_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(math_sin_uncached, x, MathCache::Sin);
 }
 
 double
 js::math_sin_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
 #ifdef _WIN64
     // Workaround MSVC bug where sin(-0) is +0 instead of -0 on x64 on
     // CPUs without FMA3 (pre-Haswell). See bug 1076670.
     if (IsNegativeZero(x))
         return -0.0;
 #endif
     return sin(x);
 }
@@ -910,29 +938,31 @@ js::math_sin(JSContext* cx, unsigned arg
     }
 
     return math_sin_handle(cx, args[0], args.rval());
 }
 
 void
 js::math_sincos_uncached(double x, double *sin, double *cos)
 {
+    AutoUnsafeCallWithABI unsafe;
 #if defined(HAVE_SINCOS)
     sincos(x, sin, cos);
 #elif defined(HAVE___SINCOS)
     __sincos(x, sin, cos);
 #else
     *sin = js::math_sin_uncached(x);
     *cos = js::math_cos_uncached(x);
 #endif
 }
 
 void
 js::math_sincos_impl(MathCache* mathCache, double x, double *sin, double *cos)
 {
+    AutoUnsafeCallWithABI unsafe;
     unsigned indexSin;
     unsigned indexCos;
     bool hasSin = mathCache->isCached(x, MathCache::Sin, sin, &indexSin);
     bool hasCos = mathCache->isCached(x, MathCache::Cos, cos, &indexCos);
     if (!(hasSin || hasCos)) {
         js::math_sincos_uncached(x, sin, cos);
         mathCache->store(MathCache::Sin, x, *sin, indexSin);
         mathCache->store(MathCache::Cos, x, *cos, indexCos);
@@ -973,22 +1003,24 @@ js::math_sqrt(JSContext* cx, unsigned ar
     }
 
     return math_sqrt_handle(cx, args[0], args.rval());
 }
 
 double
 js::math_tan_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(tan, x, MathCache::Tan);
 }
 
 double
 js::math_tan_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return tan(x);
 }
 
 bool
 js::math_tan(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
@@ -1032,197 +1064,218 @@ static bool math_function(JSContext* cx,
     args.rval().setNumber(z);
 
     return true;
 }
 
 double
 js::math_log10_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::log10, x, MathCache::Log10);
 }
 
 double
 js::math_log10_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::log10(x);
 }
 
 bool
 js::math_log10(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_log10_impl>(cx, argc, vp);
 }
 
 double
 js::math_log2_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::log2, x, MathCache::Log2);
 }
 
 double
 js::math_log2_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::log2(x);
 }
 
 bool
 js::math_log2(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_log2_impl>(cx, argc, vp);
 }
 
 double
 js::math_log1p_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::log1p, x, MathCache::Log1p);
 }
 
 double
 js::math_log1p_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::log1p(x);
 }
 
 bool
 js::math_log1p(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_log1p_impl>(cx, argc, vp);
 }
 
 double
 js::math_expm1_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::expm1, x, MathCache::Expm1);
 }
 
 double
 js::math_expm1_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::expm1(x);
 }
 
 bool
 js::math_expm1(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_expm1_impl>(cx, argc, vp);
 }
 
 double
 js::math_cosh_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::cosh, x, MathCache::Cosh);
 }
 
 double
 js::math_cosh_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::cosh(x);
 }
 
 bool
 js::math_cosh(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_cosh_impl>(cx, argc, vp);
 }
 
 double
 js::math_sinh_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::sinh, x, MathCache::Sinh);
 }
 
 double
 js::math_sinh_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::sinh(x);
 }
 
 bool
 js::math_sinh(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_sinh_impl>(cx, argc, vp);
 }
 
 double
 js::math_tanh_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::tanh, x, MathCache::Tanh);
 }
 
 double
 js::math_tanh_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::tanh(x);
 }
 
 bool
 js::math_tanh(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_tanh_impl>(cx, argc, vp);
 }
 
 double
 js::math_acosh_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::acosh, x, MathCache::Acosh);
 }
 
 double
 js::math_acosh_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::acosh(x);
 }
 
 bool
 js::math_acosh(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_acosh_impl>(cx, argc, vp);
 }
 
 double
 js::math_asinh_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::asinh, x, MathCache::Asinh);
 }
 
 double
 js::math_asinh_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::asinh(x);
 }
 
 bool
 js::math_asinh(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_asinh_impl>(cx, argc, vp);
 }
 
 double
 js::math_atanh_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::atanh, x, MathCache::Atanh);
 }
 
 double
 js::math_atanh_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::atanh(x);
 }
 
 bool
 js::math_atanh(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_atanh_impl>(cx, argc, vp);
 }
 
 /* Consistency wrapper for platform deviations in hypot() */
 double
 js::ecmaHypot(double x, double y)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::hypot(x, y);
 }
 
 static inline
 void
 hypot_step(double& scale, double& sumsq, double x)
 {
     double xabs = mozilla::Abs(x);
@@ -1232,16 +1285,18 @@ hypot_step(double& scale, double& sumsq,
     } else if (scale != 0) {
         sumsq += (xabs / scale) * (xabs / scale);
     }
 }
 
 double
 js::hypot4(double x, double y, double z, double w)
 {
+    AutoUnsafeCallWithABI unsafe;
+
     /* Check for infinity or NaNs so that we can return immediatelly.
      * Does not need to be WIN_XP specific as ecmaHypot
      */
     if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y) ||
             mozilla::IsInfinite(z) || mozilla::IsInfinite(w))
         return mozilla::PositiveInfinity<double>();
 
     if (mozilla::IsNaN(x) || mozilla::IsNaN(y) || mozilla::IsNaN(z) ||
@@ -1257,16 +1312,17 @@ js::hypot4(double x, double y, double z,
     hypot_step(scale, sumsq, w);
 
     return scale * sqrt(sumsq);
 }
 
 double
 js::hypot3(double x, double y, double z)
 {
+    AutoUnsafeCallWithABI unsafe;
     return hypot4(x, y, z, 0.0);
 }
 
 bool
 js::math_hypot(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return math_hypot_handle(cx, args, args.rval());
@@ -1313,22 +1369,24 @@ js::math_hypot_handle(JSContext* cx, Han
                     scale * sqrt(sumsq);
     res.setNumber(result);
     return true;
 }
 
 double
 js::math_trunc_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::trunc, x, MathCache::Trunc);
 }
 
 double
 js::math_trunc_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::trunc(x);
 }
 
 bool
 js::math_trunc(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_trunc_impl>(cx, argc, vp);
 }
@@ -1339,40 +1397,44 @@ static double sign(double x)
         return GenericNaN();
 
     return x == 0 ? x : x < 0 ? -1 : 1;
 }
 
 double
 js::math_sign_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(sign, x, MathCache::Sign);
 }
 
 double
 js::math_sign_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return sign(x);
 }
 
 bool
 js::math_sign(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_sign_impl>(cx, argc, vp);
 }
 
 double
 js::math_cbrt_impl(MathCache* cache, double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return cache->lookup(fdlibm::cbrt, x, MathCache::Cbrt);
 }
 
 double
 js::math_cbrt_uncached(double x)
 {
+    AutoUnsafeCallWithABI unsafe;
     return fdlibm::cbrt(x);
 }
 
 bool
 js::math_cbrt(JSContext* cx, unsigned argc, Value* vp)
 {
     return math_function<math_cbrt_impl>(cx, argc, vp);
 }
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -366,17 +366,17 @@ ArgumentsObject::createForIon(JSContext*
 }
 
 /* static */ ArgumentsObject*
 ArgumentsObject::finishForIon(JSContext* cx, jit::JitFrameLayout* frame,
                               JSObject* scopeChain, ArgumentsObject* obj)
 {
     // JIT code calls this directly (no callVM), because it's faster, so we're
     // not allowed to GC in here.
-    JS::AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     JSFunction* callee = jit::CalleeTokenToFunction(frame->calleeToken());
     RootedObject callObj(cx, scopeChain->is<CallObject>() ? scopeChain : nullptr);
     CopyJitFrameArgs copy(frame, callObj);
 
     unsigned numActuals = frame->numActualArgs();
     unsigned numFormals = callee->nargs();
     unsigned numArgs = Max(numActuals, numFormals);
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -401,30 +401,30 @@ NativeObject::growSlots(JSContext* cx, u
 
     return true;
 }
 
 /* static */ bool
 NativeObject::growSlotsDontReportOOM(JSContext* cx, NativeObject* obj, uint32_t newCount)
 {
     // IC code calls this directly.
-    AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     if (!obj->growSlots(cx, obj->numDynamicSlots(), newCount)) {
         cx->recoverFromOutOfMemory();
         return false;
     }
     return true;
 }
 
 /* static */ bool
 NativeObject::addDenseElementDontReportOOM(JSContext* cx, NativeObject* obj)
 {
     // IC code calls this directly.
-    AutoCheckCannotGC nogc;
+    AutoUnsafeCallWithABI unsafe;
 
     MOZ_ASSERT(obj->getDenseInitializedLength() == obj->getDenseCapacity());
     MOZ_ASSERT(!obj->denseElementsAreCopyOnWrite());
     MOZ_ASSERT(!obj->denseElementsAreFrozen());
     MOZ_ASSERT(!obj->isIndexed());
     MOZ_ASSERT(!obj->is<TypedArrayObject>());
     MOZ_ASSERT_IF(obj->is<ArrayObject>(), obj->as<ArrayObject>().lengthIsWritable());
 
--- a/js/xpconnect/loader/ScriptPreloader.h
+++ b/js/xpconnect/loader/ScriptPreloader.h
@@ -264,18 +264,22 @@ private:
             if (HasArray()) {
                 size += Array().ShallowSizeOfExcludingThis(mallocSizeOf);
             } else if (HasBuffer()) {
                 size += Buffer().sizeOfExcludingThis(mallocSizeOf);
             } else {
                 return size;
             }
 
-            size += (mURL.SizeOfExcludingThisEvenIfShared(mallocSizeOf) +
+            // Note: mURL and mCachePath use the same string for scripts loaded
+            // by the message manager. The following statement avoids
+            // double-measuring in that case.
+            size += (mURL.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
                      mCachePath.SizeOfExcludingThisEvenIfShared(mallocSizeOf));
+
             return size;
         }
 
         ScriptPreloader& mCache;
 
         // The URL from which this script was initially read and compiled.
         nsCString mURL;
         // A unique identifier for this script's filesystem location, used as a
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -81,18 +81,18 @@ fuzzy-if(skiaContent,1,1100) == 267459-2
 random-if(winWidget) == 305643-1.html 305643-1-ref.html # depends on windows version, see bug 590101
 == 332655-1.html 332655-1-ref.html
 == 332655-2.html 332655-2-ref.html
 == 381279-1.html 381279-1-ref.html
 == 386339.html 386339-ref.html
 == 409375.html 409375-ref.html
 == 413542-1.html 413542-1-ref.html
 == 413542-2.html 413542-2-ref.html
-fails-if(webrender) == 413928-1.html 413928-1-ref.html
-fails-if(webrender) == 413928-2.html 413928-2-ref.html
+== 413928-1.html 413928-1-ref.html
+== 413928-2.html 413928-2-ref.html
 == 425338-1a.html 425338-1-ref.html
 == 425338-1b.html 425338-1-ref.html
 == 489517-1.html 489517-1-ref.html
 == 489887-1.html 489887-1-ref.html
 == 492231-1.html 492231-1-ref.html
 == 496006-1.html 496006-1-ref.html
 == 503269-1.html 503269-1-ref.html
 == 503957-1.html 503957-1-ref.html
--- a/layout/reftests/counter-style/reftest.list
+++ b/layout/reftests/counter-style/reftest.list
@@ -1,35 +1,35 @@
-fails-if(webrender) == system-cyclic.html     system-cyclic-ref.html
-fails-if(webrender) == system-fixed.html      system-fixed-ref.html
-fails-if(webrender) == system-symbolic.html   system-symbolic-ref.html
-fails-if(webrender) == system-alphabetic.html system-alphabetic-ref.html
-fails-if(webrender) == system-numeric.html    system-numeric-ref.html
-fails-if(webrender) == system-additive.html   system-additive-ref.html
-fails-if(webrender) == system-extends.html    system-extends-ref.html
+== system-cyclic.html     system-cyclic-ref.html
+== system-fixed.html      system-fixed-ref.html
+== system-symbolic.html   system-symbolic-ref.html
+== system-alphabetic.html system-alphabetic-ref.html
+== system-numeric.html    system-numeric-ref.html
+== system-additive.html   system-additive-ref.html
+== system-extends.html    system-extends-ref.html
 == system-cyclic-invalid.html     system-common-invalid-ref.html
 == system-fixed-invalid.html      system-common-invalid2-ref.html
 == system-symbolic-invalid.html   system-common-invalid-ref.html
 == system-alphabetic-invalid.html system-common-invalid2-ref.html
 == system-numeric-invalid.html    system-common-invalid2-ref.html
 == system-additive-invalid.html   system-common-invalid-ref.html
-fails-if(webrender) == system-extends-invalid.html    system-extends-invalid-ref.html
-fails-if(webrender) == descriptor-negative.html descriptor-negative-ref.html
-fails-if(webrender) == descriptor-prefix.html   descriptor-prefix-ref.html
-fails-if(webrender) == descriptor-suffix.html   descriptor-suffix-ref.html
-fails-if(webrender) == descriptor-range.html    descriptor-range-ref.html
-fails-if(webrender) == descriptor-pad.html      descriptor-pad-ref.html
-fails-if(webrender) == descriptor-fallback.html descriptor-fallback-ref.html
-fails-if(webrender) == descriptor-symbols.html  descriptor-symbols-ref.html
-fails-if(webrender) == descriptor-negative-invalid.html descriptor-negative-invalid-ref.html
-fails-if(webrender) == descriptor-prefix-invalid.html   descriptor-prefix-invalid-ref.html
-fails-if(webrender) == descriptor-suffix-invalid.html   descriptor-suffix-invalid-ref.html
-fails-if(webrender) == descriptor-range-invalid.html    descriptor-range-invalid-ref.html
-fails-if(webrender) == descriptor-pad-invalid.html      descriptor-pad-invalid-ref.html
-fails-if(webrender) == descriptor-fallback.html         descriptor-fallback-ref.html
-fails-if(webrender) == descriptor-symbols-invalid.html  descriptor-symbols-invalid-ref.html
+== system-extends-invalid.html    system-extends-invalid-ref.html
+== descriptor-negative.html descriptor-negative-ref.html
+== descriptor-prefix.html   descriptor-prefix-ref.html
+== descriptor-suffix.html   descriptor-suffix-ref.html
+== descriptor-range.html    descriptor-range-ref.html
+== descriptor-pad.html      descriptor-pad-ref.html
+== descriptor-fallback.html descriptor-fallback-ref.html
+== descriptor-symbols.html  descriptor-symbols-ref.html
+== descriptor-negative-invalid.html descriptor-negative-invalid-ref.html
+== descriptor-prefix-invalid.html   descriptor-prefix-invalid-ref.html
+== descriptor-suffix-invalid.html   descriptor-suffix-invalid-ref.html
+== descriptor-range-invalid.html    descriptor-range-invalid-ref.html
+== descriptor-pad-invalid.html      descriptor-pad-invalid-ref.html
+== descriptor-fallback.html         descriptor-fallback-ref.html
+== descriptor-symbols-invalid.html  descriptor-symbols-invalid-ref.html
 == name-case-sensitivity.html       name-case-sensitivity-ref.html
-fails-if(webrender) == dependent-builtin.html           dependent-builtin-ref.html
+== dependent-builtin.html           dependent-builtin-ref.html
 == redefine-builtin.html            redefine-builtin-ref.html
 == redefine-attr-mapping.html       redefine-attr-mapping-ref.html
 == disclosure-styles.html           disclosure-styles-ref.html
 == symbols-function.html            symbols-function-ref.html
 == symbols-function-invalid.html    symbols-function-invalid-ref.html
--- a/layout/reftests/counters/reftest.list
+++ b/layout/reftests/counters/reftest.list
@@ -63,17 +63,17 @@
 fails-if(xulRuntime.XPCOMABI.match(/arm/)) == counter-reset-integer-range.html counter-reset-integer-range-ref.html # bug 989718
 == counter-ua-limits-00.html counter-ua-limits-00-ref.html
 == counter-ua-limits-01.html counter-ua-limits-01-ref.html
 fails-if(xulRuntime.XPCOMABI.match(/arm/)) == counter-ua-limits-02.html counter-ua-limits-02-ref.html # bug 989718
 == counter-ua-limits-03.html counter-ua-limits-03-ref.html
 == counter-ua-limits-list-00.html counter-ua-limits-list-00-ref.html
 == counter-ua-limits-list-01.html counter-ua-limits-list-01-ref.html
 == multiple-thai-counters.html multiple-thai-counters-ref.html
-fails-if(webrender) == counter-suffix.html counter-suffix-ref.html
+== counter-suffix.html counter-suffix-ref.html
 == counter-cjk-decimal.html counter-cjk-decimal-ref.html
 == counter-japanese-informal.html counter-japanese-informal-ref.html
 == counter-japanese-formal.html counter-japanese-formal-ref.html
 == counter-korean-hangul-formal.html counter-korean-hangul-formal-ref.html
 == counter-korean-hanja-informal.html counter-korean-hanja-informal-ref.html
 == counter-korean-hanja-formal.html counter-korean-hanja-formal-ref.html
 == counter-simp-chinese-informal.html counter-simp-chinese-informal-ref.html
 == counter-simp-chinese-formal.html counter-simp-chinese-formal-ref.html
--- a/layout/reftests/list-item/reftest.list
+++ b/layout/reftests/list-item/reftest.list
@@ -1,14 +1,14 @@
 fuzzy-if(OSX,55,4) == numbering-1.html numbering-1-ref.html
 == numbering-2.html numbering-2-ref.html
 pref(layout.css.grid.enabled,true) fuzzy-if(OSX,8,1) == numbering-3.html numbering-3-ref.html
 fuzzy-if(OSX,72,2) == numbering-4.html numbering-4-ref.html
-fails-if(webrender) == numbering-5.html numbering-5-ref.html
+== numbering-5.html numbering-5-ref.html
 == ol-reversed-1a.html ol-reversed-1-ref.html
 asserts(1) == ol-reversed-1b.html ol-reversed-1-ref.html # bug 478135
 == ol-reversed-1c.html ol-reversed-1-ref.html
 == ol-reversed-2.html ol-reversed-2-ref.html
 == ol-reversed-3.html ol-reversed-3-ref.html
 == bullet-space-1.html bullet-space-1-ref.html
 == bullet-space-2.html bullet-space-2-ref.html
 == bullet-intrinsic-isize-1.html bullet-intrinsic-isize-1-ref.html
-fails-if(webrender) == bullet-intrinsic-isize-2.html bullet-intrinsic-isize-2-ref.html
+== bullet-intrinsic-isize-2.html bullet-intrinsic-isize-2-ref.html
--- a/layout/reftests/stylesheet-cloning/reftest.list
+++ b/layout/reftests/stylesheet-cloning/reftest.list
@@ -1,7 +1,7 @@
-fails-if(webrender) == counter-style-rule-clone.html glyphs-ref.html # passes trivially
+== counter-style-rule-clone.html glyphs-ref.html # passes trivially
 # because "Dynamic change on @counter-style not yet supported"
 == document-rule-clone.html shouldbegreen-ref.html
 == media-rule-clone.html shouldbegreen-ref.html
 == insert-after-clone.html shouldbegreen-ref.html
 == style-rule-clone.html shouldbegreen-ref.html
 == supports-rule-clone.html shouldbegreen-ref.html
--- a/layout/reftests/w3c-css/submitted/lists-3/reftest.list
+++ b/layout/reftests/w3c-css/submitted/lists-3/reftest.list
@@ -1,3 +1,3 @@
 # Tests for list-style-type
-fails-if(webrender) == list-style-type-string-001a.html list-style-type-string-001-ref.html
-fails-if(webrender) == list-style-type-string-001b.html list-style-type-string-001-ref.html
+== list-style-type-string-001a.html list-style-type-string-001-ref.html
+== list-style-type-string-001b.html list-style-type-string-001-ref.html
--- a/layout/reftests/writing-mode/reftest.list
+++ b/layout/reftests/writing-mode/reftest.list
@@ -26,17 +26,17 @@ fuzzy-if(azureSkia,255,2700) == 1090168-
 == 1096224-1b.html 1096224-1-ref.html
 fails == 1102175-1a.html 1102175-1-ref.html
 == 1102175-1b.html 1102175-1-ref.html
 == 1103613-1.html 1103613-1-ref.html
 == 1105268-1-min-max-dimensions.html 1105268-1-min-max-dimensions-ref.html
 == 1105268-2-min-max-dimensions.html 1105268-2-min-max-dimensions-ref.html
 == 1106669-1-intrinsic-for-container.html 1106669-1-intrinsic-for-container-ref.html
 == 1108923-1-percentage-margins.html 1108923-1-percentage-margins-ref.html
-fails-if(webrender) == 1111944-1-list-marker.html 1111944-1-list-marker-ref.html
+== 1111944-1-list-marker.html 1111944-1-list-marker-ref.html
 fuzzy(116,94) fuzzy-if(winWidget,135,124) HTTP(..) == 1115916-1-vertical-metrics.html 1115916-1-vertical-metrics-ref.html
 == 1117210-1-vertical-baseline-snap.html 1117210-1-vertical-baseline-snap-ref.html
 == 1117227-1-text-overflow.html 1117227-1-text-overflow-ref.html
 == 1122366-1-margin-collapse.html 1122366-1-margin-collapse-ref.html
 == 1124636-1-fieldset-max-height.html 1124636-1-fieldset-max-height-ref.html
 == 1124636-2-fieldset-min-height.html 1124636-2-fieldset-min-height-ref.html
 
 == ua-style-sheet-margin-1.html ua-style-sheet-margin-1-ref.html
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was 2e5814de4fd9830d201d61b9d35ed24c2bba6d0f (2017-08-31 13:51:29 +0300)
+The git commit ID used was 09a90a7817bc3d76723065fdc6b53c542fbed402 (2017-09-13 18:39:50 +0200)
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -668,58 +668,82 @@ audiounit_reinit_stream(cubeb_stream * s
     // If the stream was running, start it again.
     if (!stm->shutdown) {
       audiounit_stream_start_internal(stm);
     }
   }
   return CUBEB_OK;
 }
 
+static char const *
+event_addr_to_string(AudioObjectPropertySelector selector)
+{
+  switch(selector) {
+    case kAudioHardwarePropertyDefaultOutputDevice:
+      return "kAudioHardwarePropertyDefaultOutputDevice";
+    case kAudioHardwarePropertyDefaultInputDevice:
+      return "kAudioHardwarePropertyDefaultInputDevice";
+    case kAudioDevicePropertyDeviceIsAlive:
+      return "kAudioDevicePropertyDeviceIsAlive";
+    case kAudioDevicePropertyDataSource:
+      return "kAudioDevicePropertyDataSource";
+    default:
+      return "Unknown";
+  }
+}
+
 static OSStatus
-audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_count,
+audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count,
                                      const AudioObjectPropertyAddress * addresses,
                                      void * user)
 {
   cubeb_stream * stm = (cubeb_stream*) user;
+  if (stm->switching_device) {
+    LOG("Switching is already taking place. Skip Event %s for id=%d", event_addr_to_string(addresses[0].mSelector), id);
+    return noErr;
+  }
   stm->switching_device = true;
   device_flags_value switch_side = DEV_UKNOWN;
 
   LOG("(%p) Audio device changed, %u events.", stm, (unsigned int) address_count);
   for (UInt32 i = 0; i < address_count; i++) {
     switch(addresses[i].mSelector) {
       case kAudioHardwarePropertyDefaultOutputDevice: {
-          LOG("Event[%u] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", (unsigned int) i);
+          LOG("Event[%u] - mSelector == kAudioHardwarePropertyDefaultOutputDevice for id=%d", (unsigned int) i, id);
           // Allow restart to choose the new default
           switch_side |= DEV_OUTPUT;
         }
         break;
       case kAudioHardwarePropertyDefaultInputDevice: {
-          LOG("Event[%u] - mSelector == kAudioHardwarePropertyDefaultInputDevice", (unsigned int) i);
+          LOG("Event[%u] - mSelector == kAudioHardwarePropertyDefaultInputDevice for id=%d", (unsigned int) i, id);
           // Allow restart to choose the new default
           switch_side |= DEV_INPUT;
         }
       break;
       case kAudioDevicePropertyDeviceIsAlive: {
-          LOG("Event[%u] - mSelector == kAudioDevicePropertyDeviceIsAlive", (unsigned int) i);
+          LOG("Event[%u] - mSelector == kAudioDevicePropertyDeviceIsAlive for id=%d", (unsigned int) i, id);
           // If this is the default input device ignore the event,
           // kAudioHardwarePropertyDefaultInputDevice will take care of the switch
           if (stm->input_device.flags & DEV_SYSTEM_DEFAULT) {
             LOG("It's the default input device, ignore the event");
+            stm->switching_device = false;
             return noErr;
           }
           // Allow restart to choose the new default. Event register only for input.
           switch_side |= DEV_INPUT;
         }
         break;
       case kAudioDevicePropertyDataSource: {
-          LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource", (unsigned int) i);
-          return noErr;
+          LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource for id=%d", (unsigned int) i, id);
+          switch_side |= DEV_INPUT;
         }
+        break;
       default:
         LOG("Event[%u] - mSelector == Unexpected Event id %d, return", (unsigned int) i, addresses[i].mSelector);
+        stm->switching_device = false;
         return noErr;
     }
   }
 
   for (UInt32 i = 0; i < address_count; i++) {
     switch(addresses[i].mSelector) {
     case kAudioHardwarePropertyDefaultOutputDevice:
     case kAudioHardwarePropertyDefaultInputDevice:
--- a/media/webrtc/trunk/webrtc/modules/video_coding/video_sender.cc
+++ b/media/webrtc/trunk/webrtc/modules/video_coding/video_sender.cc
@@ -189,17 +189,18 @@ int VideoSender::FrameRate(unsigned int*
 }
 
 EncoderParameters VideoSender::UpdateEncoderParameters(
     const EncoderParameters& params,
     VideoBitrateAllocator* bitrate_allocator,
     uint32_t target_bitrate_bps) {
   uint32_t video_target_rate_bps = _mediaOpt.SetTargetRates(target_bitrate_bps);
   uint32_t input_frame_rate = _mediaOpt.InputFrameRate();
-  if (input_frame_rate == 0)
+
+  if (input_frame_rate == 0 || input_frame_rate > current_codec_.maxFramerate)
     input_frame_rate = current_codec_.maxFramerate;
 
   BitrateAllocation bitrate_allocation;
   if (bitrate_allocator) {
     bitrate_allocation = bitrate_allocator->GetAllocation(video_target_rate_bps,
                                                           input_frame_rate);
   } else {
     DefaultVideoBitrateAllocator default_allocator(current_codec_);
--- a/memory/mozalloc/moz.build
+++ b/memory/mozalloc/moz.build
@@ -24,20 +24,26 @@ if CONFIG['WRAP_STL_INCLUDES']:
 if CONFIG['OS_TARGET'] == 'WINNT':
     # Keep this file separate to avoid #include'ing windows.h everywhere.
     SOURCES += [
         'winheap.cpp',
     ]
 
 UNIFIED_SOURCES += [
     'mozalloc.cpp',
-    'mozalloc_abort.cpp',
     'mozalloc_oom.cpp',
 ]
 
+SOURCES += [
+    'mozalloc_abort.cpp',
+]
+
+if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['CC_TYPE'] == 'clang':
+    SOURCES['mozalloc_abort.cpp'].flags += ['-Wno-infinite-recursion']
+
 FINAL_LIBRARY = 'mozglue'
 
 # The strndup declaration in string.h is in an ifdef __USE_GNU section
 DEFINES['_GNU_SOURCE'] = True
 
 DisableStlWrapping()
 
 DEFINES['IMPL_MFBT'] = True
--- a/mfbt/Compression.cpp
+++ b/mfbt/Compression.cpp
@@ -20,18 +20,22 @@
 #ifdef _MSC_VER
 #include <intrin.h>
 #endif
 
 using namespace mozilla::Compression;
 
 namespace {
 
+extern "C" {
+
 #include "lz4.c"
 
+}
+
 }/* anonymous namespace */
 
 /* Our wrappers */
 
 size_t
 LZ4::compress(const char* aSource, size_t aInputSize, char* aDest)
 {
   CheckedInt<int> inputSizeChecked = aInputSize;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1313,22 +1313,18 @@ pref("dom.experimental_forms", false);
 
 // Enable <input type=number>:
 pref("dom.forms.number", true);
 
 // Enable <input type=color> by default. It will be turned off for remaining
 // platforms which don't have a color picker implemented yet.
 pref("dom.forms.color", true);
 
-// Support for input type=date and type=time. Enabled by default on Nightly.
-#ifdef NIGHTLY_BUILD
+// Support for input type=date and type=time.
 pref("dom.forms.datetime", true);
-#else
-pref("dom.forms.datetime", false);
-#endif
 
 // Support for input type=month, type=week and type=datetime-local. By default,
 // disabled.
 pref("dom.forms.datetime.others", false);
 
 // Enable time picker UI. By default, disabled.
 pref("dom.forms.datetime.timepicker", false);
 
@@ -1821,17 +1817,17 @@ pref("network.http.tcp_keepalive.long_li
 
 pref("network.http.enforce-framing.http1", false); // should be named "strict"
 pref("network.http.enforce-framing.soft", true);
 
 // Max size, in bytes, for received HTTP response header.
 pref("network.http.max_response_header_size", 393216);
 
 // If we should attempt to race the cache and network
-pref("network.http.rcwn.enabled", false);
+pref("network.http.rcwn.enabled", true);
 pref("network.http.rcwn.cache_queue_normal_threshold", 8);
 pref("network.http.rcwn.cache_queue_priority_threshold", 2);
 // We might attempt to race the cache with the network only if a resource
 // is smaller than this size.
 pref("network.http.rcwn.small_resource_size_kb", 256);
 
 pref("network.http.rcwn.min_wait_before_racing_ms", 0);
 pref("network.http.rcwn.max_wait_before_racing_ms", 500);
--- a/netwerk/base/nsIFileStreams.idl
+++ b/netwerk/base/nsIFileStreams.idl
@@ -217,16 +217,23 @@ interface nsIFileMetadata : nsISupports
     [noscript] PRFileDescPtr getFileDescriptor();
 };
 
 [scriptable, uuid(de15b80b-29ba-4b7f-9220-a3d75b17ae8c)]
 interface nsIAsyncFileMetadata : nsIFileMetadata
 {
     /**
      * Asynchronously wait for the object to be ready.
+     *
+     * @param aCallback The callback will be used when the stream is ready to
+     *                  return File metadata. Use a nullptr to cancel a
+     *                  previous operation.
+     *
+     * @param aEventTarget The event target where aCallback will be executed.
+     *                     If aCallback is passed, aEventTarget cannot be null.
      */
     void asyncWait(in nsIFileMetadataCallback aCallback,
                    in nsIEventTarget aEventTarget);
 };
 
 /**
  * This is a companion interface for nsIAsyncFileMetadata::asyncWait.
  */
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -3853,16 +3853,18 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
     RefPtr<LoadContextInfo> info = GetLoadContextInfo(this);
     if (!info) {
         return NS_ERROR_FAILURE;
     }
 
     uint32_t cacheEntryOpenFlags;
     bool offline = gIOService->IsOffline();
 
+    bool maybeRCWN = false;
+
     nsAutoCString cacheControlRequestHeader;
     Unused << mRequestHead.GetHeader(nsHttp::Cache_Control, cacheControlRequestHeader);
     CacheControlParser cacheControlRequest(cacheControlRequestHeader);
     if (cacheControlRequest.NoStore() && !PossiblyIntercepted()) {
         goto bypassCacheEntryOpen;
     }
 
     if (offline || (mLoadFlags & INHIBIT_CACHING)) {
@@ -3901,19 +3903,23 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
         rv = cacheStorageService->MemoryCacheStorage(info, // ? choose app cache as well...
             getter_AddRefs(cacheStorage));
     }
     else if (mPinCacheContent) {
         rv = cacheStorageService->PinningCacheStorage(info,
             getter_AddRefs(cacheStorage));
     }
     else {
-        rv = cacheStorageService->DiskCacheStorage(info,
-            !mPostID && (mChooseApplicationCache || (mLoadFlags & LOAD_CHECK_OFFLINE_CACHE)),
-            getter_AddRefs(cacheStorage));
+        bool lookupAppCache = !mPostID && (mChooseApplicationCache ||
+                              (mLoadFlags & LOAD_CHECK_OFFLINE_CACHE));
+        // Try to race only if we use disk cache storage and we don't lookup
+        // app cache first
+        maybeRCWN = !lookupAppCache;
+        rv = cacheStorageService->DiskCacheStorage(
+            info, lookupAppCache, getter_AddRefs(cacheStorage));
     }
     NS_ENSURE_SUCCESS(rv, rv);
 
     if ((mClassOfService & nsIClassOfService::Leader) ||
         (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI))
         cacheEntryOpenFlags |= nsICacheStorage::OPEN_PRIORITY;
 
     // Only for backward compatibility with the old cache back end.
@@ -3954,27 +3960,30 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
             DebugOnly<bool> exists;
             MOZ_ASSERT(NS_SUCCEEDED(cacheStorage->Exists(openURI, extension, &exists)) && exists,
                        "The entry must exist in the cache after we create it here");
         }
 
         mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY;
         mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority);
 
-        bool hasAltData = false;
-        uint32_t sizeInKb = 0;
-        rv = cacheStorage->GetCacheIndexEntryAttrs(openURI, extension,
-                                                   &hasAltData, &sizeInKb);
-
-        // We will attempt to race the network vs the cache if we've found this
-        // entry in the cache index, and it has appropriate
-        // attributes (doesn't have alt-data, and has a small size)
-        if (sRCWNEnabled && mInterceptCache != INTERCEPTED &&
-            NS_SUCCEEDED(rv) && !hasAltData && sizeInKb < sRCWNSmallResourceSizeKB) {
-            MaybeRaceCacheWithNetwork();
+        if (sRCWNEnabled && maybeRCWN && !mApplicationCacheForWrite &&
+            mInterceptCache != INTERCEPTED) {
+            bool hasAltData = false;
+            uint32_t sizeInKb = 0;
+            rv = cacheStorage->GetCacheIndexEntryAttrs(openURI, extension,
+                                                       &hasAltData, &sizeInKb);
+
+            // We will attempt to race the network vs the cache if we've found
+            // this entry in the cache index, and it has appropriate attributes
+            // (doesn't have alt-data, and has a small size)
+            if (NS_SUCCEEDED(rv) && !hasAltData &&
+                sizeInKb < sRCWNSmallResourceSizeKB) {
+                MaybeRaceCacheWithNetwork();
+            }
         }
 
         if (!mCacheOpenDelay) {
             MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread");
             mCacheAsyncOpenCalled = true;
             if (mNetworkTriggered) {
                 mRaceCacheWithNetwork = true;
             }
--- a/toolkit/components/backgroundhangmonitor/HangStack.cpp
+++ b/toolkit/components/backgroundhangmonitor/HangStack.cpp
@@ -1,10 +1,13 @@
 #include "HangStack.h"
+
+#ifdef MOZ_GECKO_PROFILER
 #include "shared-libraries.h"
+#endif
 
 namespace mozilla {
 
 HangStack::HangStack(const HangStack& aOther)
   : mModules(aOther.mModules)
 {
   if (NS_WARN_IF(!mBuffer.reserve(aOther.mBuffer.length()) ||
                  !mImpl.reserve(aOther.mImpl.length()))) {
@@ -94,16 +97,17 @@ struct PCFrameComparator {
 } // anonymous namespace
 
 void
 HangStack::ReadModuleInformation()
 {
   // mModules should be empty when we start filling it.
   mModules.Clear();
 
+#ifdef MOZ_GECKO_PROFILER
   // Create a sorted list of the PCs in the current stack.
   AutoTArray<Frame*, 100> frames;
   for (auto& frame : *this) {
     if (frame.GetKind() == Frame::Kind::PC) {
       frames.AppendElement(&frame);
     }
   }
   PCFrameComparator comparator;
@@ -150,16 +154,17 @@ HangStack::ReadModuleInformation()
       nsDependentCString cstr(info.GetBreakpadId().c_str());
       Module module = {
         info.GetDebugName(),
         cstr
       };
       mModules.AppendElement(module);
     }
   }
+#endif
 }
 
 } // namespace mozilla
 
 namespace IPC {
 
 void
 ParamTraits<mozilla::HangStack::ModOffset>::Write(Message* aMsg, const mozilla::HangStack::ModOffset& aParam)
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsThreadManager.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "nsIClassInfoImpl.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
+#include "nsXULAppAPI.h"
 #include "LabeledEventQueue.h"
 #include "MainThreadQueue.h"
 #include "mozilla/AbstractThread.h"
 #include "mozilla/EventQueue.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Scheduler.h"
 #include "mozilla/SystemGroup.h"
 #include "mozilla/ThreadEventQueue.h"