merge mozilla-inbound to mozilla-central. r=merge a=merge
authorSebastian Hengst <archaeopteryx@coole-files.de>
Sun, 19 Mar 2017 16:26:07 +0100
changeset 348371 1b9293be51637f841275541d8991314ca56561a5
parent 348358 51844ae447dbc52cec81abb4c1a6e676b905a743 (current diff)
parent 348370 e5ca758200837169cb800d75dd267b09dfe27104 (diff)
child 348372 53392221fe7828781c8c8d5e2b15e99cbc59bdbc
child 348413 5733e0b0e0969bdcdcd53ae25641bafeeae095bf
push id39126
push userarchaeopteryx@coole-files.de
push dateSun, 19 Mar 2017 15:37:50 +0000
treeherderautoland@53392221fe78 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge, merge
milestone55.0a1
first release with
nightly linux32
1b9293be5163 / 55.0a1 / 20170320110254 / files
nightly linux64
1b9293be5163 / 55.0a1 / 20170320110254 / files
nightly mac
1b9293be5163 / 55.0a1 / 20170320030209 / files
nightly win32
1b9293be5163 / 55.0a1 / 20170320030209 / files
nightly win64
1b9293be5163 / 55.0a1 / 20170320030209 / 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: 3NxyjkZ2h59
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3885,8 +3885,16 @@ Element::UpdateIntersectionObservation(D
 void
 Element::ClearServoData() {
 #ifdef MOZ_STYLO
   Servo_Element_ClearData(this);
 #else
   MOZ_CRASH("Accessing servo node data in non-stylo build");
 #endif
 }
+
+void
+Element::SetCustomElementData(CustomElementData* aData)
+{
+  nsDOMSlots *slots = DOMSlots();
+  MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set.");
+  slots->mCustomElementData = aData;
+}
--- a/dom/base/Element.h
+++ b/dom/base/Element.h
@@ -458,16 +458,39 @@ public:
     return !!mServoData.Get();
 #else
     MOZ_CRASH("Accessing servo node data in non-stylo build");
 #endif
   }
 
   void ClearServoData();
 
+  /**
+   * Gets the custom element data used by web components custom element.
+   * Custom element data is created at the first attempt to enqueue a callback.
+   *
+   * @return The custom element data or null if none.
+   */
+  inline CustomElementData* GetCustomElementData() const
+  {
+    nsDOMSlots *slots = GetExistingDOMSlots();
+    if (slots) {
+      return slots->mCustomElementData;
+    }
+    return nullptr;
+  }
+
+  /**
+   * Sets the custom element data, ownership of the
+   * callback data is taken by this element.
+   *
+   * @param aData The custom element data.
+   */
+  void SetCustomElementData(CustomElementData* aData);
+
 protected:
   /**
    * Method to get the _intrinsic_ content state of this element.  This is the
    * state that is independent of the element's presentation.  To get the full
    * content state, use State().  See mozilla/EventStates.h for
    * the possible bits that could be set here.
    */
   virtual EventStates IntrinsicState() const;
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1147,34 +1147,16 @@ FragmentOrElement::SetXBLInsertionParent
 
   // We just changed the flattened tree, so any Servo style data is now invalid.
   // We rely on nsXBLService::LoadBindings to re-traverse the subtree afterwards.
   if (IsStyledByServo() && IsElement() && AsElement()->HasServoData()) {
     ServoRestyleManager::ClearServoDataFromSubtree(AsElement());
   }
 }
 
-CustomElementData*
-FragmentOrElement::GetCustomElementData() const
-{
-  nsDOMSlots *slots = GetExistingDOMSlots();
-  if (slots) {
-    return slots->mCustomElementData;
-  }
-  return nullptr;
-}
-
-void
-FragmentOrElement::SetCustomElementData(CustomElementData* aData)
-{
-  nsDOMSlots *slots = DOMSlots();
-  MOZ_ASSERT(!slots->mCustomElementData, "Custom element data may not be changed once set.");
-  slots->mCustomElementData = aData;
-}
-
 nsresult
 FragmentOrElement::InsertChildAt(nsIContent* aKid,
                                 uint32_t aIndex,
                                 bool aNotify)
 {
   NS_PRECONDITION(aKid, "null ptr");
 
   return doInsertChildAt(aKid, aIndex, aNotify, mAttrsAndChildren);
--- a/dom/base/FragmentOrElement.h
+++ b/dom/base/FragmentOrElement.h
@@ -31,16 +31,17 @@ class nsIControllers;
 class nsICSSDeclaration;
 class nsIDocument;
 class nsDOMStringMap;
 class nsIURI;
 
 namespace mozilla {
 class DeclarationBlock;
 namespace dom {
+struct CustomElementData;
 class DOMIntersectionObserver;
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 /**
  * A class that implements nsIWeakReference
  */
@@ -153,19 +154,16 @@ public:
   virtual ShadowRoot *GetContainingShadow() const override;
   virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
   virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
   virtual void SetShadowRoot(ShadowRoot* aBinding) override;
   virtual nsIContent *GetXBLInsertionParent() const override;
   virtual void SetXBLInsertionParent(nsIContent* aContent) override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
-  virtual CustomElementData *GetCustomElementData() const override;
-  virtual void SetCustomElementData(CustomElementData* aData) override;
-
   virtual void DestroyContent() override;
   virtual void SaveSubtreeState() override;
 
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
 
   nsIHTMLCollection* Children();
   uint32_t ChildElementCount()
   {
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -759,27 +759,16 @@ nsGenericDOMDataNode::SetXBLInsertionPar
   } else {
     nsDataSlots *slots = GetExistingDataSlots();
     if (slots) {
       slots->mXBLInsertionParent = nullptr;
     }
   }
 }
 
-CustomElementData *
-nsGenericDOMDataNode::GetCustomElementData() const
-{
-  return nullptr;
-}
-
-void
-nsGenericDOMDataNode::SetCustomElementData(CustomElementData* aData)
-{
-}
-
 bool
 nsGenericDOMDataNode::IsNodeOfType(uint32_t aFlags) const
 {
   return !(aFlags & ~(eCONTENT | eDATA_NODE));
 }
 
 void
 nsGenericDOMDataNode::SaveSubtreeState()
--- a/dom/base/nsGenericDOMDataNode.h
+++ b/dom/base/nsGenericDOMDataNode.h
@@ -156,19 +156,16 @@ public:
   virtual nsTArray<nsIContent*> &DestInsertionPoints() override;
   virtual nsTArray<nsIContent*> *GetExistingDestInsertionPoints() const override;
   virtual void SetShadowRoot(mozilla::dom::ShadowRoot* aShadowRoot) override;
   virtual nsIContent *GetXBLInsertionParent() const override;
   virtual void SetXBLInsertionParent(nsIContent* aContent) override;
   virtual bool IsNodeOfType(uint32_t aFlags) const override;
   virtual bool IsLink(nsIURI** aURI) const override;
 
-  virtual mozilla::dom::CustomElementData* GetCustomElementData() const override;
-  virtual void SetCustomElementData(mozilla::dom::CustomElementData* aData) override;
-
   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) override;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
                                               int32_t aModType) const;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override
   {
     nsCOMPtr<nsINode> result = CloneDataNode(aNodeInfo, true);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -14707,48 +14707,51 @@ nsGlobalWindow::FireOnNewGlobalObject()
   JS_FireOnNewGlobalObject(aes.cx(), global);
 }
 
 #ifdef _WINDOWS_
 #error "Never include windows.h in this file!"
 #endif
 
 already_AddRefed<Promise>
-nsGlobalWindow::CreateImageBitmap(const ImageBitmapSource& aImage,
+nsGlobalWindow::CreateImageBitmap(JSContext* aCx,
+                                  const ImageBitmapSource& aImage,
                                   ErrorResult& aRv)
 {
   if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     return nullptr;
   }
 
   return ImageBitmap::Create(this, aImage, Nothing(), aRv);
 }
 
 already_AddRefed<Promise>
-nsGlobalWindow::CreateImageBitmap(const ImageBitmapSource& aImage,
+nsGlobalWindow::CreateImageBitmap(JSContext* aCx,
+                                  const ImageBitmapSource& aImage,
                                   int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh,
                                   ErrorResult& aRv)
 {
   if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     return nullptr;
   }
 
   return ImageBitmap::Create(this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv);
 }
 
 already_AddRefed<mozilla::dom::Promise>
