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 380970 8e818b5e9b6b
parent 380940 b778b6cb49c8 (current diff)
parent 380969 38e7e0bba036 (diff)
child 380996 442cc0fe3bec
child 381066 c006eaf460bb
push id32504
push userarchaeopteryx@coole-files.de
push dateThu, 14 Sep 2017 21:59:22 +0000
treeherdermozilla-central@8e818b5e9b6b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone57.0a1
first release with
nightly linux32
8e818b5e9b6b / 57.0a1 / 20170914220209 / files
nightly linux64
8e818b5e9b6b / 57.0a1 / 20170914220209 / files
nightly mac
8e818b5e9b6b / 57.0a1 / 20170914220209 / files
nightly win32
8e818b5e9b6b / 57.0a1 / 20170914220209 / files
nightly win64
8e818b5e9b6b / 57.0a1 / 20170914220209 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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"