-nsGlobalWindow::CreateImageBitmap(const ImageBitmapSource& aImage,
+nsGlobalWindow::CreateImageBitmap(JSContext* aCx,
+                                  const ImageBitmapSource& aImage,
                                   int32_t aOffset, int32_t aLength,
                                   ImageBitmapFormat aFormat,
                                   const Sequence<ChannelPixelLayout>& aLayout,
                                   ErrorResult& aRv)
 {
-  if (!ImageBitmap::ExtensionsEnabled(nullptr, nullptr)) {
+  if (!ImageBitmap::ExtensionsEnabled(aCx, nullptr)) {
     aRv.Throw(NS_ERROR_TYPE_ERR);
     return nullptr;
   }
   if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
     return ImageBitmap::Create(this, aImage, aOffset, aLength, aFormat, aLayout,
                                aRv);
   }
   aRv.Throw(NS_ERROR_TYPE_ERR);
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1246,26 +1246,29 @@ public:
   {
     if (mDoc) {
       mDoc->WarnOnceAbout(nsIDocument::eWindow_Content);
     }
     GetContent(aCx, aRetval, aCallerType, aError);
   }
 
   already_AddRefed<mozilla::dom::Promise>
-  CreateImageBitmap(const mozilla::dom::ImageBitmapSource& aImage,
+  CreateImageBitmap(JSContext* aCx,
+                    const mozilla::dom::ImageBitmapSource& aImage,
                     mozilla::ErrorResult& aRv);
 
   already_AddRefed<mozilla::dom::Promise>
-  CreateImageBitmap(const mozilla::dom::ImageBitmapSource& aImage,
+  CreateImageBitmap(JSContext* aCx,
+                    const mozilla::dom::ImageBitmapSource& aImage,
                     int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh,
                     mozilla::ErrorResult& aRv);
 
   already_AddRefed<mozilla::dom::Promise>
-  CreateImageBitmap(const mozilla::dom::ImageBitmapSource& aImage,
+  CreateImageBitmap(JSContext* aCx,
+                    const mozilla::dom::ImageBitmapSource& aImage,
                     int32_t aOffset, int32_t aLength,
                     mozilla::dom::ImageBitmapFormat aFormat,
                     const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout,
                     mozilla::ErrorResult& aRv);
 
 
   // ChromeWindow bits.  Do NOT call these unless your window is in
   // fact an nsGlobalChromeWindow.
--- a/dom/base/nsIContent.h
+++ b/dom/base/nsIContent.h
@@ -21,17 +21,16 @@ class nsAttrName;
 class nsTextFragment;
 class nsIFrame;
 class nsXBLBinding;
 
 namespace mozilla {
 class EventChainPreVisitor;
 namespace dom {
 class ShadowRoot;
-struct CustomElementData;
 } // namespace dom
 namespace widget {
 struct IMEState;
 } // namespace widget
 } // namespace mozilla
 
 enum nsLinkState {
   eLinkState_Unvisited  = 1,
@@ -731,32 +730,16 @@ public:
    */
   inline nsIContent *GetFlattenedTreeParent() const;
 
   // Helper method, which we leave public so that it's accessible from nsINode.
   enum FlattenedParentType { eNotForStyle, eForStyle };
   nsINode* GetFlattenedTreeParentNodeInternal(FlattenedParentType aType) const;
 
   /**
-   * Gets the custom element data used by web components custom element.
-   * Custom element data is created at the first attempt to enqueue a callback.
-   *
-   * @return The custom element data or null if none.
-   */
-  virtual mozilla::dom::CustomElementData *GetCustomElementData() const = 0;
-
-  /**
-   * Sets the custom element data, ownership of the
-   * callback data is taken by this content.
-   *
-   * @param aCallbackData The custom element data.
-   */
-  virtual void SetCustomElementData(mozilla::dom::CustomElementData* aData) = 0;
-
-  /**
    * API to check if this is a link that's traversed in response to user input
    * (e.g. a click event). Specializations for HTML/SVG/generic XML allow for
    * different types of link in different types of content.
    *
    * @param aURI Required out param. If this content is a link, a new nsIURI
    *             set to this link's URI will be passed out.
    *
    * @note The out param, aURI, is guaranteed to be set to a non-null pointer
--- a/dom/base/nsRange.cpp
+++ b/dom/base/nsRange.cpp
@@ -3456,23 +3456,24 @@ IsVisibleAndNotInReplacedElement(nsIFram
         !f->GetContent()->IsHTMLElement(nsGkAtoms::select)) {
       return false;
     }
   }
   return true;
 }
 
 static bool
-ElementIsVisible(Element* aElement)
+ElementIsVisibleNoFlush(Element* aElement)
 {
   if (!aElement) {
     return false;
   }
-  RefPtr<nsStyleContext> sc = nsComputedDOMStyle::GetStyleContextForElement(
-    aElement, nullptr, nullptr);
+  RefPtr<nsStyleContext> sc =
+    nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
+                                                         nullptr);
   return sc && sc->StyleVisibility()->IsVisible();
 }
 
 static void
 AppendTransformedText(InnerTextAccumulator& aResult,
                       nsGenericDOMDataNode* aTextNode,
                       int32_t aStart, int32_t aEnd)
 {
@@ -3590,17 +3591,17 @@ nsRange::GetInnerTextNoFlush(DOMString& 
   }
 
   while (currentNode != endNode || currentState != endState) {
     nsIFrame* f = currentNode->GetPrimaryFrame();
     bool isVisibleAndNotReplaced = IsVisibleAndNotInReplacedElement(f);
     if (currentState == AT_NODE) {
       bool isText = currentNode->IsNodeOfType(nsINode::eTEXT);
       if (isText && currentNode->GetParent()->IsHTMLElement(nsGkAtoms::rp) &&
-          ElementIsVisible(currentNode->GetParent()->AsElement())) {
+          ElementIsVisibleNoFlush(currentNode->GetParent()->AsElement())) {
         nsAutoString str;
         currentNode->GetTextContent(str, aError);
         result.Append(str);
       } else if (isVisibleAndNotReplaced) {
         result.AddRequiredLineBreakCount(GetRequiredInnerTextLineBreakCount(f));
         if (isText) {
           nsIFrame::RenderedText text = f->GetRenderedText();
           result.Append(text.mString);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1361,16 +1361,17 @@ DOMInterfaces = {
 },
 
 'Window': {
     'nativeType': 'nsGlobalWindow',
     'binaryNames': {
         'postMessage': 'postMessageMoz',
     },
     'implicitJSContext': [
+        'createImageBitmap',
         'requestIdleCallback'
     ],
 },
 
 'WindowProxy': {
     'nativeType': 'nsPIDOMWindowOuter',
     'headerFile': 'nsPIDOMWindow.h',
     'concrete': False
@@ -1389,16 +1390,17 @@ DOMInterfaces = {
     'headerFile': 'mozilla/dom/WorkerScope.h',
     'implicitJSContext': [
         'dump', 'global', 'reportError', 'setConsoleEventHandler',
     ],
 },
 
 'WorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
+    'implicitJSContext': [ 'createImageBitmap' ],
     'concrete': False,
     # Rename a few things so we don't have both classes and methods
     # with the same name
     'binaryNames': {
         'performance': 'getPerformance',
     },
 },
 
--- a/dom/file/MutableBlobStorage.cpp
+++ b/dom/file/MutableBlobStorage.cpp
@@ -70,17 +70,16 @@ private:
 // the temporary file.
 class FileCreatedRunnable final : public Runnable
 {
 public:
   FileCreatedRunnable(MutableBlobStorage* aBlobStorage, PRFileDesc* aFD)
     : mBlobStorage(aBlobStorage)
     , mFD(aFD)
   {
-    MOZ_ASSERT(!NS_IsMainThread());
     MOZ_ASSERT(aBlobStorage);
     MOZ_ASSERT(aFD);
   }
 
   NS_IMETHOD
   Run() override
   {
     MOZ_ASSERT(NS_IsMainThread());
@@ -106,31 +105,29 @@ private:
 // dispatched back to the main-thread.
 class CreateTemporaryFileRunnable final : public Runnable
 {
 public:
   explicit CreateTemporaryFileRunnable(MutableBlobStorage* aBlobStorage)
     : mBlobStorage(aBlobStorage)
   {
     MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(XRE_IsParentProcess());
     MOZ_ASSERT(aBlobStorage);
   }
 
   NS_IMETHOD
   Run() override
   {
     MOZ_ASSERT(!NS_IsMainThread());
+    MOZ_ASSERT(XRE_IsParentProcess());
 
     PRFileDesc* tempFD = nullptr;
     nsresult rv = NS_OpenAnonymousTemporaryFile(&tempFD);
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      // In sandboxed context we are not allowed to create temporary files, but
-      // this doesn't mean that BlobStorage should fail. We can continue to
-      // store data in memory.  We don't change the storageType so that we don't
-      // try to create a temporary file again.
       return NS_OK;
     }
 
     // The ownership of the tempFD is moved to the FileCreatedRunnable.
     return NS_DispatchToMainThread(new FileCreatedRunnable(mBlobStorage, tempFD));
   }
 
 private:
@@ -529,19 +526,30 @@ MutableBlobStorage::ShouldBeTemporarySto
 
   return bufferSize.value() >= Preferences::GetUint("dom.blob.memoryToTemporaryFile",
                                                     BLOB_MEMORY_TEMPORARY_FILE);
 }
 
 nsresult
 MutableBlobStorage::MaybeCreateTemporaryFile()
 {
-  nsresult rv = DispatchToIOThread(new CreateTemporaryFileRunnable(this));
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return rv;
+  if (XRE_IsParentProcess()) {
+    nsresult rv = DispatchToIOThread(new CreateTemporaryFileRunnable(this));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  } else {
+    RefPtr<MutableBlobStorage> self(this);
+    ContentChild::GetSingleton()->
+      AsyncOpenAnonymousTemporaryFile([self](PRFileDesc* prfile) {
+        if (prfile) {
+          // The ownership of the prfile is moved to the FileCreatedRunnable.
+          NS_DispatchToMainThread(new FileCreatedRunnable(self, prfile));
+        }
+      });
   }
 
   mStorageState = eWaitingForTemporaryFile;
   return NS_OK;
 }
 
 void
 MutableBlobStorage::TemporaryFileCreated(PRFileDesc* aFD)
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -193,16 +193,17 @@
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "mozilla/widget/PuppetBidiKeyboard.h"
 #include "mozilla/RemoteSpellCheckEngineChild.h"
 #include "GMPServiceChild.h"
 #include "GfxInfoBase.h"
 #include "gfxPlatform.h"
 #include "nscore.h" // for NS_FREE_PERMANENT_DATA
 #include "VRManagerChild.h"
+#include "private/pprio.h"
 
 #ifdef MOZ_WIDGET_GTK
 #include "nsAppRunner.h"
 #endif
 #ifdef MOZ_CRASHREPORTER
 #include "mozilla/ipc/CrashReporterClient.h"
 #endif
 
@@ -3217,10 +3218,48 @@ ContentChild::RecvDeactivate(PBrowserChi
 
 mozilla::ipc::IPCResult
 ContentChild::RecvParentActivated(PBrowserChild* aTab, const bool& aActivated)
 {
   TabChild* tab = static_cast<TabChild*>(aTab);
   return tab->RecvParentActivated(aActivated);
 }
 
+mozilla::ipc::IPCResult
+ContentChild::RecvProvideAnonymousTemporaryFile(const uint64_t& aID,
+                                                const FileDescOrError& aFDOrError)
+{
+  nsAutoPtr<AnonymousTemporaryFileCallback> callback;
+  mPendingAnonymousTemporaryFiles.RemoveAndForget(aID, callback);
+  MOZ_ASSERT(callback);
+
+  PRFileDesc* prfile = nullptr;
+  if (aFDOrError.type() == FileDescOrError::Tnsresult) {
+    DebugOnly<nsresult> rv = aFDOrError.get_nsresult();
+    MOZ_ASSERT(NS_FAILED(rv));
+  } else {
+    auto rawFD = aFDOrError.get_FileDescriptor().ClonePlatformHandle();
+    prfile = PR_ImportFile(PROsfd(rawFD.release()));
+  }
+  (*callback)(prfile);
+  return IPC_OK();
+}
+
+nsresult
+ContentChild::AsyncOpenAnonymousTemporaryFile(AnonymousTemporaryFileCallback aCallback)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  static uint64_t id = 0;
+  auto newID = id++;
+  if (!SendRequestAnonymousTemporaryFile(newID)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  // Remember the association with the callback.
+  MOZ_ASSERT(!mPendingAnonymousTemporaryFiles.Get(newID));
+  mPendingAnonymousTemporaryFiles.LookupOrAdd(newID, aCallback);
+  return NS_OK;
+}
+
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -581,16 +581,19 @@ public:
           const bool& minimizeMemoryUsage,
           const MaybeFileDesc& DMDFile) override;
 
   virtual mozilla::ipc::IPCResult
   RecvSetXPCOMProcessAttributes(const XPCOMInitData& aXPCOMInit,
                                 const StructuredCloneData& aInitialData,
                                 nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
 
+  virtual mozilla::ipc::IPCResult
+  RecvProvideAnonymousTemporaryFile(const uint64_t& aID, const FileDescOrError& aFD) override;
+
 #if defined(XP_WIN) && defined(ACCESSIBILITY)
   bool
   SendGetA11yContentId();
 #endif // defined(XP_WIN) && defined(ACCESSIBILITY)
 
   // Get a reference to the font family list passed from the chrome process,
   // for use during gfx initialization.
   InfallibleTArray<mozilla::dom::FontFamilyListEntry>&
@@ -623,16 +626,19 @@ public:
   // This method is used by FileCreatorHelper for the creation of a BlobImpl.
   void
   FileCreationRequest(nsID& aUUID, FileCreatorHelper* aHelper,
                       const nsAString& aFullPath, const nsAString& aType,
                       const nsAString& aName,
                       const Optional<int64_t>& aLastModified,
                       bool aExistenceCheck, bool aIsFromNsIFile);
 
+  typedef std::function<void(PRFileDesc*)> AnonymousTemporaryFileCallback;
+  nsresult AsyncOpenAnonymousTemporaryFile(AnonymousTemporaryFileCallback aCallback);
+
 private:
   static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
   void StartForceKillTimer();
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   virtual void ProcessingError(Result aCode, const char* aReason) override;
 
@@ -691,16 +697,19 @@ private:
   // This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
   // received.
   nsRefPtrHashtable<nsIDHashKey, GetFilesHelperChild> mGetFilesPendingRequests;
 
   // Hashtable to keep track of the pending file creation.
   // These items are removed when RecvFileCreationResponse is received.
   nsRefPtrHashtable<nsIDHashKey, FileCreatorHelper> mFileCreationPending;
 
+
+  nsClassHashtable<nsUint64HashKey, AnonymousTemporaryFileCallback> mPendingAnonymousTemporaryFiles;
+
   bool mShuttingDown;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 uint64_t
 NextWindowID();
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4082,16 +4082,90 @@ ContentParent::RecvBackUpXResources(cons
   if (aXSocketFd.IsValid()) {
     auto rawFD = aXSocketFd.ClonePlatformHandle();
     mChildXSocketFdDup.reset(rawFD.release());
   }
 #endif
   return IPC_OK();
 }
 
+class AnonymousTemporaryFileRequestor final : public Runnable
+{
+public:
+  AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID)
+    : mCP(aCP)
+    , mID(aID)
+    , mRv(NS_OK)
+    , mPRFD(nullptr)
+  {
+  }
+
+  NS_IMETHOD Run() override
+  {
+    if (NS_IsMainThread()) {
+      FileDescOrError result;
+      if (NS_WARN_IF(NS_FAILED(mRv))) {
+        // Returning false will kill the child process; instead
+        // propagate the error and let the child handle it.
+        result = mRv;
+      } else {
+        result = FileDescriptor(FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mPRFD)));
+        // The FileDescriptor object owns a duplicate of the file handle; we
+        // must close the original (and clean up the NSPR descriptor).
+        PR_Close(mPRFD);
+      }
+      Unused << mCP->SendProvideAnonymousTemporaryFile(mID, result);
+      // It's important to release this reference while wr're on the main thread!
+      mCP = nullptr;
+    } else {
+      mRv = NS_OpenAnonymousTemporaryFile(&mPRFD);
+      NS_DispatchToMainThread(this);
+    }
+    return NS_OK;
+  }
+
+private:
+  RefPtr<ContentParent> mCP;
+  uint64_t mID;
+  nsresult mRv;
+  PRFileDesc* mPRFD;
+};
+
+mozilla::ipc::IPCResult
+ContentParent::RecvRequestAnonymousTemporaryFile(const uint64_t& aID)
+{
+  // Make sure to send a callback to the child if we bail out early.
+  nsresult rv = NS_OK;
+  RefPtr<ContentParent> self(this);
+  auto autoNotifyChildOnError = MakeScopeExit([&]() {
+    if (NS_FAILED(rv)) {
+      FileDescOrError result(rv);
+      Unused << self->SendProvideAnonymousTemporaryFile(aID, result);
+    }
+  });
+
+  // We use a helper runnable to open the anonymous temporary file on the IO
+  // thread.  The same runnable will call us back on the main thread when the
+  // file has been opened.
+  nsCOMPtr<nsIEventTarget> target
+    = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
+  if (!target) {
+    return IPC_OK();
+  }
+
+  rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID),
+                        NS_DISPATCH_NORMAL);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return IPC_OK();
+  }
+
+  rv = NS_OK;
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult
 ContentParent::RecvOpenAnonymousTemporaryFile(FileDescOrError *aFD)
 {
   PRFileDesc *prfd;
   nsresult rv = NS_OpenAnonymousTemporaryFile(&prfd);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     // Returning false will kill the child process; instead
     // propagate the error and let the child handle it.
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1054,16 +1054,19 @@ private:
 
   virtual mozilla::ipc::IPCResult RecvRemoveIdleObserver(const uint64_t& observerId,
                                                          const uint32_t& aIdleTimeInS) override;
 
   virtual mozilla::ipc::IPCResult
   RecvBackUpXResources(const FileDescriptor& aXSocketFd) override;
 
   virtual mozilla::ipc::IPCResult
+  RecvRequestAnonymousTemporaryFile(const uint64_t& aID) override;
+
+  virtual mozilla::ipc::IPCResult
   RecvOpenAnonymousTemporaryFile(FileDescOrError* aFD) override;
 
   virtual mozilla::ipc::IPCResult
   RecvKeygenProcessValue(const nsString& oldValue, const nsString& challenge,
                          const nsString& keytype, const nsString& keyparams,
                          nsString* newValue) override;
 
   virtual mozilla::ipc::IPCResult
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -586,16 +586,18 @@ child:
     async Activate(PBrowser aTab);
 
     async Deactivate(PBrowser aTab);
 
     async ParentActivated(PBrowser aTab, bool aActivated);
 
     async PParentToChildStream();
 
+    async ProvideAnonymousTemporaryFile(uint64_t aID, FileDescOrError aFD);
+
 parent:
     async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority,
                             TabId openerTabId)
         returns (ContentParentId cpId, bool isForBrowser, TabId tabId);
     sync BridgeToChildProcess(ContentParentId cpId)
@@ -867,16 +869,18 @@ parent:
      * around until after both the plugin process shuts down *and* the
      * parent process closes the dup fd.  This is used to prevent the
      * parent process from crashing on X errors if, e.g., the plugin
      * crashes *just before* a repaint and the parent process tries to
      * use the newly-invalid surface.
      */
     async BackUpXResources(FileDescriptor aXSocketFd);
 
+    async RequestAnonymousTemporaryFile(uint64_t aID);
+
     sync OpenAnonymousTemporaryFile() returns (FileDescOrError aFD);
 
     /**
      * Keygen requires us to call it after a <keygen> element is parsed and
      * before one is submitted. This is urgent because an extension might use
      * a CPOW to synchronously submit a keygen element.
      */
     nested(inside_cpow) sync KeygenProcessValue(nsString oldValue,
--- a/dom/media/EncodedBufferCache.cpp
+++ b/dom/media/EncodedBufferCache.cpp
@@ -1,37 +1,77 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "EncodedBufferCache.h"
-#include "mozilla/dom/File.h"
+#include "prio.h"
 #include "nsAnonymousTemporaryFile.h"
-#include "prio.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/File.h"
+#include "nsThreadUtils.h"
+#include "nsXULAppAPI.h"
 
 namespace mozilla {
 
 void
 EncodedBufferCache::AppendBuffer(nsTArray<uint8_t> & aBuf)
 {
+  MOZ_ASSERT(!NS_IsMainThread());
+
   MutexAutoLock lock(mMutex);
   mDataSize += aBuf.Length();
 
   mEncodedBuffers.AppendElement()->SwapElements(aBuf);
 
   if (!mTempFileEnabled && mDataSize > mMaxMemoryStorage) {
     nsresult rv;
     PRFileDesc* tempFD = nullptr;
     {
-      // Release the mMutex because there is a sync dispatch to mainthread in
-      // NS_OpenAnonymousTemporaryFile.
+      // Release the mMutex because of the sync dispatch to the main thread.
       MutexAutoUnlock unlock(mMutex);
-      rv = NS_OpenAnonymousTemporaryFile(&tempFD);
+      if (XRE_IsParentProcess()) {
+        // In case we are in the parent process, do a synchronous I/O here to open a
+        // temporary file.
+        rv = NS_OpenAnonymousTemporaryFile(&tempFD);
+      } else {
+        // In case we are in the child process, we don't have access to open a file
+        // directly due to sandbox restrictions, so we need to ask the parent process
+        // to do that for us.  In order to initiate the IPC, we need to first go to
+        // the main thread.  This is done by dispatching a runnable to the main thread.
+        // From there, we start an asynchronous IPC, and we block the current thread
+        // using a monitor while this async work is in progress.  When we receive the
+        // resulting file descriptor from the parent process, we notify the monitor
+        // and unblock the current thread and continue.
+        typedef dom::ContentChild::AnonymousTemporaryFileCallback
+          AnonymousTemporaryFileCallback;
+        bool done = false;
+        Monitor monitor("EncodeBufferCache::AppendBuffer");
+        RefPtr<dom::ContentChild> cc = dom::ContentChild::GetSingleton();
+        nsCOMPtr<nsIRunnable> runnable =
+          NewRunnableMethod<AnonymousTemporaryFileCallback>(cc,
+            &dom::ContentChild::AsyncOpenAnonymousTemporaryFile,
+            [&](PRFileDesc* aFile) {
+              rv = aFile ? NS_OK : NS_ERROR_FAILURE;
+              tempFD = aFile;
+              MonitorAutoLock lock(monitor);
+              done = true;
+              lock.Notify();
+            });
+        MonitorAutoLock lock(monitor);
+        rv = NS_DispatchToMainThread(runnable);
+        if (NS_SUCCEEDED(rv)) {
+          while (!done) {
+            lock.Wait();
+          }
+        }
+      }
     }
     if (!NS_FAILED(rv)) {
       // Check the mDataSize again since we release the mMutex before.
       if (mDataSize > mMaxMemoryStorage) {
         mFD = tempFD;
         mTempFileEnabled = true;
       } else {
         // Close the tempFD because the data had been taken during the
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -436,51 +436,51 @@ WorkerGlobalScope::GetIndexedDB(ErrorRes
 
     mIndexedDB = indexedDB;
   }
 
   return indexedDB.forget();
 }
 
 already_AddRefed<Promise>
-WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage,
+WorkerGlobalScope::CreateImageBitmap(JSContext* aCx,
+                                     const ImageBitmapSource& aImage,
                                      ErrorResult& aRv)
 {
   if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     return nullptr;
   }
 
   return ImageBitmap::Create(this, aImage, Nothing(), aRv);
 }
 
 already_AddRefed<Promise>
-WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage,
+WorkerGlobalScope::CreateImageBitmap(JSContext* aCx,
+                                     const ImageBitmapSource& aImage,
                                      int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh,
                                      ErrorResult& aRv)
 {
   if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
     aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     return nullptr;
   }
 
   return ImageBitmap::Create(this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aRv);
 }
 
 already_AddRefed<mozilla::dom::Promise>
-WorkerGlobalScope::CreateImageBitmap(const ImageBitmapSource& aImage,
+WorkerGlobalScope::CreateImageBitmap(JSContext* aCx,
+                                     const ImageBitmapSource& aImage,
                                      int32_t aOffset, int32_t aLength,
                                      ImageBitmapFormat aFormat,
                                      const Sequence<ChannelPixelLayout>& aLayout,
                                      ErrorResult& aRv)
 {
-  JSContext* cx = GetCurrentThreadJSContext();
-  MOZ_ASSERT(cx);
-
-  if (!ImageBitmap::ExtensionsEnabled(cx, nullptr)) {
+  if (!ImageBitmap::ExtensionsEnabled(aCx, nullptr)) {
     aRv.Throw(NS_ERROR_TYPE_ERR);
     return nullptr;
   }
 
   if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
     return ImageBitmap::Create(this, aImage, aOffset, aLength, aFormat, aLayout,
                                aRv);
   } else {
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -163,25 +163,28 @@ public:
   GetIndexedDB(ErrorResult& aErrorResult);
 
   already_AddRefed<cache::CacheStorage>
   GetCaches(ErrorResult& aRv);
 
   bool IsSecureContext() const;
 
   already_AddRefed<Promise>
-  CreateImageBitmap(const ImageBitmapSource& aImage, ErrorResult& aRv);
+  CreateImageBitmap(JSContext* aCx,
+                    const ImageBitmapSource& aImage, ErrorResult& aRv);
 
   already_AddRefed<Promise>
-  CreateImageBitmap(const ImageBitmapSource& aImage,
+  CreateImageBitmap(JSContext* aCx,
+                    const ImageBitmapSource& aImage,
                     int32_t aSx, int32_t aSy, int32_t aSw, int32_t aSh,
                     ErrorResult& aRv);
 
   already_AddRefed<mozilla::dom::Promise>
-  CreateImageBitmap(const ImageBitmapSource& aImage,
+  CreateImageBitmap(JSContext* aCx,
+                    const ImageBitmapSource& aImage,
                     int32_t aOffset, int32_t aLength,
                     mozilla::dom::ImageBitmapFormat aFormat,
                     const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout,
                     mozilla::ErrorResult& aRv);
 
   bool
   WindowInteractionAllowed() const
   {
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -123,17 +123,20 @@ class MOZ_STACK_CLASS CallArgsBase : pub
 {
     static_assert(mozilla::IsSame<WantUsedRval, IncludeUsedRval>::value ||
                   mozilla::IsSame<WantUsedRval, NoUsedRval>::value,
                   "WantUsedRval can only be IncludeUsedRval or NoUsedRval");
 
   protected:
     Value* argv_;
     unsigned argc_;
-    bool constructing_;
+    bool constructing_:1;
+
+    // True if the caller does not use the return value.
+    bool ignoresReturnValue_:1;
 
   public:
     // CALLEE ACCESS
 
     /*
      * Returns the function being called, as a value.  Must not be called after
      * rval() has been used!
      */
@@ -159,16 +162,20 @@ class MOZ_STACK_CLASS CallArgsBase : pub
 #ifdef JS_DEBUG
         if (!this->usedRval_)
             CheckIsValidConstructible(calleev());
 #endif
 
         return true;
     }
 
+    bool ignoresReturnValue() const {
+        return ignoresReturnValue_;
+    }
+
     MutableHandleValue newTarget() const {
         MOZ_ASSERT(constructing_);
         return MutableHandleValue::fromMarkedLocation(&this->argv_[argc_]);
     }
 
     /*
      * Returns the |this| value passed to the function.  This method must not
      * be called when the function is being called as a constructor via |new|.
@@ -275,24 +282,27 @@ class MOZ_STACK_CLASS CallArgsBase : pub
 };
 
 } // namespace detail
 
 class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsedRval>
 {
   private:
     friend CallArgs CallArgsFromVp(unsigned argc, Value* vp);
-    friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing);
+    friend CallArgs CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing,
+                                   bool ignoresReturnValue);
 
-    static CallArgs create(unsigned argc, Value* argv, bool constructing) {
+    static CallArgs create(unsigned argc, Value* argv, bool constructing,
+                           bool ignoresReturnValue = false) {
         CallArgs args;
         args.clearUsedRval();
         args.argv_ = argv;
         args.argc_ = argc;
         args.constructing_ = constructing;
+        args.ignoresReturnValue_ = ignoresReturnValue;
 #ifdef DEBUG
         MOZ_ASSERT(ValueIsNotGray(args.thisv()));
         MOZ_ASSERT(ValueIsNotGray(args.calleev()));
         for (unsigned i = 0; i < argc; ++i)
             MOZ_ASSERT(ValueIsNotGray(argv[i]));
 #endif
         return args;
     }
@@ -311,19 +321,21 @@ CallArgsFromVp(unsigned argc, Value* vp)
 {
     return CallArgs::create(argc, vp + 2, vp[1].isMagic(JS_IS_CONSTRUCTING));
 }
 
 // This method is only intended for internal use in SpiderMonkey.  We may
 // eventually move it to an internal header.  Embedders should use
 // JS::CallArgsFromVp!
 MOZ_ALWAYS_INLINE CallArgs
-CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false)
+CallArgsFromSp(unsigned stackSlots, Value* sp, bool constructing = false,
+               bool ignoresReturnValue = false)
 {
-    return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing);
+    return CallArgs::create(stackSlots - constructing, sp - stackSlots, constructing,
+                            ignoresReturnValue);
 }
 
 } // namespace JS
 
 /*
  * Macros to hide interpreter stack layout details from a JSNative using its
  * JS::Value* vp parameter.  DO NOT USE THESE!  Instead use JS::CallArgs and
  * friends, above.  These macros will be removed when we change JSNative to
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -4585,17 +4585,17 @@ BytecodeEmitter::emitSwitch(ParseNode* p
 
         // Emit code for evaluating cases and jumping to case statements.
         for (CaseClause* caseNode = firstCase; caseNode; caseNode = caseNode->next()) {
             ParseNode* caseValue = caseNode->caseExpression();
 
             // If the expression is a literal, suppress line number emission so
             // that debugging works more naturally.
             if (caseValue) {
-                if (!emitTree(caseValue,
+                if (!emitTree(caseValue, ValueUsage::WantValue,
                               caseValue->isLiteral() ? SUPPRESS_LINENOTE : EMIT_LINENOTE))
                 {
                     return false;
                 }
             }
 
             if (!beforeCases) {
                 // prevCase is the previous JSOP_CASE's bytecode offset.
@@ -6613,17 +6613,17 @@ BytecodeEmitter::emitLexicalScopeBody(Pa
         // This block contains function statements whose definitions are
         // hoisted to the top of the block. Emit these as a separate pass
         // before the rest of the block.
         if (!emitHoistedFunctionsInList(body))
             return false;
     }
 
     // Line notes were updated by emitLexicalScope.
-    return emitTree(body, emitLineNote);
+    return emitTree(body, ValueUsage::WantValue, emitLineNote);
 }
 
 // Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
 // the comment on emitSwitch.
 MOZ_NEVER_INLINE bool
 BytecodeEmitter::emitLexicalScope(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
@@ -6715,19 +6715,19 @@ BytecodeEmitter::emitRequireObjectCoerci
                     JSOP_GETINTRINSIC))    // VAL VAL REQUIREOBJECTCOERCIBLE
     {
         return false;
     }
     if (!emit1(JSOP_UNDEFINED))            // VAL VAL REQUIREOBJECTCOERCIBLE UNDEFINED
         return false;
     if (!emit2(JSOP_PICK, 2))              // VAL REQUIREOBJECTCOERCIBLE UNDEFINED VAL
         return false;
-    if (!emitCall(JSOP_CALL, 1))           // VAL IGNORED
-        return false;
-    checkTypeSet(JSOP_CALL);
+    if (!emitCall(JSOP_CALL_IGNORES_RV, 1))// VAL IGNORED
+        return false;
+    checkTypeSet(JSOP_CALL_IGNORES_RV);
 
     if (!emit1(JSOP_POP))                  // VAL
         return false;
 
     MOZ_ASSERT(depth == this->stackDepth);
     return true;
 }
 
@@ -7237,22 +7237,24 @@ BytecodeEmitter::emitCStyleFor(ParseNode
     // ES6 spec also skips cloning the environment in this case.)
     bool forLoopRequiresFreshening = false;
     if (ParseNode* init = forHead->pn_kid1) {
         // Emit the `init` clause, whether it's an expression or a variable
         // declaration. (The loop variables were hoisted into an enclosing
         // scope, but we still need to emit code for the initializers.)
         if (!updateSourceCoordNotes(init->pn_pos.begin))
             return false;
-        if (!emitTree(init))
-            return false;
-
-        if (!init->isForLoopDeclaration()) {
+        if (init->isForLoopDeclaration()) {
+            if (!emitTree(init))
+                return false;
+        } else {
             // 'init' is an expression, not a declaration. emitTree left its
             // value on the stack.
+            if (!emitTree(init, ValueUsage::IgnoreValue))
+                return false;
             if (!emit1(JSOP_POP))
                 return false;
         }
 
         // ES 13.7.4.8 step 2. The initial freshening.
         //
         // If an initializer let-declaration may be captured during loop iteration,
         // the current scope has an environment.  If so, freshen the current
@@ -7324,17 +7326,17 @@ BytecodeEmitter::emitCStyleFor(ParseNode
 
     // Check for update code to do before the condition (if any).
     // The update code may not be executed at all; it needs its own TDZ cache.
     if (ParseNode* update = forHead->pn_kid3) {
         TDZCheckCache tdzCache(this);
 
         if (!updateSourceCoordNotes(update->pn_pos.begin))
             return false;
-        if (!emitTree(update))
+        if (!emitTree(update, ValueUsage::IgnoreValue))
             return false;
         if (!emit1(JSOP_POP))
             return false;
 
         /* Restore the absolute line number for source note readers. */
         uint32_t lineNum = parser->tokenStream.srcCoords.lineNum(pn->pn_pos.end);
         if (currentLine() != lineNum) {
             if (!newSrcNote2(SRC_SETLINE, ptrdiff_t(lineNum)))
@@ -8681,18 +8683,19 @@ BytecodeEmitter::emitStatement(ParseNode
             innermostNestableControl->as<LabelControl>().startOffset() >= offset())
         {
             useful = true;
         }
     }
 
     if (useful) {
         JSOp op = wantval ? JSOP_SETRVAL : JSOP_POP;
+        ValueUsage valueUsage = wantval ? ValueUsage::WantValue : ValueUsage::IgnoreValue;
         MOZ_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
-        if (!emitTree(pn2))
+        if (!emitTree(pn2, valueUsage))
             return false;
         if (!emit1(op))
             return false;
     } else if (pn->isDirectivePrologueMember()) {
         // Don't complain about directive prologue members; just don't emit
         // their code.
     } else {
         if (JSAtom* atom = pn->isStringExprStatement()) {
@@ -9060,17 +9063,17 @@ BytecodeEmitter::emitOptimizeSpread(Pars
     if (!emit1(JSOP_POP))
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
-BytecodeEmitter::emitCallOrNew(ParseNode* pn)
+BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */)
 {
     bool callop = pn->isKind(PNK_CALL) || pn->isKind(PNK_TAGGED_TEMPLATE);
     /*
      * Emit callable invocation or operator new (constructor call) code.
      * First, emit code for the left operand to evaluate the callable or
      * constructable object expression.
      *
      * For operator new, we emit JSOP_GETPROP instead of JSOP_CALLPROP, etc.
@@ -9241,23 +9244,30 @@ BytecodeEmitter::emitCallOrNew(ParseNode
             } else {
                 if (!emitDupAt(2))
                     return false;
             }
         }
     }
 
     if (!spread) {
-        if (!emitCall(pn->getOp(), argc, pn))
-            return false;
+        if (pn->getOp() == JSOP_CALL && valueUsage == ValueUsage::IgnoreValue) {
+            if (!emitCall(JSOP_CALL_IGNORES_RV, argc, pn))
+                return false;
+            checkTypeSet(JSOP_CALL_IGNORES_RV);
+        } else {
+            if (!emitCall(pn->getOp(), argc, pn))
+                return false;
+            checkTypeSet(pn->getOp());
+        }
     } else {
         if (!emit1(pn->getOp()))
             return false;
-    }
-    checkTypeSet(pn->getOp());
+        checkTypeSet(pn->getOp());
+    }
     if (pn->isOp(JSOP_EVAL) ||
         pn->isOp(JSOP_STRICTEVAL) ||
         pn->isOp(JSOP_SPREADEVAL) ||
         pn->isOp(JSOP_STRICTSPREADEVAL))
     {
         uint32_t lineNum = parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
         if (!emitUint32Operand(JSOP_LINENO, lineNum))
             return false;
@@ -9345,22 +9355,23 @@ BytecodeEmitter::emitLogical(ParseNode* 
         return false;
 
     if (!emitJumpTargetAndPatch(jump))
         return false;
     return true;
 }
 
 bool
-BytecodeEmitter::emitSequenceExpr(ParseNode* pn)
+BytecodeEmitter::emitSequenceExpr(ParseNode* pn,
+                                  ValueUsage valueUsage /* = ValueUsage::WantValue */)
 {
     for (ParseNode* child = pn->pn_head; ; child = child->pn_next) {
         if (!updateSourceCoordNotes(child->pn_pos.begin))
             return false;
-        if (!emitTree(child))
+        if (!emitTree(child, child->pn_next ? ValueUsage::IgnoreValue : valueUsage))
             return false;
         if (!child->pn_next)
             break;
         if (!emit1(JSOP_POP))
             return false;
     }
     return true;
 }
@@ -9413,33 +9424,34 @@ BytecodeEmitter::emitLabeledStatement(co
 
     if (!controlInfo.patchBreaks(this))
         return false;
 
     return true;
 }
 
 bool
-BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional)
+BytecodeEmitter::emitConditionalExpression(ConditionalExpression& conditional,
+                                           ValueUsage valueUsage /* = ValueUsage::WantValue */)
 {
     /* Emit the condition, then branch if false to the else part. */
     if (!emitTree(&conditional.condition()))
         return false;
 
     IfThenElseEmitter ifThenElse(this);
     if (!ifThenElse.emitCond())
         return false;
 
-    if (!emitTreeInBranch(&conditional.thenExpression()))
+    if (!emitTreeInBranch(&conditional.thenExpression(), valueUsage))
         return false;
 
     if (!ifThenElse.emitElse())
         return false;
 
-    if (!emitTreeInBranch(&conditional.elseExpression()))
+    if (!emitTreeInBranch(&conditional.elseExpression(), valueUsage))
         return false;
 
     if (!ifThenElse.emitEnd())
         return false;
     MOZ_ASSERT(ifThenElse.pushed() == 1);
 
     return true;
 }
@@ -10307,17 +10319,18 @@ BytecodeEmitter::emitClass(ParseNode* pn
     }
 
     MOZ_ALWAYS_TRUE(sc->setLocalStrictMode(savedStrictness));
 
     return true;
 }
 
 bool
-BytecodeEmitter::emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote)
+BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::WantValue */,
+                          EmitLineNumberNote emitLineNote /* = EMIT_LINENOTE */)
 {
     if (!CheckRecursionLimit(cx))
         return false;
 
     EmitLevelManager elm(this);
 
     /* Emit notes to tell the current bytecode's source line number.
        However, a couple trees require special treatment; see the
@@ -10439,17 +10452,17 @@ BytecodeEmitter::emitTree(ParseNode* pn,
         break;
 
       case PNK_LABEL:
         if (!emitLabeledStatement(&pn->as<LabeledStatement>()))
             return false;
         break;
 
       case PNK_COMMA:
-        if (!emitSequenceExpr(pn))
+        if (!emitSequenceExpr(pn, valueUsage))
             return false;
         break;
 
       case PNK_ASSIGN:
       case PNK_ADDASSIGN:
       case PNK_SUBASSIGN:
       case PNK_BITORASSIGN:
       case PNK_BITXORASSIGN:
@@ -10461,17 +10474,17 @@ BytecodeEmitter::emitTree(ParseNode* pn,
       case PNK_DIVASSIGN:
       case PNK_MODASSIGN:
       case PNK_POWASSIGN:
         if (!emitAssignment(pn->pn_left, pn->getOp(), pn->pn_right))
             return false;
         break;
 
       case PNK_CONDITIONAL:
-        if (!emitConditionalExpression(pn->as<ConditionalExpression>()))
+        if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage))
             return false;
         break;
 
       case PNK_OR:
       case PNK_AND:
         if (!emitLogical(pn))
             return false;
         break;
@@ -10574,17 +10587,17 @@ BytecodeEmitter::emitTree(ParseNode* pn,
         }
         break;
 
       case PNK_NEW:
       case PNK_TAGGED_TEMPLATE:
       case PNK_CALL:
       case PNK_GENEXP:
       case PNK_SUPERCALL:
-        if (!emitCallOrNew(pn))
+        if (!emitCallOrNew(pn, valueUsage))
             return false;
         break;
 
       case PNK_LEXICALSCOPE:
         if (!emitLexicalScope(pn))
             return false;
         break;
 
@@ -10732,22 +10745,23 @@ BytecodeEmitter::emitTree(ParseNode* pn,
     if (emitLevel == 1) {
         if (!updateSourceCoordNotes(pn->pn_pos.end))
             return false;
     }
     return true;
 }
 
 bool
-BytecodeEmitter::emitTreeInBranch(ParseNode* pn)
+BytecodeEmitter::emitTreeInBranch(ParseNode* pn,
+                                  ValueUsage valueUsage /* = ValueUsage::WantValue */)
 {
     // Code that may be conditionally executed always need their own TDZ
     // cache.
     TDZCheckCache tdzCache(this);
-    return emitTree(pn);
+    return emitTree(pn, valueUsage);
 }
 
 static bool
 AllocSrcNote(JSContext* cx, SrcNotesVector& notes, unsigned* index)
 {
     // Start it off moderately large to avoid repeated resizings early on.
     // ~99% of cases fit within 256 bytes.
     if (notes.capacity() == 0 && !notes.reserve(256))
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -162,16 +162,21 @@ struct JumpList {
     // Add a jump instruction to the list.
     void push(jsbytecode* code, ptrdiff_t jumpOffset);
 
     // Patch all jump instructions in this list to jump to `target`.  This
     // clobbers the list.
     void patchAll(jsbytecode* code, JumpTarget target);
 };
 
+enum class ValueUsage {
+    WantValue,
+    IgnoreValue
+};
+
 struct MOZ_STACK_CLASS BytecodeEmitter
 {
     class TDZCheckCache;
     class NestableControl;
     class EmitterScope;
 
     SharedContext* const sc;      /* context shared between parsing and bytecode generation */
 
@@ -425,20 +430,22 @@ struct MOZ_STACK_CLASS BytecodeEmitter
 
     // Control whether emitTree emits a line number note.
     enum EmitLineNumberNote {
         EMIT_LINENOTE,
         SUPPRESS_LINENOTE
     };
 
     // Emit code for the tree rooted at pn.
-    MOZ_MUST_USE bool emitTree(ParseNode* pn, EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
+    MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue,
+                               EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
 
     // Emit code for the tree rooted at pn with its own TDZ cache.
-    MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn);
+    MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn,
+                                       ValueUsage valueUsage = ValueUsage::WantValue);
 
     // Emit global, eval, or module code for tree rooted at body. Always
     // encompasses the entire source.
     MOZ_MUST_USE bool emitScript(ParseNode* body);
 
     // Emit function code for the tree rooted at body.
     MOZ_MUST_USE bool emitFunctionScript(ParseNode* body);
 
@@ -726,26 +733,28 @@ struct MOZ_STACK_CLASS BytecodeEmitter
 
     // |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
     MOZ_MUST_USE bool emitTypeof(ParseNode* node, JSOp op);
 
     MOZ_MUST_USE bool emitUnary(ParseNode* pn);
     MOZ_MUST_USE bool emitRightAssociative(ParseNode* pn);
     MOZ_MUST_USE bool emitLeftAssociative(ParseNode* pn);
     MOZ_MUST_USE bool emitLogical(ParseNode* pn);
-    MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn);
+    MOZ_MUST_USE bool emitSequenceExpr(ParseNode* pn,
+                                       ValueUsage valueUsage = ValueUsage::WantValue);
 
     MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(ParseNode* pn);
 
-    MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional);
+    MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional,
+                                                ValueUsage valueUsage = ValueUsage::WantValue);
 
     MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result);
     MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted);
 
-    MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn);
+    MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
     MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedAllowContentIter(ParseNode* pn);
     MOZ_MUST_USE bool emitSelfHostedDefineDataProperty(ParseNode* pn);
 
     MOZ_MUST_USE bool emitComprehensionFor(ParseNode* compFor);
     MOZ_MUST_USE bool emitComprehensionForIn(ParseNode* pn);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -3295,16 +3295,22 @@ BaselineCompiler::emitSpreadCall()
 
 bool
 BaselineCompiler::emit_JSOP_CALL()
 {
     return emitCall();
 }
 
 bool
+BaselineCompiler::emit_JSOP_CALL_IGNORES_RV()
+{
+    return emitCall();
+}
+
+bool
 BaselineCompiler::emit_JSOP_CALLITER()
 {
     return emitCall();
 }
 
 bool
 BaselineCompiler::emit_JSOP_NEW()
 {
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -155,16 +155,17 @@ namespace jit {
     _(JSOP_SETARG)             \
     _(JSOP_CHECKLEXICAL)       \
     _(JSOP_INITLEXICAL)        \
     _(JSOP_INITGLEXICAL)       \
     _(JSOP_CHECKALIASEDLEXICAL) \
     _(JSOP_INITALIASEDLEXICAL) \
     _(JSOP_UNINITIALIZED)      \
     _(JSOP_CALL)               \
+    _(JSOP_CALL_IGNORES_RV)    \
     _(JSOP_CALLITER)           \
     _(JSOP_FUNCALL)            \
     _(JSOP_FUNAPPLY)           \
     _(JSOP_NEW)                \
     _(JSOP_EVAL)               \
     _(JSOP_STRICTEVAL)         \
     _(JSOP_SPREADCALL)         \
     _(JSOP_SPREADNEW)          \
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/BaselineIC.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/SizePrintfMacros.h"
 #include "mozilla/TemplateLib.h"
 
+#include "jsfriendapi.h"
+#include "jsfun.h"
 #include "jslibmath.h"
 #include "jstypes.h"
 
 #include "builtin/Eval.h"
 #include "builtin/SIMD.h"
 #include "gc/Policy.h"
 #include "jit/BaselineCacheIRCompiler.h"
 #include "jit/BaselineDebugModeOSR.h"
@@ -2191,21 +2193,27 @@ TryAttachCallStub(JSContext* cx, ICCall_
                 return false;
             if (skipAttach) {
                 *handled = true;
                 return true;
             }
             MOZ_ASSERT_IF(templateObject, !templateObject->group()->maybePreliminaryObjects());
         }
 
+        bool ignoresReturnValue = false;
+        if (op == JSOP_CALL_IGNORES_RV && fun->isNative()) {
+            const JSJitInfo* jitInfo = fun->jitInfo();
+            ignoresReturnValue = jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative;
+        }
+
         JitSpew(JitSpew_BaselineIC, "  Generating Call_Native stub (fun=%p, cons=%s, spread=%s)",
                 fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no");
         ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
-                                         fun, templateObject, constructing, isSpread,
-                                         script->pcToOffset(pc));
+                                         fun, templateObject, constructing, ignoresReturnValue,
+                                         isSpread, script->pcToOffset(pc));
         ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         stub->addNewStub(newStub);
         *handled = true;
         return true;
     }
@@ -2293,22 +2301,24 @@ DoCallFallback(JSContext* cx, BaselineFr
 
     RootedScript script(cx, frame->script());
     jsbytecode* pc = stub->icEntry()->pc(script);
     JSOp op = JSOp(*pc);
     FallbackICSpew(cx, stub, "Call(%s)", CodeName[op]);
 
     MOZ_ASSERT(argc == GET_ARGC(pc));
     bool constructing = (op == JSOP_NEW);
+    bool ignoresReturnValue = (op == JSOP_CALL_IGNORES_RV);
 
     // Ensure vp array is rooted - we may GC in here.
     size_t numValues = argc + 2 + constructing;
     AutoArrayRooter vpRoot(cx, numValues, vp);
 
-    CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing);
+    CallArgs callArgs = CallArgsFromSp(argc + constructing, vp + numValues, constructing,
+                                       ignoresReturnValue);
     RootedValue callee(cx, vp[0]);
 
     // Handle funapply with JSOP_ARGUMENTS
     if (op == JSOP_FUNAPPLY && argc == 2 && callArgs[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) {
         if (!GuardFunApplyArgumentsOptimization(cx, frame, callArgs))
             return false;
     }
 
@@ -2328,16 +2338,17 @@ DoCallFallback(JSContext* cx, BaselineFr
         res.set(callArgs.rval());
     } else if ((op == JSOP_EVAL || op == JSOP_STRICTEVAL) &&
                frame->environmentChain()->global().valueIsEval(callee))
     {
         if (!DirectEval(cx, callArgs.get(0), res))
             return false;
     } else {
         MOZ_ASSERT(op == JSOP_CALL ||
+                   op == JSOP_CALL_IGNORES_RV ||
                    op == JSOP_CALLITER ||
                    op == JSOP_FUNCALL ||
                    op == JSOP_FUNAPPLY ||
                    op == JSOP_EVAL ||
                    op == JSOP_STRICTEVAL);
         if (op == JSOP_CALLITER && callee.isPrimitive()) {
             MOZ_ASSERT(argc == 0, "thisv must be on top of the stack");
             ReportValueError(cx, JSMSG_NOT_ITERABLE, -1, callArgs.thisv(), nullptr);
@@ -3379,17 +3390,22 @@ ICCall_Native::Compiler::generateStubCod
     masm.passABIArg(vpReg);
 
 #ifdef JS_SIMULATOR
     // The simulator requires VM calls to be redirected to a special swi
     // instruction to handle them, so we store the redirected pointer in the
     // stub and use that instead of the original one.
     masm.callWithABI(Address(ICStubReg, ICCall_Native::offsetOfNative()));
 #else
-    masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript()));
+    if (ignoresReturnValue_) {
+        masm.loadPtr(Address(callee, JSFunction::offsetOfJitInfo()), callee);
+        masm.callWithABI(Address(callee, JSJitInfo::offsetOfIgnoresReturnValueNative()));
+    } else {
+        masm.callWithABI(Address(callee, JSFunction::offsetOfNativeOrScript()));
+    }
 #endif
 
     // Test for failure.
     masm.branchIfFalseBool(ReturnReg, masm.exceptionLabel());
 
     // Load the return value into R0.
     masm.loadValue(Address(masm.getStackPointer(), NativeExitFrameLayout::offsetOfResult()), R0);
 
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -663,16 +663,17 @@ class ICSetProp_Fallback : public ICFall
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICSetProp_Fallback>(space, getStubCode());
         }
     };
 };
 
 // Call
 //      JSOP_CALL
+//      JSOP_CALL_IGNORES_RV
 //      JSOP_FUNAPPLY
 //      JSOP_FUNCALL
 //      JSOP_NEW
 //      JSOP_SPREADCALL
 //      JSOP_SPREADNEW
 //      JSOP_SPREADEVAL
 
 class ICCallStubCompiler : public ICStubCompiler
@@ -933,36 +934,39 @@ class ICCall_Native : public ICMonitored
     }
 #endif
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         ICStub* firstMonitorStub_;
         bool isConstructing_;
+        bool ignoresReturnValue_;
         bool isSpread_;
         RootedFunction callee_;
         RootedObject templateObject_;
         uint32_t pcOffset_;
         MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
 
         virtual int32_t getKey() const {
             return static_cast<int32_t>(engine_) |
                   (static_cast<int32_t>(kind) << 1) |
-                  (static_cast<int32_t>(isConstructing_) << 17) |
-                  (static_cast<int32_t>(isSpread_) << 18);
+                  (static_cast<int32_t>(isSpread_) << 17) |
+                  (static_cast<int32_t>(isConstructing_) << 18) |
+                  (static_cast<int32_t>(ignoresReturnValue_) << 19);
         }
 
       public:
         Compiler(JSContext* cx, ICStub* firstMonitorStub,
                  HandleFunction callee, HandleObject templateObject,
-                 bool isConstructing, bool isSpread, uint32_t pcOffset)
+                 bool isConstructing, bool ignoresReturnValue, bool isSpread, uint32_t pcOffset)
           : ICCallStubCompiler(cx, ICStub::Call_Native),
             firstMonitorStub_(firstMonitorStub),
             isConstructing_(isConstructing),
+            ignoresReturnValue_(ignoresReturnValue),
             isSpread_(isSpread),
             callee_(cx, callee),
             templateObject_(cx, templateObject),
             pcOffset_(pcOffset)
         { }
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICCall_Native>(space, getStubCode(), firstMonitorStub_, callee_,
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3926,17 +3926,23 @@ CodeGenerator::visitCallNative(LCallNati
 
     emitTracelogStartEvent(TraceLogger_Call);
 
     // Construct and execute call.
     masm.setupUnalignedABICall(tempReg);
     masm.passABIArg(argContextReg);
     masm.passABIArg(argUintNReg);
     masm.passABIArg(argVpReg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, target->native()));
+    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));
 
     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);
@@ -4083,30 +4089,33 @@ static const VMFunction GetIntrinsicValu
 
 void
 CodeGenerator::visitCallGetIntrinsicValue(LCallGetIntrinsicValue* lir)
 {
     pushArg(ImmGCPtr(lir->mir()->name()));
     callVM(GetIntrinsicValueInfo, lir);
 }
 
-typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, uint32_t, Value*, MutableHandleValue);
+typedef bool (*InvokeFunctionFn)(JSContext*, HandleObject, bool, bool, uint32_t, Value*,
+                                 MutableHandleValue);
 static const VMFunction InvokeFunctionInfo =
     FunctionInfo<InvokeFunctionFn>(InvokeFunction, "InvokeFunction");
 
 void
 CodeGenerator::emitCallInvokeFunction(LInstruction* call, Register calleereg,
-                                      bool constructing, uint32_t argc, uint32_t unusedStack)
+                                      bool constructing, bool ignoresReturnValue,
+                                      uint32_t argc, uint32_t unusedStack)
 {
     // Nestle %esp up to the argument vector.
     // Each path must account for framePushed_ separately, for callVM to be valid.
     masm.freeStack(unusedStack);
 
     pushArg(masm.getStackPointer()); // argv.
     pushArg(Imm32(argc));            // argc.
+    pushArg(Imm32(ignoresReturnValue));
     pushArg(Imm32(constructing));    // constructing.
     pushArg(calleereg);              // JSFunction*.
 
     callVM(InvokeFunctionInfo, call);
 
     // Un-nestle %esp from the argument vector. No prefix was pushed.
     masm.reserveStack(unusedStack);
 }
@@ -4183,18 +4192,18 @@ CodeGenerator::visitCallGeneric(LCallGen
     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
     // The return address has already been removed from the Ion frame.
     int prefixGarbage = sizeof(JitFrameLayout) - sizeof(void*);
     masm.adjustStack(prefixGarbage - unusedStack);
     masm.jump(&end);
 
     // Handle uncompiled or native functions.
     masm.bind(&invoke);
-    emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(),
-                           unusedStack);
+    emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
+                           call->numActualArgs(), unusedStack);
 
     masm.bind(&end);
 
     // If the return value of the constructing function is Primitive,
     // replace the return value with the Object from CreateThis.
     if (call->mir()->isConstructing()) {
         Label notPrimitive;
         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
@@ -4239,17 +4248,18 @@ CodeGenerator::visitCallKnown(LCallKnown
     DebugOnly<unsigned> numNonArgsOnStack = 1 + call->isConstructing();
     MOZ_ASSERT(target->nargs() <= call->mir()->numStackArgs() - numNonArgsOnStack);
 
     MOZ_ASSERT_IF(call->isConstructing(), target->isConstructor());
 
     masm.checkStackAlignment();
 
     if (target->isClassConstructor() && !call->isConstructing()) {
-        emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack);
+        emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
+                               call->numActualArgs(), unusedStack);
         return;
     }
 
     MOZ_ASSERT_IF(target->isClassConstructor(), call->isConstructing());
 
     // The calleereg is known to be a non-native function, but might point to
     // a LazyScript instead of a JSScript.
     masm.branchIfFunctionHasNoScript(calleereg, &uncompiled);
@@ -4283,17 +4293,18 @@ CodeGenerator::visitCallKnown(LCallKnown
     masm.adjustStack(prefixGarbage - unusedStack);
     masm.jump(&end);
 
     // Handle uncompiled functions.
     masm.bind(&uncompiled);
     if (call->isConstructing() && target->nargs() > call->numActualArgs())
         emitCallInvokeFunctionShuffleNewTarget(call, calleereg, target->nargs(), unusedStack);
     else
-        emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->numActualArgs(), unusedStack);
+        emitCallInvokeFunction(call, calleereg, call->isConstructing(), call->ignoresReturnValue(),
+                               call->numActualArgs(), unusedStack);
 
     masm.bind(&end);
 
     // If the return value of the constructing function is Primitive,
     // replace the return value with the Object from CreateThis.
     if (call->mir()->isConstructing()) {
         Label notPrimitive;
         masm.branchTestPrimitive(Assembler::NotEqual, JSReturnOperand, &notPrimitive);
@@ -4310,16 +4321,17 @@ CodeGenerator::emitCallInvokeFunction(T*
     MOZ_ASSERT(objreg != extraStackSize);
 
     // Push the space used by the arguments.
     masm.moveStackPtrTo(objreg);
     masm.Push(extraStackSize);
 
     pushArg(objreg);                           // argv.
     pushArg(ToRegister(apply->getArgc()));     // argc.
+    pushArg(Imm32(false));                     // ignoresReturnValue.
     pushArg(Imm32(false));                     // isConstrucing.
     pushArg(ToRegister(apply->getFunction())); // JSFunction*.
 
     // This specialization og callVM restore the extraStackSize after the call.
     callVM(InvokeFunctionInfo, apply, &extraStackSize);
 
     masm.Pop(extraStackSize);
 }
@@ -4649,29 +4661,16 @@ CodeGenerator::visitApplyArrayGeneric(LA
     Address initializedLength(ToRegister(apply->getElements()),
                               ObjectElements::offsetOfInitializedLength());
     masm.sub32(initializedLength, tmp);
     bailoutCmp32(Assembler::NotEqual, tmp, Imm32(0), snapshot);
 
     emitApplyGeneric(apply);
 }
 
-typedef bool (*ArraySpliceDenseFn)(JSContext*, HandleObject, uint32_t, uint32_t);
-static const VMFunction ArraySpliceDenseInfo =
-    FunctionInfo<ArraySpliceDenseFn>(ArraySpliceDense, "ArraySpliceDense");
-
-void
-CodeGenerator::visitArraySplice(LArraySplice* lir)
-{
-    pushArg(ToRegister(lir->getDeleteCount()));
-    pushArg(ToRegister(lir->getStart()));
-    pushArg(ToRegister(lir->getObject()));
-    callVM(ArraySpliceDenseInfo, lir);
-}
-
 void
 CodeGenerator::visitBail(LBail* lir)
 {
     bailout(lir->snapshot());
 }
 
 void
 CodeGenerator::visitUnreachable(LUnreachable* lir)
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -163,18 +163,18 @@ class CodeGenerator final : public CodeG
     void visitPostWriteBarrierO(LPostWriteBarrierO* lir);
     void visitPostWriteElementBarrierO(LPostWriteElementBarrierO* lir);
     void visitPostWriteBarrierV(LPostWriteBarrierV* lir);
     void visitPostWriteElementBarrierV(LPostWriteElementBarrierV* lir);
     void visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool);
     void visitOutOfLineCallPostWriteElementBarrier(OutOfLineCallPostWriteElementBarrier* ool);
     void visitCallNative(LCallNative* call);
     void emitCallInvokeFunction(LInstruction* call, Register callereg,
-                                bool isConstructing, uint32_t argc,
-                                uint32_t unusedStack);
+                                bool isConstructing, bool ignoresReturnValue,
+                                uint32_t argc, uint32_t unusedStack);
     void visitCallGeneric(LCallGeneric* call);
     void emitCallInvokeFunctionShuffleNewTarget(LCallKnown *call,
                                                 Register calleeReg,
                                                 uint32_t numFormals,
                                                 uint32_t unusedStack);
     void visitCallKnown(LCallKnown* call);
     template<typename T> void emitApplyGeneric(T* apply);
     template<typename T> void emitCallInvokeFunction(T* apply, Register extraStackSize);
@@ -253,17 +253,16 @@ class CodeGenerator final : public CodeG
     void visitStoreFixedSlotT(LStoreFixedSlotT* ins);
     void emitGetPropertyPolymorphic(LInstruction* lir, Register obj,
                                     Register scratch, const TypedOrValueRegister& output);
     void visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV* ins);
     void visitGetPropertyPolymorphicT(LGetPropertyPolymorphicT* ins);
     void emitSetPropertyPolymorphic(LInstruction* lir, Register obj,
                                     Register scratch, const ConstantOrRegister& value);
     void visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins);
-    void visitArraySplice(LArraySplice* splice);
     void visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins);
     void visitAbsI(LAbsI* lir);
     void visitAtan2D(LAtan2D* lir);
     void visitHypot(LHypot* lir);
     void visitPowI(LPowI* lir);
     void visitPowD(LPowD* lir);
     void visitPowV(LPowV* lir);
     void visitMathFunctionD(LMathFunctionD* ins);
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -10,17 +10,16 @@
 #define INLINABLE_NATIVE_LIST(_)    \
     _(Array)                        \
     _(ArrayIsArray)                 \
     _(ArrayJoin)                    \
     _(ArrayPop)                     \
     _(ArrayShift)                   \
     _(ArrayPush)                    \
     _(ArraySlice)                   \
-    _(ArraySplice)                  \
                                     \
     _(AtomicsCompareExchange)       \
     _(AtomicsExchange)              \
     _(AtomicsLoad)                  \
     _(AtomicsStore)                 \
     _(AtomicsAdd)                   \
     _(AtomicsSub)                   \
     _(AtomicsAnd)                   \
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -2005,20 +2005,22 @@ IonBuilder::inspectOpcode(JSOp op)
 
       case JSOP_FUNCALL:
         return jsop_funcall(GET_ARGC(pc));
 
       case JSOP_FUNAPPLY:
         return jsop_funapply(GET_ARGC(pc));
 
       case JSOP_CALL:
+      case JSOP_CALL_IGNORES_RV:
       case JSOP_CALLITER:
       case JSOP_NEW:
       case JSOP_SUPERCALL:
-        MOZ_TRY(jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL));
+        MOZ_TRY(jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL,
+                          (JSOp)*pc == JSOP_CALL_IGNORES_RV));
         if (op == JSOP_CALLITER) {
             if (!outermostBuilder()->iterators_.append(current->peek(-1)))
                 return abort(AbortReason::Alloc);
         }
         return Ok();
 
       case JSOP_EVAL:
       case JSOP_STRICTEVAL:
@@ -4267,17 +4269,17 @@ AbortReasonOr<Ok>
 IonBuilder::inlineGenericFallback(JSFunction* target, CallInfo& callInfo, MBasicBlock* dispatchBlock)
 {
     // Generate a new block with all arguments on-stack.
     MBasicBlock* fallbackBlock;
     MOZ_TRY_VAR(fallbackBlock, newBlock(dispatchBlock, pc));
     graph().addBlock(fallbackBlock);
 
     // Create a new CallInfo to track modified state within this block.
-    CallInfo fallbackInfo(alloc(), callInfo.constructing());
+    CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
     if (!fallbackInfo.init(callInfo))
         return abort(AbortReason::Alloc);
     fallbackInfo.popFormals(fallbackBlock);
 
     // Generate an MCall, which uses stateful |current|.
     MOZ_TRY(setCurrentAndSpecializePhis(fallbackBlock));
     MOZ_TRY(makeCall(target, fallbackInfo));
 
@@ -4304,17 +4306,17 @@ IonBuilder::inlineObjectGroupFallback(Ca
     MOZ_ASSERT_IF(callInfo.fun()->isTypeBarrier(), cache->hasOneUse());
 
     // This means that no resume points yet capture the MGetPropertyCache,
     // so everything from the MGetPropertyCache up until the call is movable.
     // We now move the MGetPropertyCache and friends into a fallback path.
     MOZ_ASSERT(cache->idempotent());
 
     // Create a new CallInfo to track modified state within the fallback path.
-    CallInfo fallbackInfo(alloc(), callInfo.constructing());
+    CallInfo fallbackInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
     if (!fallbackInfo.init(callInfo))
         return abort(AbortReason::Alloc);
 
     // Capture stack prior to the call operation. This captures the function.
     MResumePoint* preCallResumePoint =
         MResumePoint::New(alloc(), dispatchBlock, pc, MResumePoint::ResumeAt);
     if (!preCallResumePoint)
         return abort(AbortReason::Alloc);
@@ -4480,17 +4482,17 @@ IonBuilder::inlineCalls(CallInfo& callIn
         dispatchBlock->add(funcDef);
 
         // Use the inlined callee in the inline resume point and on stack.
         int funIndex = inlineBlock->entryResumePoint()->stackDepth() - callInfo.numFormals();
         inlineBlock->entryResumePoint()->replaceOperand(funIndex, funcDef);
         inlineBlock->rewriteSlot(funIndex, funcDef);
 
         // Create a new CallInfo to track modified state within the inline block.
-        CallInfo inlineInfo(alloc(), callInfo.constructing());
+        CallInfo inlineInfo(alloc(), callInfo.constructing(), callInfo.ignoresReturnValue());
         if (!inlineInfo.init(callInfo))
             return abort(AbortReason::Alloc);
         inlineInfo.popFormals(inlineBlock);
         inlineInfo.setFun(funcDef);
 
         if (maybeCache) {
             // Assign the 'this' value a TypeSet specialized to the groups that
             // can generate this inlining target.
@@ -4923,17 +4925,18 @@ IonBuilder::jsop_funcall(uint32_t argc)
 
     int calleeDepth = -((int)argc + 2);
     int funcDepth = -((int)argc + 1);
 
     // If |Function.prototype.call| may be overridden, don't optimize callsite.
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction* native = getSingleCallTarget(calleeTypes);
     if (!native || !native->isNative() || native->native() != &fun_call) {
-        CallInfo callInfo(alloc(), false);
+        CallInfo callInfo(alloc(), /* constructing = */ false,
+                          /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         return makeCall(native, callInfo);
     }
     current->peek(calleeDepth)->setImplicitlyUsedUnchecked();
 
     // Extract call target.
     TemporaryTypeSet* funTypes = current->peek(funcDepth)->resultTypeSet();
@@ -4948,17 +4951,18 @@ IonBuilder::jsop_funcall(uint32_t argc)
     // Pushing is safe here, since one stack slot has been removed.
     if (zeroArguments) {
         pushConstant(UndefinedValue());
     } else {
         // |this| becomes implicit in the call.
         argc -= 1;
     }
 
-    CallInfo callInfo(alloc(), false);
+    CallInfo callInfo(alloc(), /* constructing = */ false,
+                      /* ignoresReturnValue = */ BytecodeIsPopped(pc));
     if (!callInfo.init(current, argc))
         return abort(AbortReason::Alloc);
 
     // Try to inline the call.
     if (!zeroArguments) {
         InliningDecision decision = makeInliningDecision(target, callInfo);
         switch (decision) {
           case InliningDecision_Error:
@@ -4984,17 +4988,18 @@ IonBuilder::jsop_funcall(uint32_t argc)
 AbortReasonOr<Ok>
 IonBuilder::jsop_funapply(uint32_t argc)
 {
     int calleeDepth = -((int)argc + 2);
 
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     JSFunction* native = getSingleCallTarget(calleeTypes);
     if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) {
-        CallInfo callInfo(alloc(), false);
+        CallInfo callInfo(alloc(), /* constructing = */ false,
+                          /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         return makeCall(native, callInfo);
     }
 
     // Disable compilation if the second argument to |apply| cannot be guaranteed
     // to be either definitely |arguments| or definitely not |arguments|.
     MDefinition* argument = current->peek(-1);
@@ -5013,17 +5018,18 @@ IonBuilder::jsop_funapply(uint32_t argc)
             objTypes &&
             objTypes->getKnownClass(constraints()) == &ArrayObject::class_ &&
             !objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW) &&
             ElementAccessIsPacked(constraints(), argument))
         {
             return jsop_funapplyarray(argc);
         }
 
-        CallInfo callInfo(alloc(), false);
+        CallInfo callInfo(alloc(), /* constructing = */ false,
+                          /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         return makeCall(native, callInfo);
     }
 
     if ((!native || !native->isNative() ||
         native->native() != fun_apply) &&
         info().analysisMode() != Analysis_DefiniteProperties)
@@ -5120,17 +5126,18 @@ IonBuilder::jsop_funapplyarguments(uint3
     }
 
     // When inlining we have the arguments the function gets called with
     // and can optimize even more, by just calling the functions with the args.
     // We also try this path when doing the definite properties analysis, as we
     // can inline the apply() target and don't care about the actual arguments
     // that were passed in.
 
-    CallInfo callInfo(alloc(), false);
+    CallInfo callInfo(alloc(), /* constructing = */ false,
+                      /* ignoresReturnValue = */ BytecodeIsPopped(pc));
 
     // Vp
     MDefinition* vp = current->pop();
     vp->setImplicitlyUsedUnchecked();
 
     // Arguments
     if (inliningDepth_) {
         if (!callInfo.setArgs(inlineCallInfo_->argv()))
@@ -5165,17 +5172,17 @@ IonBuilder::jsop_funapplyarguments(uint3
                 return Ok();
         }
     }
 
     return makeCall(target, callInfo);
 }
 
 AbortReasonOr<Ok>
-IonBuilder::jsop_call(uint32_t argc, bool constructing)
+IonBuilder::jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue)
 {
     startTrackingOptimizations();
 
     // If this call has never executed, try to seed the observed type set
     // based on how the call result is used.
     TemporaryTypeSet* observed = bytecodeTypes(pc);
     if (observed->empty()) {
         if (BytecodeFlowsToBitop(pc)) {
@@ -5191,17 +5198,17 @@ IonBuilder::jsop_call(uint32_t argc, boo
     int calleeDepth = -((int)argc + 2 + constructing);
 
     // Acquire known call target if existent.
     ObjectVector targets(alloc());
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
     if (calleeTypes)
         MOZ_TRY(getPolyCallTargets(calleeTypes, constructing, targets, 4));
 
-    CallInfo callInfo(alloc(), constructing);
+    CallInfo callInfo(alloc(), constructing, ignoresReturnValue);
     if (!callInfo.init(current, argc))
         return abort(AbortReason::Alloc);
 
     // Try inlining
     InliningStatus status;
     MOZ_TRY_VAR(status, inlineCallsite(targets, callInfo));
     if (status == InliningStatus_Inlined)
         return Ok();
@@ -5328,17 +5335,18 @@ IonBuilder::makeCallHelper(JSFunction* t
             thisTypes->getKnownMIRType() == MIRType::Object &&
             thisTypes->isDOMClass(constraints()))
         {
             MOZ_TRY_VAR(isDOMCall, testShouldDOMCall(thisTypes, target, JSJitInfo::Method));
         }
     }
 
     MCall* call = MCall::New(alloc(), target, targetArgs + 1 + callInfo.constructing(),
-                             callInfo.argc(), callInfo.constructing(), isDOMCall);
+                             callInfo.argc(), callInfo.constructing(),
+                             callInfo.ignoresReturnValue(), isDOMCall);
     if (!call)
         return abort(AbortReason::Alloc);
 
     if (callInfo.constructing())
         call->addArg(targetArgs + 1, callInfo.getNewTarget());
 
     // Explicitly pad any missing arguments with |undefined|.
     // This permits skipping the argumentsRectifier.
@@ -5426,33 +5434,34 @@ AbortReasonOr<Ok>
 IonBuilder::jsop_eval(uint32_t argc)
 {
     int calleeDepth = -((int)argc + 2);
     TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet();
 
     // Emit a normal call if the eval has never executed. This keeps us from
     // disabling compilation for the script when testing with --ion-eager.
     if (calleeTypes && calleeTypes->empty())
-        return jsop_call(argc, /* constructing = */ false);
+        return jsop_call(argc, /* constructing = */ false, false);
 
     JSFunction* singleton = getSingleCallTarget(calleeTypes);
     if (!singleton)
         return abort(AbortReason::Disable, "No singleton callee for eval()");
 
     if (script()->global().valueIsEval(ObjectValue(*singleton))) {
         if (argc != 1)
             return abort(AbortReason::Disable, "Direct eval with more than one argument");
 
         if (!info().funMaybeLazy())
             return abort(AbortReason::Disable, "Direct eval in global code");
 
         if (info().funMaybeLazy()->isArrow())
             return abort(AbortReason::Disable, "Direct eval from arrow function");
 
-        CallInfo callInfo(alloc(), /* constructing = */ false);
+        CallInfo callInfo(alloc(), /* constructing = */ false,
+                          /* ignoresReturnValue = */ BytecodeIsPopped(pc));
         if (!callInfo.init(current, argc))
             return abort(AbortReason::Alloc);
         callInfo.setImplicitlyUsedUnchecked();
 
         callInfo.fun()->setImplicitlyUsedUnchecked();
 
         MDefinition* envChain = current->environmentChain();
         MDefinition* string = callInfo.getArg(0);
@@ -5480,17 +5489,18 @@ IonBuilder::jsop_eval(uint32_t argc)
             if (StringEqualsAscii(atom, "()")) {
                 MDefinition* name = string->getOperand(0);
                 MInstruction* dynamicName = MGetDynamicName::New(alloc(), envChain, name);
                 current->add(dynamicName);
 
                 current->push(dynamicName);
                 current->push(constant(UndefinedValue())); // thisv
 
-                CallInfo evalCallInfo(alloc(), /* constructing = */ false);
+                CallInfo evalCallInfo(alloc(), /* constructing = */ false,
+                                      /* ignoresReturnValue = */ BytecodeIsPopped(pc));
                 if (!evalCallInfo.init(current, /* argc = */ 0))
                     return abort(AbortReason::Alloc);
 
                 return makeCall(nullptr, evalCallInfo);
             }
         }
 
         MInstruction* ins = MCallDirectEval::New(alloc(), envChain, string,
@@ -5498,17 +5508,17 @@ IonBuilder::jsop_eval(uint32_t argc)
         current->add(ins);
         current->push(ins);
 
         TemporaryTypeSet* types = bytecodeTypes(pc);
         MOZ_TRY(resumeAfter(ins));
         return pushTypeBarrier(ins, types, BarrierKind::TypeSet);
     }
 
-    return jsop_call(argc, /* constructing = */ false);
+    return jsop_call(argc, /* constructing = */ false, false);
 }
 
 AbortReasonOr<Ok>
 IonBuilder::jsop_compare(JSOp op)
 {
     MDefinition* right = current->pop();
     MDefinition* left = current->pop();
 
@@ -5752,18 +5762,18 @@ IonBuilder::compareTrySharedStub(bool* e
     return Ok();
 }
 
 static bool
 IsCallOpcode(JSOp op)
 {
     // TODO: Support tracking optimizations for inlining a call and regular
     // optimization tracking at the same time.
-    return op == JSOP_CALL || op == JSOP_CALLITER || op == JSOP_NEW || op == JSOP_SUPERCALL ||
-           op == JSOP_EVAL || op == JSOP_STRICTEVAL;
+    return op == JSOP_CALL || op == JSOP_CALL_IGNORES_RV || op == JSOP_CALLITER || op == JSOP_NEW ||
+           op == JSOP_SUPERCALL || op == JSOP_EVAL || op == JSOP_STRICTEVAL;
 }
 
 AbortReasonOr<Ok>
 IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, uint32_t length)
 {
     MOZ_ASSERT(*emitted == false);
 
     if (!IsCallOpcode(JSOp(*pc)))
@@ -10844,17 +10854,18 @@ IonBuilder::getPropTryCommonGetter(bool*
 
     // Make sure there's enough room
     if (!current->ensureHasSlots(2))
         return abort(AbortReason::Alloc);
     current->push(constant(ObjectValue(*commonGetter)));
 
     current->push(obj);
 
-    CallInfo callInfo(alloc(), false);
+    CallInfo callInfo(alloc(), /* constructing = */ false,
+                      /* ignoresReturnValue = */ BytecodeIsPopped(pc));
     if (!callInfo.init(current, 0))
         return abort(AbortReason::Alloc);
 
     if (commonGetter->isNative()) {
         InliningStatus status;
         MOZ_TRY_VAR(status, inlineNativeGetter(callInfo, commonGetter));
         switch (status) {
           case InliningStatus_WarmUpCountTooLow:
@@ -11370,17 +11381,18 @@ IonBuilder::setPropTryCommonSetter(bool*
         return abort(AbortReason::Alloc);
 
     current->push(constant(ObjectValue(*commonSetter)));
     current->push(obj);
     current->push(value);
 
     // Call the setter. Note that we have to push the original value, not
     // the setter's return value.
-    CallInfo callInfo(alloc(), false);
+    CallInfo callInfo(alloc(), /* constructing = */ false,
+                      /* ignoresReturnValue = */ BytecodeIsPopped(pc));
     if (!callInfo.init(current, 1))
         return abort(AbortReason::Alloc);
 
     // Ensure that we know we are calling a setter in case we inline it.
     callInfo.markAsSetter();
 
     // Inline the setter if we can.
     if (commonSetter->isInterpreted()) {
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -499,17 +499,17 @@ class IonBuilder
     AbortReasonOr<Ok> jsop_notearg();
     AbortReasonOr<Ok> jsop_throwsetconst();
     AbortReasonOr<Ok> jsop_checklexical();
     AbortReasonOr<Ok> jsop_checkaliasedlexical(EnvironmentCoordinate ec);
     AbortReasonOr<Ok> jsop_funcall(uint32_t argc);
     AbortReasonOr<Ok> jsop_funapply(uint32_t argc);
     AbortReasonOr<Ok> jsop_funapplyarguments(uint32_t argc);
     AbortReasonOr<Ok> jsop_funapplyarray(uint32_t argc);
-    AbortReasonOr<Ok> jsop_call(uint32_t argc, bool constructing);
+    AbortReasonOr<Ok> jsop_call(uint32_t argc, bool constructing, bool ignoresReturnValue);
     AbortReasonOr<Ok> jsop_eval(uint32_t argc);
     AbortReasonOr<Ok> jsop_label();
     AbortReasonOr<Ok> jsop_andor(JSOp op);
     AbortReasonOr<Ok> jsop_dup2();
     AbortReasonOr<Ok> jsop_loophead(jsbytecode* pc);
     AbortReasonOr<Ok> jsop_compare(JSOp op);
     AbortReasonOr<Ok> jsop_compare(JSOp op, MDefinition* left, MDefinition* right);
     AbortReasonOr<Ok> getStaticName(bool* emitted, JSObject* staticObject, PropertyName* name,
@@ -622,17 +622,16 @@ class IonBuilder
 
     // Array natives.
     InliningResult inlineArray(CallInfo& callInfo);
     InliningResult inlineArrayIsArray(CallInfo& callInfo);
     InliningResult inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode);
     InliningResult inlineArrayPush(CallInfo& callInfo);
     InliningResult inlineArraySlice(CallInfo& callInfo);
     InliningResult inlineArrayJoin(CallInfo& callInfo);
-    InliningResult inlineArraySplice(CallInfo& callInfo);
 
     // Math natives.
     InliningResult inlineMathAbs(CallInfo& callInfo);
     InliningResult inlineMathFloor(CallInfo& callInfo);
     InliningResult inlineMathCeil(CallInfo& callInfo);
     InliningResult inlineMathClz32(CallInfo& callInfo);
     InliningResult inlineMathRound(CallInfo& callInfo);
     InliningResult inlineMathSqrt(CallInfo& callInfo);
@@ -1172,34 +1171,40 @@ class IonBuilder
 
 class CallInfo
 {
     MDefinition* fun_;
     MDefinition* thisArg_;
     MDefinition* newTargetArg_;
     MDefinitionVector args_;
 
-    bool constructing_;
-    bool setter_;
+    bool constructing_:1;
+
+    // True if the caller does not use the return value.
+    bool ignoresReturnValue_:1;
+
+    bool setter_:1;
 
   public:
-    CallInfo(TempAllocator& alloc, bool constructing)
+    CallInfo(TempAllocator& alloc, bool constructing, bool ignoresReturnValue)
       : fun_(nullptr),
         thisArg_(nullptr),
         newTargetArg_(nullptr),
         args_(alloc),
         constructing_(constructing),
+        ignoresReturnValue_(ignoresReturnValue),
         setter_(false)
     { }
 
     MOZ_MUST_USE bool init(CallInfo& callInfo) {
         MOZ_ASSERT(constructing_ == callInfo.constructing());
 
         fun_ = callInfo.fun();
         thisArg_ = callInfo.thisArg();
+        ignoresReturnValue_ = callInfo.ignoresReturnValue();
 
         if (constructing())
             newTargetArg_ = callInfo.getNewTarget();
 
         if (!args_.appendAll(callInfo.argv()))
             return false;
 
         return true;
@@ -1286,16 +1291,20 @@ class CallInfo
     void setThis(MDefinition* thisArg) {
         thisArg_ = thisArg;
     }
 
     bool constructing() const {
         return constructing_;
     }
 
+    bool ignoresReturnValue() const {
+        return ignoresReturnValue_;
+    }
+
     void setNewTarget(MDefinition* newTarget) {
         MOZ_ASSERT(constructing());
         newTargetArg_ = newTarget;
     }
     MDefinition* getNewTarget() const {
         MOZ_ASSERT(newTargetArg_);
         return newTargetArg_;
     }
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -651,26 +651,16 @@ LIRGenerator::visitAssertFloat32(MAssert
 
 void
 LIRGenerator::visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* assertion)
 {
     MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
 }
 
 void
-LIRGenerator::visitArraySplice(MArraySplice* ins)
-{
-    LArraySplice* lir = new(alloc()) LArraySplice(useRegisterAtStart(ins->object()),
-                                                  useRegisterAtStart(ins->start()),
-                                                  useRegisterAtStart(ins->deleteCount()));
-    add(lir, ins);
-    assignSafepoint(lir, ins);
-}
-
-void
 LIRGenerator::visitGetDynamicName(MGetDynamicName* ins)
 {
     MDefinition* envChain = ins->getEnvironmentChain();
     MOZ_ASSERT(envChain->type() == MIRType::Object);
 
     MDefinition* name = ins->getName();
     MOZ_ASSERT(name->type() == MIRType::String);
 
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -102,17 +102,16 @@ class LIRGenerator : public LIRGenerator
     void visitCreateArgumentsObject(MCreateArgumentsObject* ins);
     void visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins);
     void visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins);
     void visitReturnFromCtor(MReturnFromCtor* ins);
     void visitComputeThis(MComputeThis* ins);
     void visitCall(MCall* call);
     void visitApplyArgs(MApplyArgs* apply);
     void visitApplyArray(MApplyArray* apply);
-    void visitArraySplice(MArraySplice* splice);
     void visitBail(MBail* bail);
     void visitUnreachable(MUnreachable* unreachable);
     void visitEncodeSnapshot(MEncodeSnapshot* ins);
     void visitAssertFloat32(MAssertFloat32* ins);
     void visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* ins);
     void visitGetDynamicName(MGetDynamicName* ins);
     void visitCallDirectEval(MCallDirectEval* ins);
     void visitTest(MTest* test);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -82,18 +82,16 @@ IonBuilder::inlineNativeCall(CallInfo& c
       case InlinableNative::ArrayPop:
         return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
       case InlinableNative::ArrayShift:
         return inlineArrayPopShift(callInfo, MArrayPopShift::Shift);
       case InlinableNative::ArrayPush:
         return inlineArrayPush(callInfo);
       case InlinableNative::ArraySlice:
         return inlineArraySlice(callInfo);
-      case InlinableNative::ArraySplice:
-        return inlineArraySplice(callInfo);
 
       // Atomic natives.
       case InlinableNative::AtomicsCompareExchange:
         return inlineAtomicsCompareExchange(callInfo);
       case InlinableNative::AtomicsExchange:
         return inlineAtomicsExchange(callInfo);
       case InlinableNative::AtomicsLoad:
         return inlineAtomicsLoad(callInfo);
@@ -663,55 +661,16 @@ IonBuilder::inlineArrayPopShift(CallInfo
     ins->setResultType(returnType);
 
     MOZ_TRY(resumeAfter(ins));
     MOZ_TRY(pushTypeBarrier(ins, returnTypes, barrier));
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningResult
-IonBuilder::inlineArraySplice(CallInfo& callInfo)
-{
-    if (callInfo.argc() != 2 || callInfo.constructing()) {
-        trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
-        return InliningStatus_NotInlined;
-    }
-
-    // Ensure |this|, argument and result are objects.
-    if (getInlineReturnType() != MIRType::Object)
-        return InliningStatus_NotInlined;
-    if (callInfo.thisArg()->type() != MIRType::Object)
-        return InliningStatus_NotInlined;
-    if (callInfo.getArg(0)->type() != MIRType::Int32)
-        return InliningStatus_NotInlined;
-    if (callInfo.getArg(1)->type() != MIRType::Int32)
-        return InliningStatus_NotInlined;
-
-    callInfo.setImplicitlyUsedUnchecked();
-
-    // Specialize arr.splice(start, deleteCount) with unused return value and
-    // avoid creating the result array in this case.
-    if (!BytecodeIsPopped(pc)) {
-        trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
-        return InliningStatus_NotInlined;
-    }
-
-    MArraySplice* ins = MArraySplice::New(alloc(),
-                                          callInfo.thisArg(),
-                                          callInfo.getArg(0),
-                                          callInfo.getArg(1));
-
-    current->add(ins);
-    pushConstant(UndefinedValue());
-
-    MOZ_TRY(resumeAfter(ins));
-    return InliningStatus_Inlined;
-}
-
-IonBuilder::InliningResult
 IonBuilder::inlineArrayJoin(CallInfo& callInfo)
 {
     if (callInfo.argc() != 1 || callInfo.constructing()) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
         return InliningStatus_NotInlined;
     }
 
     if (getInlineReturnType() != MIRType::String)
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -1971,26 +1971,26 @@ WrappedFunction::WrappedFunction(JSFunct
     isNative_(fun->isNative()),
     isConstructor_(fun->isConstructor()),
     isClassConstructor_(fun->isClassConstructor()),
     isSelfHostedBuiltin_(fun->isSelfHostedBuiltin())
 {}
 
 MCall*
 MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
-           bool construct, bool isDOMCall)
+           bool construct, bool ignoresReturnValue, bool isDOMCall)
 {
     WrappedFunction* wrappedTarget = target ? new(alloc) WrappedFunction(target) : nullptr;
     MOZ_ASSERT(maxArgc >= numActualArgs);
     MCall* ins;
     if (isDOMCall) {
         MOZ_ASSERT(!construct);
         ins = new(alloc) MCallDOMNative(wrappedTarget, numActualArgs);
     } else {
-        ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct);
+        ins = new(alloc) MCall(wrappedTarget, numActualArgs, construct, ignoresReturnValue);
     }
     if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
         return nullptr;
     return ins;
 }
 
 AliasSet
 MCallDOMNative::getAliasSet() const
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4076,33 +4076,37 @@ class MCall
   protected:
     // Monomorphic cache of single target from TI, or nullptr.
     WrappedFunction* target_;
 
     // Original value of argc from the bytecode.
     uint32_t numActualArgs_;
 
     // True if the call is for JSOP_NEW.
-    bool construct_;
-
-    bool needsArgCheck_;
-
-    MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct)
+    bool construct_:1;
+
+    // True if the caller does not use the return value.
+    bool ignoresReturnValue_:1;
+
+    bool needsArgCheck_:1;
+
+    MCall(WrappedFunction* target, uint32_t numActualArgs, bool construct, bool ignoresReturnValue)
       : target_(target),
         numActualArgs_(numActualArgs),
         construct_(construct),
+        ignoresReturnValue_(ignoresReturnValue),
         needsArgCheck_(true)
     {
         setResultType(MIRType::Value);
     }
 
   public:
     INSTRUCTION_HEADER(Call)
     static MCall* New(TempAllocator& alloc, JSFunction* target, size_t maxArgc, size_t numActualArgs,
-                      bool construct, bool isDOMCall);
+                      bool construct, bool ignoresReturnValue, bool isDOMCall);
 
     void initFunction(MDefinition* func) {
         initOperand(FunctionOperandIndex, func);
     }
 
     bool needsArgCheck() const {
         return needsArgCheck_;
     }
@@ -4137,16 +4141,20 @@ class MCall
     WrappedFunction* getSingleTarget() const {
         return target_;
     }
 
     bool isConstructing() const {
         return construct_;
     }
 
+    bool ignoresReturnValue() const {
+        return ignoresReturnValue_;
+    }
+
     // The number of stack arguments is the max between the number of formal
     // arguments and the number of actual arguments. The number of stack
     // argument includes the |undefined| padding added in case of underflow.
     // Includes |this|.
     uint32_t numStackArgs() const {
         return numOperands() - NumNonArgumentOperands;
     }
 
@@ -4180,67 +4188,47 @@ class MCall
 class MCallDOMNative : public MCall
 {
     // A helper class for MCalls for DOM natives.  Note that this is NOT
     // actually a separate MIR op from MCall, because all sorts of places use
     // isCall() to check for calls and all we really want is to overload a few
     // virtual things from MCall.
   protected:
     MCallDOMNative(WrappedFunction* target, uint32_t numActualArgs)
-        : MCall(target, numActualArgs, false)
+        : MCall(target, numActualArgs, false, false)
     {
         MOZ_ASSERT(getJitInfo()->type() != JSJitInfo::InlinableNative);
 
         // If our jitinfo is not marked eliminatable, that means that our C++
         // implementation is fallible or that it never wants to be eliminated or
         // that we have no hope of ever doing the sort of argument analysis that
         // would allow us to detemine that we're side-effect-free.  In the
         // latter case we wouldn't get DCEd no matter what, but for the former
         // two cases we have to explicitly say that we can't be DCEd.
         if (!getJitInfo()->isEliminatable)
             setGuard();
     }
 
     friend MCall* MCall::New(TempAllocator& alloc, JSFunction* target, size_t maxArgc,
-                             size_t numActualArgs, bool construct, bool isDOMCall);
+                             size_t numActualArgs, bool construct, bool ignoresReturnValue,
+                             bool isDOMCall);
 
     const JSJitInfo* getJitInfo() const;
   public:
     virtual AliasSet getAliasSet() const override;
 
     virtual bool congruentTo(const MDefinition* ins) const override;
 
     virtual bool isCallDOMNative() const override {
         return true;
     }
 
     virtual void computeMovable() override;
 };
 
-// arr.splice(start, deleteCount) with unused return value.
-class MArraySplice
-  : public MTernaryInstruction,
-    public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data
-{
-  private:
-
-    MArraySplice(MDefinition* object, MDefinition* start, MDefinition* deleteCount)
-      : MTernaryInstruction(object, start, deleteCount)
-    { }
-
-  public:
-    INSTRUCTION_HEADER(ArraySplice)
-    TRIVIAL_NEW_WRAPPERS
-    NAMED_OPERANDS((0, object), (1, start), (2, deleteCount))
-
-    bool possiblyCalls() const override {
-        return true;
-    }
-};
-
 // fun.apply(self, arguments)
 class MApplyArgs
   : public MAryInstruction<3>,
     public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >::Data
 {
   protected:
     // Monomorphic cache of single target from TI, or nullptr.
     WrappedFunction* target_;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -64,17 +64,16 @@ namespace jit {
     _(CreateThisWithTemplate)                                               \
     _(CreateArgumentsObject)                                                \
     _(GetArgumentsObjectArg)                                                \
     _(SetArgumentsObjectArg)                                                \
     _(ComputeThis)                                                          \
     _(Call)                                                                 \
     _(ApplyArgs)                                                            \
     _(ApplyArray)                                                           \
-    _(ArraySplice)                                                          \
     _(Bail)                                                                 \
     _(Unreachable)                                                          \
     _(EncodeSnapshot)                                                       \
     _(AssertFloat32)                                                        \
     _(AssertRecoveredOnBailout)                                             \
     _(GetDynamicName)                                                       \
     _(CallDirectEval)                                                       \
     _(BitNot)                                                               \
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -49,18 +49,18 @@ AutoDetectInvalidation::AutoDetectInvali
 void
 VMFunction::addToFunctions()
 {
     this->next = functions;
     functions = this;
 }
 
 bool
-InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, uint32_t argc, Value* argv,
-               MutableHandleValue rval)
+InvokeFunction(JSContext* cx, HandleObject obj, bool constructing, bool ignoresReturnValue,
+               uint32_t argc, Value* argv, MutableHandleValue rval)
 {
     TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
     TraceLogStartEvent(logger, TraceLogger_Call);
 
     AutoArrayRooter argvRoot(cx, argc + 1 + constructing, argv);
 
     // Data in the argument vector is arranged for a JIT -> JIT call.
     RootedValue thisv(cx, argv[0]);
@@ -99,33 +99,33 @@ InvokeFunction(JSContext* cx, HandleObje
 
         // Otherwise the default |this| has already been created.  We could
         // almost perform a *call* at this point, but we'd break |new.target|
         // in the function.  So in this one weird case we call a one-off
         // construction path that *won't* set |this| to JS_IS_CONSTRUCTING.
         return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget, rval);
     }
 
-    InvokeArgs args(cx);
+    InvokeArgsMaybeIgnoresReturnValue args(cx, ignoresReturnValue);
     if (!args.init(cx, argc))
         return false;
 
     for (size_t i = 0; i < argc; i++)
         args[i].set(argvWithoutThis[i]);
 
     return Call(cx, fval, thisv, args, rval);
 }
 
 bool
 InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
                                uint32_t numFormalArgs, Value* argv, MutableHandleValue rval)
 {
     MOZ_ASSERT(numFormalArgs > numActualArgs);
     argv[1 + numActualArgs] = argv[1 + numFormalArgs];
-    return InvokeFunction(cx, obj, true, numActualArgs, argv, rval);
+    return InvokeFunction(cx, obj, true, false, numActualArgs, argv, rval);
 }
 
 #ifdef JS_SIMULATOR
 static bool
 CheckSimulatorRecursionLimitWithExtra(JSContext* cx, uint32_t extra)
 {
     if (cx->simulator()->overRecursedWithExtra(extra)) {
         ReportOverRecursed(cx);
@@ -319,28 +319,16 @@ StringsEqual(JSContext* cx, HandleString
         *res = !*res;
     return true;
 }
 
 template bool StringsEqual<true>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
 template bool StringsEqual<false>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
 
 bool
-ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount)
-{
-    JS::AutoValueArray<4> argv(cx);
-    argv[0].setUndefined();
-    argv[1].setObject(*obj);
-    argv[2].set(Int32Value(start));
-    argv[3].set(Int32Value(deleteCount));
-
-    return js::array_splice_impl(cx, 2, argv.begin(), false);
-}
-
-bool
 ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
 {
     MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
 
     AutoDetectInvalidation adi(cx, rval);
 
     JS::AutoValueArray<2> argv(cx);
     argv[0].setUndefined();
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -597,18 +597,18 @@ class AutoDetectInvalidation
 
     ~AutoDetectInvalidation() {
         if (!disabled_ && ionScript_->invalidated())
             setReturnOverride();
     }
 };
 
 MOZ_MUST_USE bool
-InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, uint32_t argc, Value* argv,
-               MutableHandleValue rval);
+InvokeFunction(JSContext* cx, HandleObject obj0, bool constructing, bool ignoresReturnValue,
+               uint32_t argc, Value* argv, MutableHandleValue rval);
 MOZ_MUST_USE bool
 InvokeFunctionShuffleNewTarget(JSContext* cx, HandleObject obj, uint32_t numActualArgs,
                                uint32_t numFormalArgs, Value* argv, MutableHandleValue rval);
 
 bool CheckOverRecursed(JSContext* cx);
 bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
                                 uint32_t extra, uint32_t earlyCheck);
 
@@ -763,19 +763,16 @@ PopVarEnv(JSContext* cx, BaselineFrame* 
 MOZ_MUST_USE bool
 InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame,
                              uint32_t numStackValues);
 
 JSObject* CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
                                 HandleObject owner, int32_t offset);
 
 MOZ_MUST_USE bool
-ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount);
-
-MOZ_MUST_USE bool
 Recompile(JSContext* cx);
 MOZ_MUST_USE bool
 ForcedRecompile(JSContext* cx);
 JSString* StringReplace(JSContext* cx, HandleString string, HandleString pattern,
                         HandleString repl);
 
 MOZ_MUST_USE bool SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
                                                 HandleValue value, bool strict);
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1905,16 +1905,19 @@ class LJSCallInstructionHelper : public 
     // Does not include |this|.
     uint32_t numActualArgs() const {
         return mir()->numActualArgs();
     }
 
     bool isConstructing() const {
         return mir()->isConstructing();
     }
+    bool ignoresReturnValue() const {
+        return mir()->ignoresReturnValue();
+    }
 };
 
 // Generates a polymorphic callsite, wherein the function being called is
 // unknown and anticipated to vary.
 class LCallGeneric : public LJSCallInstructionHelper<BOX_PIECES, 1, 2>
 {
   public:
     LIR_HEADER(CallGeneric)
@@ -2225,44 +2228,16 @@ class LApplyArrayGeneric : public LCallI
     const LDefinition* getTempObject() {
         return getTemp(0);
     }
     const LDefinition* getTempStackCounter() {
         return getTemp(1);
     }
 };
 
-class LArraySplice : public LCallInstructionHelper<0, 3, 0>
-{
-  public:
-    LIR_HEADER(ArraySplice)
-
-    LArraySplice(const LAllocation& object, const LAllocation& start,
-                 const LAllocation& deleteCount)
-    {
-        setOperand(0, object);
-        setOperand(1, start);
-        setOperand(2, deleteCount);
-    }
-
-    MArraySplice* mir() const {
-        return mir_->toArraySplice();
-    }
-
-    const LAllocation* getObject() {
-        return getOperand(0);
-    }
-    const LAllocation* getStart() {
-        return getOperand(1);
-    }
-    const LAllocation* getDeleteCount() {
-        return getOperand(2);
-    }
-};
-
 class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3>
 {
   public:
     LIR_HEADER(GetDynamicName)
 
     LGetDynamicName(const LAllocation& envChain, const LAllocation& name,
                     const LDefinition& temp1, const LDefinition& temp2, const LDefinition& temp3)
     {
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -64,17 +64,16 @@
     _(TableSwitch)                  \
     _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewArray)                     \
     _(NewArrayCopyOnWrite)          \
     _(NewArrayDynamicLength)        \
     _(NewTypedArray)                \
     _(NewTypedArrayDynamicLength)   \
-    _(ArraySplice)                  \
     _(NewObject)                    \
     _(NewTypedObject)               \
     _(NewNamedLambdaObject)         \
     _(NewCallObject)                \
     _(NewSingletonCallObject)       \
     _(NewStringObject)              \
     _(NewDerivedTypedObject)        \
     _(InitElem)                     \
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2477,23 +2477,16 @@ CanOptimizeForDenseStorage(HandleObject 
      * Now watch out for getters and setters along the prototype chain or in
      * other indexed properties on the object.  (Note that non-writable length
      * is subsumed by the initializedLength comparison.)
      */
     return !ObjectMayHaveExtraIndexedProperties(arr) &&
            startingIndex + count <= GetAnyBoxedOrUnboxedInitializedLength(arr);
 }
 
-/* ES 2016 draft Mar 25, 2016 22.1.3.26. */
-bool
-js::array_splice(JSContext* cx, unsigned argc, Value* vp)
-{
-    return array_splice_impl(cx, argc, vp, true);
-}
-
 static inline bool
 ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj,
                 uint32_t actualStart, uint32_t actualDeleteCount)
 {
     // Steps 10, 11, 11.d.
     RootedValue fromValue(cx);
     for (uint32_t k = 0; k < actualDeleteCount; k++) {
         // Step 11.a (implicit).
@@ -2513,18 +2506,18 @@ ArraySpliceCopy(JSContext* cx, HandleObj
                 return false;
         }
     }
 
     // Step 12.
     return SetLengthProperty(cx, arr, actualDeleteCount);
 }
 
-bool
-js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed)
+static bool
+array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed)
 {
     AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.splice");
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
@@ -2758,16 +2751,29 @@ js::array_splice_impl(JSContext* cx, uns
 
     /* Step 20. */
     if (returnValueIsUsed)
         args.rval().setObject(*arr);
 
     return true;
 }
 
+/* ES 2016 draft Mar 25, 2016 22.1.3.26. */
+bool
+js::array_splice(JSContext* cx, unsigned argc, Value* vp)
+{
+    return array_splice_impl(cx, argc, vp, true);
+}
+
+static bool
+array_splice_noRetVal(JSContext* cx, unsigned argc, Value* vp)
+{
+    return array_splice_impl(cx, argc, vp, false);
+}
+
 struct SortComparatorIndexes
 {
     bool operator()(uint32_t a, uint32_t b, bool* lessOrEqualp) {
         *lessOrEqualp = (a <= b);
         return true;
     }
 };
 
@@ -3172,32 +3178,41 @@ array_of(JSContext* cx, unsigned argc, V
     if (!SetLengthProperty(cx, obj, args.length()))
         return false;
 
     // Step 11.
     args.rval().setObject(*obj);
     return true;
 }
 
+const JSJitInfo js::array_splice_info = {
+  { (JSJitGetterOp)array_splice_noRetVal },
+  { 0 }, /* unused */
+  { 0 }, /* unused */
+  JSJitInfo::IgnoresReturnValueNative,
+  JSJitInfo::AliasEverything,
+  JSVAL_TYPE_UNDEFINED,
+};
+
 static const JSFunctionSpec array_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,      array_toSource,     0,0),
 #endif
     JS_SELF_HOSTED_FN(js_toString_str, "ArrayToString",      0,0),
     JS_FN(js_toLocaleString_str,       array_toLocaleString, 0,0),
 
     /* Perl-ish methods. */
     JS_INLINABLE_FN("join",     array_join,         1,0, ArrayJoin),
     JS_FN("reverse",            array_reverse,      0,0),
     JS_FN("sort",               array_sort,         1,0),
     JS_INLINABLE_FN("push",     array_push,         1,0, ArrayPush),
     JS_INLINABLE_FN("pop",      array_pop,          0,0, ArrayPop),
     JS_INLINABLE_FN("shift",    array_shift,        0,0, ArrayShift),
     JS_FN("unshift",            array_unshift,      1,0),
-    JS_INLINABLE_FN("splice",   array_splice,       2,0, ArraySplice),
+    JS_FNINFO("splice",         array_splice,       &array_splice_info, 2,0),
 
     /* Pythonic sequence methods. */
     JS_SELF_HOSTED_FN("concat",      "ArrayConcat",      1,0),
     JS_INLINABLE_FN("slice",    array_slice,        2,0, ArraySlice),
 
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayLastIndexOf", 1,0),
     JS_SELF_HOSTED_FN("indexOf",     "ArrayIndexOf",     1,0),
     JS_SELF_HOSTED_FN("forEach",     "ArrayForEach",     1,0),
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -161,19 +161,16 @@ array_sort(JSContext* cx, unsigned argc,
 
 extern bool
 array_push(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern bool
 array_pop(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern bool
-array_splice_impl(JSContext* cx, unsigned argc, js::Value* vp, bool pop);
-
-extern bool
 array_join(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern void
 ArrayShiftMoveElements(JSObject* obj);
 
 extern bool
 array_shift(JSContext* cx, unsigned argc, js::Value* vp);
 
@@ -187,16 +184,18 @@ extern JSObject*
 array_slice_dense(JSContext* cx, HandleObject obj, int32_t begin, int32_t end, HandleObject result);
 
 extern bool
 array_reverse(JSContext* cx, unsigned argc, js::Value* vp);
 
 extern bool
 array_splice(JSContext* cx, unsigned argc, js::Value* vp);
 
+extern const JSJitInfo array_splice_info;
+
 /*
  * Append the given (non-hole) value to the end of an array.  The array must be
  * a newborn array -- that is, one which has not been exposed to script for
  * arbitrary manipulation.  (This method optimizes on the assumption that
  * extending the array to accommodate the element will never make the array
  * sparse, which requires that the array be completely filled.)
  */
 extern bool
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2307,16 +2307,17 @@ typedef bool
  */
 struct JSJitInfo {
     enum OpType {
         Getter,
         Setter,
         Method,
         StaticMethod,
         InlinableNative,
+        IgnoresReturnValueNative,
         // Must be last
         OpTypeCount
     };
 
     enum ArgType {
         // Basic types
         String = (1 << 0),
         Integer = (1 << 1), // Only 32-bit or less
@@ -2398,18 +2399,23 @@ struct JSJitInfo {
     }
 
     union {
         JSJitGetterOp getter;
         JSJitSetterOp setter;
         JSJitMethodOp method;
         /** A DOM static method, used for Promise wrappers */
         JSNative staticMethod;
+        JSNative ignoresReturnValueMethod;
     };
 
+    static unsigned offsetOfIgnoresReturnValueNative() {
+        return offsetof(JSJitInfo, ignoresReturnValueMethod);
+    }
+
     union {
         uint16_t protoID;
         js::jit::InlinableNative inlinableNative;
     };
 
     union {
         uint16_t depth;
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -567,16 +567,20 @@ class JSFunction : public js::NativeObje
                       "for offsetOfNativeOrScript() have any sense");
         static_assert(offsetof(U, n.native) == offsetof(U, nativeOrScript),
                       "U::nativeOrScript must be at the same offset as "
                       "native");
 
         return offsetof(JSFunction, u.nativeOrScript);
     }
 
+    static unsigned offsetOfJitInfo() {
+        return offsetof(JSFunction, u.n.jitinfo);
+    }
+
     inline void trace(JSTracer* trc);
 
     /* Bound function accessors. */
 
     JSObject* getBoundFunctionTarget() const;
     const js::Value& getBoundFunctionThis() const;
     const js::Value& getBoundFunctionArgument(unsigned which) const;
     size_t getBoundFunctionArgumentCount() const;
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -128,17 +128,18 @@ js::StackUses(JSScript* script, jsbyteco
     switch (op) {
       case JSOP_POPN:
         return GET_UINT16(pc);
       case JSOP_NEW:
       case JSOP_SUPERCALL:
         return 2 + GET_ARGC(pc) + 1;
       default:
         /* stack: fun, this, [argc arguments] */
-        MOZ_ASSERT(op == JSOP_CALL || op == JSOP_EVAL || op == JSOP_CALLITER ||
+        MOZ_ASSERT(op == JSOP_CALL || op == JSOP_CALL_IGNORES_RV || op == JSOP_EVAL ||
+                   op == JSOP_CALLITER ||
                    op == JSOP_STRICTEVAL || op == JSOP_FUNCALL || op == JSOP_FUNAPPLY);
         return 2 + GET_ARGC(pc);
     }
 }
 
 unsigned
 js::StackDefs(JSScript* script, jsbytecode* pc)
 {
@@ -1868,16 +1869,17 @@ ExpressionDecompiler::decompilePC(jsbyte
         return write(js_undefined_str);
       case JSOP_GLOBALTHIS:
         // |this| could convert to a very long object initialiser, so cite it by
         // its keyword name.
         return write(js_this_str);
       case JSOP_NEWTARGET:
         return write("new.target");
       case JSOP_CALL:
+      case JSOP_CALL_IGNORES_RV:
       case JSOP_CALLITER:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
         return decompilePCForStackOperand(pc, -int32_t(GET_ARGC(pc) + 2)) &&
                write("(...)");
       case JSOP_SPREADCALL:
         return decompilePCForStackOperand(pc, -3) &&
                write("(...)");
@@ -2389,17 +2391,17 @@ DecompileArgumentFromStack(JSContext* cx
 
     MOZ_ASSERT(script->containsPC(current));
 
     if (current < script->main())
         return true;
 
     /* Don't handle getters, setters or calls from fun.call/fun.apply. */
     JSOp op = JSOp(*current);
-    if (op != JSOP_CALL && op != JSOP_NEW)
+    if (op != JSOP_CALL && op != JSOP_CALL_IGNORES_RV && op != JSOP_NEW)
         return true;
 
     if (static_cast<unsigned>(formalIndex) >= GET_ARGC(current))
         return true;
 
     BytecodeParser parser(cx, script);
     if (!parser.parse())
         return false;
@@ -2452,16 +2454,18 @@ js::CallResultEscapes(jsbytecode* pc)
      *
      * If we see any of these sequences, the result is only tested for nullness:
      * - call / ifeq
      * - call / not / ifeq
      */
 
     if (*pc == JSOP_CALL)
         pc += JSOP_CALL_LENGTH;
+    else if (*pc == JSOP_CALL_IGNORES_RV)
+        pc += JSOP_CALL_IGNORES_RV_LENGTH;
     else if (*pc == JSOP_SPREADCALL)
         pc += JSOP_SPREADCALL_LENGTH;
     else
         return true;
 
     if (*pc == JSOP_POP)
         return false;
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -440,17 +440,23 @@ js::InternalCallOrConstruct(JSContext* c
     RootedFunction fun(cx, &args.callee().as<JSFunction>());
     if (construct != CONSTRUCT && fun->isClassConstructor()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
         return false;
     }
 
     if (fun->isNative()) {
         MOZ_ASSERT_IF(construct, !fun->isConstructor());
-        return CallJSNative(cx, fun->native(), args);
+        JSNative native = fun->native();
+        if (!construct && args.ignoresReturnValue()) {
+            const JSJitInfo* jitInfo = fun->jitInfo();
+            if (jitInfo && jitInfo->type() == JSJitInfo::IgnoresReturnValueNative)
+                native = jitInfo->ignoresReturnValueMethod;
+        }
+        return CallJSNative(cx, native, args);
     }
 
     if (!JSFunction::getOrCreateScript(cx, fun))
         return false;
 
     /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */
     InvokeState state(cx, args, construct);
 
@@ -2917,28 +2923,30 @@ CASE(JSOP_FUNAPPLY)
     CallArgs args = CallArgsFromSp(GET_ARGC(REGS.pc), REGS.sp);
     if (!GuardFunApplyArgumentsOptimization(cx, REGS.fp(), args))
         goto error;
     /* FALL THROUGH */
 }
 
 CASE(JSOP_NEW)
 CASE(JSOP_CALL)
+CASE(JSOP_CALL_IGNORES_RV)
 CASE(JSOP_CALLITER)
 CASE(JSOP_SUPERCALL)
 CASE(JSOP_FUNCALL)
 {
     if (REGS.fp()->hasPushedGeckoProfilerFrame())
         cx->runtime()->geckoProfiler().updatePC(script, REGS.pc);
 
     MaybeConstruct construct = MaybeConstruct(*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
+    bool ignoresReturnValue = *REGS.pc == JSOP_CALL_IGNORES_RV;
     unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
 
     MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
-    CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct);
+    CallArgs args = CallArgsFromSp(argStackSlots, REGS.sp, construct, ignoresReturnValue);
 
     JSFunction* maybeFun;
     bool isFunction = IsFunctionObject(args.calleev(), &maybeFun);
 
     /* Don't bother trying to fast-path calls to scripted non-constructors. */
     if (!isFunction || !maybeFun->isInterpreted() || !maybeFun->isConstructor() ||
         (!construct && maybeFun->isClassConstructor()))
     {
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -2292,24 +2292,33 @@ 1234567890123456789012345678901234567890
      * This opcode is a no-op and it indicates the location of a jump
      * instruction target. Some other opcodes act as jump targets, such as
      * LOOPENTRY, as well as all which are matched by BytecodeIsJumpTarget
      * function.
      *   Category: Other
      *   Operands:
      *   Stack: =>
      */ \
-    macro(JSOP_JUMPTARGET,  230, "jumptarget",     NULL,  1,  0,  0,  JOF_BYTE)
+    macro(JSOP_JUMPTARGET,  230, "jumptarget",     NULL,  1,  0,  0,  JOF_BYTE)\
+    /*
+     * Like JSOP_CALL, but tells the function that the return value is ignored.
+     * stack.
+     *   Category: Statements
+     *   Type: Function
+     *   Operands: uint16_t argc
+     *   Stack: callee, this, args[0], ..., args[argc-1] => rval
+     *   nuses: (argc+2)
+     */ \
+    macro(JSOP_CALL_IGNORES_RV, 231, "call-ignores-rv", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 /*
  * In certain circumstances it may be useful to "pad out" the opcode space to
  * a power of two.  Use this macro to do so.
  */
 #define FOR_EACH_TRAILING_UNUSED_OPCODE(macro) \
-    macro(231) \
     macro(232) \
     macro(233) \
     macro(234) \
     macro(235) \
     macro(236) \
     macro(237) \
     macro(238) \
     macro(239) \
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2301,17 +2301,17 @@ static const JSFunctionSpec intrinsic_fu
     JS_FN("std_Array_join",                      array_join,                   1,0),
     JS_INLINABLE_FN("std_Array_push",            array_push,                   1,0, ArrayPush),
     JS_INLINABLE_FN("std_Array_pop",             array_pop,                    0,0, ArrayPop),
     JS_INLINABLE_FN("std_Array_shift",           array_shift,                  0,0, ArrayShift),
     JS_FN("std_Array_unshift",                   array_unshift,                1,0),
     JS_INLINABLE_FN("std_Array_slice",           array_slice,                  2,0, ArraySlice),
     JS_FN("std_Array_sort",                      array_sort,                   1,0),
     JS_FN("std_Array_reverse",                   array_reverse,                0,0),
-    JS_INLINABLE_FN("std_Array_splice",          array_splice,                 2,0, ArraySplice),
+    JS_FNINFO("std_Array_splice",                array_splice, &array_splice_info, 2,0),
 
     JS_FN("std_Date_now",                        date_now,                     0,0),
     JS_FN("std_Date_valueOf",                    date_valueOf,                 0,0),
 
     JS_FN("std_Function_apply",                  fun_apply,                    2,0),
 
     JS_INLINABLE_FN("std_Math_floor",            math_floor,                   1,0, MathFloor),
     JS_INLINABLE_FN("std_Math_max",              math_max,                     2,0, MathMax),
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1040,16 +1040,27 @@ class FixedArgsBase
 class InvokeArgs : public detail::GenericArgsBase<NO_CONSTRUCT>
 {
     using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
 
   public:
     explicit InvokeArgs(JSContext* cx) : Base(cx) {}
 };
 
+/** Function call args of statically-unknown count. */
+class InvokeArgsMaybeIgnoresReturnValue : public detail::GenericArgsBase<NO_CONSTRUCT>
+{
+    using Base = detail::GenericArgsBase<NO_CONSTRUCT>;
+
+  public:
+    explicit InvokeArgsMaybeIgnoresReturnValue(JSContext* cx, bool ignoresReturnValue) : Base(cx) {
+        this->ignoresReturnValue_ = ignoresReturnValue;
+    }
+};
+
 /** Function call args of statically-known count. */
 template <size_t N>
 class FixedInvokeArgs : public detail::FixedArgsBase<NO_CONSTRUCT, N>
 {
     using Base = detail::FixedArgsBase<NO_CONSTRUCT, N>;
 
   public:
     explicit FixedInvokeArgs(JSContext* cx) : Base(cx) {}
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3604,17 +3604,19 @@ ScrollFrameHelper::DecideScrollableLayer
       } else {
         // Make the displayport base equal to the dirty rect restricted to
         // the scrollport and the root composition bounds, relative to the
         // scrollport.
         displayportBase = aDirtyRect->Intersect(mScrollPort);
 
         // Only restrict to the root composition bounds if necessary,
         // as the required coordinate transformation is expensive.
-        if (wasUsingDisplayPort) {
+        // Note that we call HasDisplayPort again instead of using
+        // wasUsingDisplayPort because we might have just created a display port.
+        if (nsLayoutUtils::HasDisplayPort(content)) {
           const nsPresContext* rootPresContext =
             pc->GetToplevelContentDocumentPresContext();
           if (!rootPresContext) {
             rootPresContext = pc->GetRootPresContext();
           }
           if (rootPresContext) {
             const nsIPresShell* const rootPresShell = rootPresContext->PresShell();
             nsIFrame* rootFrame = rootPresShell->GetRootScrollFrame();