Merge mozilla-central to autoland. a=merge CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Fri, 19 Jan 2018 12:15:59 +0200
changeset 454320 d502a8e0691ec8de2819d4c51f3b6d2ad7459f9b
parent 454319 db4cf9d2c11d38c6be1c3dc8697a3912c0315e29 (current diff)
parent 454280 6ffbba9ce0ef9ec77a63445f068f2e218ed4830f (diff)
child 454321 332f7a69835390b8918f2de7d0e2c5e799ad24fa
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
docshell/base/nsIContentViewerContainer.idl
--- a/browser/extensions/shield-recipe-client/lib/ShieldPreferences.jsm
+++ b/browser/extensions/shield-recipe-client/lib/ShieldPreferences.jsm
@@ -116,29 +116,24 @@ this.ShieldPreferences = {
     const viewStudies = doc.createElementNS(XUL_NS, "label");
     viewStudies.setAttribute("id", "viewShieldStudies");
     viewStudies.setAttribute("href", "about:studies");
     viewStudies.setAttribute("useoriginprincipal", true);
     viewStudies.textContent = "View Firefox Studies";
     viewStudies.classList.add("learnMore", "text-link");
     hContainer.appendChild(viewStudies);
 
-    const optOutPref = doc.createElementNS(XUL_NS, "preference");
-    optOutPref.setAttribute("id", OPT_OUT_STUDIES_ENABLED_PREF);
-    optOutPref.setAttribute("name", OPT_OUT_STUDIES_ENABLED_PREF);
-    optOutPref.setAttribute("type", "bool");
-
     // Preference instances for prefs that we need to monitor while the page is open.
     doc.defaultView.Preferences.add({ id: OPT_OUT_STUDIES_ENABLED_PREF, type: "bool" });
 
-    // Weirdly, FHR doesn't have a <preference> element on the page, so we create it.
+    // Weirdly, FHR doesn't have a Preference instance on the page, so we create it.
     const fhrPref = doc.defaultView.Preferences.add({ id: FHR_UPLOAD_ENABLED_PREF, type: "bool" });
-    fhrPref.on("change", function(event) {
-      // Avoid reference to the document directly, to avoid leaks.
-      const eventTargetCheckbox = event.target.ownerDocument.getElementById("optOutStudiesEnabled");
-      eventTargetCheckbox.disabled = !Services.prefs.getBoolPref(FHR_UPLOAD_ENABLED_PREF);
-    });
+    function onChangeFHRPref(event) {
+      checkbox.disabled = !Services.prefs.getBoolPref(FHR_UPLOAD_ENABLED_PREF);
+    }
+    fhrPref.on("change", onChangeFHRPref);
+    doc.defaultView.addEventListener("unload", () => fhrPref.off("change", onChangeFHRPref), { once: true });
 
     // Actually inject the elements we've created.
     const parent = doc.getElementById("submitHealthReportBox").closest("description");
     parent.appendChild(container);
   },
 };
--- a/browser/extensions/shield-recipe-client/test/browser/browser_about_preferences.js
+++ b/browser/extensions/shield-recipe-client/test/browser/browser_about_preferences.js
@@ -166,14 +166,16 @@ decorate_task(
 
 decorate_task(
   withPrivacyPrefs,
   async function testViewStudiesLink(browser) {
     browser.contentDocument.getElementById("viewShieldStudies").click();
     await BrowserTestUtils.waitForLocationChange(gBrowser);
 
     is(
-      browser.currentURI.spec,
+      gBrowser.currentURI.spec,
       "about:studies",
-      "Clicking the view studies link opens about:studies."
+      "Clicking the view studies link opens about:studies in a new tab."
     );
+
+    gBrowser.removeCurrentTab();
   }
 );
--- a/docshell/base/moz.build
+++ b/docshell/base/moz.build
@@ -34,17 +34,16 @@ with Files('nsIScrollObserver.*'):
 DIRS += [
     'timeline',
 ]
 
 XPIDL_SOURCES += [
     'nsCDefaultURIFixup.idl',
     'nsIClipboardCommands.idl',
     'nsIContentViewer.idl',
-    'nsIContentViewerContainer.idl',
     'nsIContentViewerEdit.idl',
     'nsIDocCharset.idl',
     'nsIDocShell.idl',
     'nsIDocShellLoadInfo.idl',
     'nsIDocShellTreeItem.idl',
     'nsIDocShellTreeOwner.idl',
     'nsIDocumentLoaderFactory.idl',
     'nsIDownloadHistory.idl',
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -508,17 +508,16 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
   NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
   NS_INTERFACE_MAP_ENTRY(nsIScrollable)
   NS_INTERFACE_MAP_ENTRY(nsITextScroll)
   NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
   NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
   NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
   NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
   NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
   NS_INTERFACE_MAP_ENTRY(nsILoadContext)
   NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
   NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
   NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
   NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController)
@@ -6851,21 +6850,17 @@ nsDocShell::RefreshURIFromQueue()
         }
       }
     }
   }
 
   return NS_OK;
 }
 
-//*****************************************************************************
-// nsDocShell::nsIContentViewerContainer
-//*****************************************************************************
-
-NS_IMETHODIMP
+nsresult
 nsDocShell::Embed(nsIContentViewer* aContentViewer,
                   const char* aCommand, nsISupports* aExtraInfo)
 {
   // Save the LayoutHistoryState of the previous document, before
   // setting up new document
   PersistLayoutHistoryState();
 
   nsresult rv = SetupNewViewer(aContentViewer);
@@ -6918,22 +6913,16 @@ nsDocShell::Embed(nsIContentViewer* aCon
 
   if (!updateHistory) {
     SetLayoutHistoryState(nullptr);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDocShell::SetIsPrinting(bool aIsPrinting)
-{
-  mIsPrintingOrPP = aIsPrinting;
-  return NS_OK;
-}
 
 //*****************************************************************************
 // nsDocShell::nsIWebProgressListener
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsDocShell::OnProgressChange(nsIWebProgress* aProgress,
                              nsIRequest* aRequest,
@@ -13853,16 +13842,23 @@ nsDocShell::StopDocumentLoad(void)
     Stop(nsIWebNavigation::STOP_ALL);
     return NS_OK;
   }
   // return failer if this request is not accepted due to mCharsetReloadState
   return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
 }
 
 NS_IMETHODIMP
+nsDocShell::SetIsPrinting(bool aIsPrinting)
+{
+  mIsPrintingOrPP = aIsPrinting;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
 {
   *aPrintPreview = nullptr;
 #if NS_PRINT_PREVIEW
   nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
   if (!print || !print->IsInitializedForPrintPreview()) {
     // XXX: Creating a brand new content viewer to host preview every
     // time we enter here seems overwork. We could skip ahead to where
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -15,17 +15,16 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 
 #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
 
 #include "nsIAuthPromptProvider.h"
 #include "nsIBaseWindow.h"
 #include "nsIClipboardCommands.h"
-#include "nsIContentViewerContainer.h"
 #include "nsIDeprecationWarner.h"
 #include "nsIDocCharset.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDOMStorageManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsILinkHandler.h"
@@ -122,17 +121,16 @@ enum eCharsetReloadState
 class nsDocShell final
   : public nsDocLoader
   , public nsIDocShell
   , public nsIWebNavigation
   , public nsIBaseWindow
   , public nsIScrollable
   , public nsITextScroll
   , public nsIDocCharset
-  , public nsIContentViewerContainer
   , public nsIRefreshURI
   , public nsIWebProgressListener
   , public nsIWebPageDescriptor
   , public nsIAuthPromptProvider
   , public nsILoadContext
   , public nsIWebShellServices
   , public nsILinkHandler
   , public nsIClipboardCommands
@@ -178,17 +176,16 @@ public:
   NS_DECL_NSIWEBNAVIGATION
   NS_DECL_NSIBASEWINDOW
   NS_DECL_NSISCROLLABLE
   NS_DECL_NSITEXTSCROLL
   NS_DECL_NSIDOCCHARSET
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIWEBPROGRESSLISTENER
   NS_DECL_NSIREFRESHURI
-  NS_DECL_NSICONTENTVIEWERCONTAINER
   NS_DECL_NSIWEBPAGEDESCRIPTOR
   NS_DECL_NSIAUTHPROMPTPROVIDER
   NS_DECL_NSICLIPBOARDCOMMANDS
   NS_DECL_NSIWEBSHELLSERVICES
   NS_DECL_NSINETWORKINTERCEPTCONTROLLER
   NS_DECL_NSIDEPRECATIONWARNER
 
   NS_FORWARD_SAFE_NSIDOMSTORAGEMANAGER(TopSessionStorageManager())
@@ -864,16 +861,18 @@ private: // member functions
   nsIDOMStorageManager* TopSessionStorageManager();
   nsIChannel* GetCurrentDocChannel();
   nsresult EnsureScriptEnvironment();
   nsresult EnsureEditorData();
   nsresult EnsureTransferableHookData();
   nsresult EnsureFind();
   nsresult EnsureCommandHandler();
   nsresult RefreshURIFromQueue();
+  nsresult Embed(nsIContentViewer* aContentViewer,
+                 const char* aCommand, nsISupports* aExtraInfo);
   nsresult GetEldestPresContext(nsPresContext** aPresContext);
   nsresult CheckLoadingPermissions();
   nsresult PersistLayoutHistoryState();
   nsresult LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType);
   nsresult SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer);
   nsresult GetRootSessionHistory(nsISHistory** aReturn);
   nsresult GetHttpChannel(nsIChannel* aChannel, nsIHttpChannel** aReturn);
   nsresult ConfirmRepost(bool* aRepost);
deleted file mode 100644
--- a/docshell/base/nsIContentViewerContainer.idl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * 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 "nsISupports.idl"
-
-interface nsIContentViewer;
-
-[scriptable, uuid(ea2ce7a0-5c3d-11d4-90c2-0050041caf44)]
-interface nsIContentViewerContainer : nsISupports {
-	void embed(in nsIContentViewer aDocViewer, in string aCommand, in nsISupports aExtraInfo);
-
-  /**
-   * Allows nsPrintJob to make this call on an internal interface to the
-   * DocShell.
-   */
-  void setIsPrinting(in boolean aIsPrinting);
-};
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -651,16 +651,22 @@ interface nsIDocShell : nsIDocShellTreeI
   /**
    * If true, this browser is not visible in the traditional sense, but
    * is actively being rendered to the screen (ex. painted on a canvas)
    * and should be treated accordingly.
    **/
   attribute boolean isOffScreenBrowser;
 
   /**
+   * Allows nsDocumentViewer to tell the top-level same-type docshell that
+   * one of the documents under it is printing.
+   */
+  void setIsPrinting(in boolean aIsPrinting);
+
+  /**
    * If the current content viewer isn't initialized for print preview,
    * it is replaced with one which is and to which an about:blank document
    * is loaded.
    */
   readonly attribute nsIWebBrowserPrint printPreview;
 
   /**
    * Whether this docshell can execute scripts based on its hierarchy.
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -27,17 +27,16 @@
 #include "nsIDOMElement.h"
 #include "nsPIDOMWindow.h"
 #include "nsDOMString.h"
 #include "nsIStreamListener.h"
 #include "nsIURI.h"
 #include "nsIIOService.h"
 #include "nsNetUtil.h"
 #include "nsIPrivateBrowsingChannel.h"
-#include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsDocShell.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsIWebNavigation.h"
 #include "nsIBaseWindow.h"
 #include "nsIWebShellServices.h"
 #include "nsIScriptContext.h"
 #include "nsIXPConnect.h"
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -468,22 +468,16 @@ cubeb* GetCubebContextUnlocked()
     : cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
   sIPCConnection = nullptr;
 #else // !MOZ_CUBEB_REMOTING
   int rv = cubeb_init(&sCubebContext, sBrandName, sCubebBackendName.get());
 #endif // MOZ_CUBEB_REMOTING
   NS_WARNING_ASSERTION(rv == CUBEB_OK, "Could not get a cubeb context.");
   sCubebState = (rv == CUBEB_OK) ? CubebState::Initialized : CubebState::Uninitialized;
 
-  if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
-    cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
-  } else if (MOZ_LOG_TEST(gCubebLog, LogLevel::Error)) {
-    cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
-  }
-
   return sCubebContext;
 }
 
 void ReportCubebBackendUsed()
 {
   StaticMutexAutoLock lock(sMutex);
 
   sAudioStreamInitEverSucceeded = true;
@@ -545,20 +539,25 @@ Maybe<uint32_t> GetCubebMSGLatencyInFram
 
 void InitLibrary()
 {
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_VOLUME_SCALE);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_SANDBOX);
+  if (MOZ_LOG_TEST(gCubebLog, LogLevel::Verbose)) {
+    cubeb_set_log_callback(CUBEB_LOG_VERBOSE, CubebLogCallback);
+  } else if (MOZ_LOG_TEST(gCubebLog, LogLevel::Error)) {
+    cubeb_set_log_callback(CUBEB_LOG_NORMAL, CubebLogCallback);
+  }
   // We don't want to call the callback on startup, because the pref is the
   // empty string by default ("", which means "logging disabled"). Because the
   // logging can be enabled via environment variables (MOZ_LOG="module:5"),
-  // calling this callback on init would immediately re-disble the logging.
+  // calling this callback on init would immediately re-disable the logging.
   Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
 #ifndef MOZ_WIDGET_ANDROID
   AbstractThread::MainThread()->Dispatch(
     NS_NewRunnableFunction("CubebUtils::InitLibrary", &InitBrandName));
 #endif
 #ifdef MOZ_CUBEB_REMOTING
   if (sCubebSandbox && XRE_IsContentProcess()) {
     InitAudioIPCConnection();
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -60,16 +60,18 @@
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Unused.h"
 #include "nsIScriptError.h"
 #include "nsIOutputStream.h"
 
 using JS::SourceBufferHolder;
 
+using mozilla::Telemetry::LABELS_DOM_SCRIPT_PRELOAD_RESULT;
+
 namespace mozilla {
 namespace dom {
 
 LazyLogModule ScriptLoader::gCspPRLog("CSP");
 LazyLogModule ScriptLoader::gScriptLoaderLog("ScriptLoader");
 
 #undef LOG
 #define LOG(args) \
@@ -175,31 +177,42 @@ ScriptLoader::~ScriptLoader()
     req->FireScriptAvailable(NS_ERROR_ABORT);
   }
 
   // Unblock the kids, in case any of them moved to a different document
   // subtree in the meantime and therefore aren't actually going away.
   for (uint32_t j = 0; j < mPendingChildLoaders.Length(); ++j) {
     mPendingChildLoaders[j]->RemoveParserBlockingScriptExecutionBlocker();
   }
+
+  for (size_t i = 0; i < mPreloads.Length(); i++) {
+    AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::NotUsed);
+  }
 }
 
 // Collect telemtry data about the cache information, and the kind of source
 // which are being loaded, and where it is being loaded from.
 static void
 CollectScriptTelemetry(nsIIncrementalStreamLoader* aLoader,
                        ScriptLoadRequest* aRequest)
 {
   using namespace mozilla::Telemetry;
 
   // Skip this function if we are not running telemetry.
   if (!CanRecordExtended()) {
     return;
   }
 
+  // Report the script kind.
+  if (aRequest->IsModuleRequest()) {
+    AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ModuleScript);
+  } else {
+    AccumulateCategorical(LABELS_DOM_SCRIPT_KIND::ClassicScript);
+  }
+
   // Report the type of source, as well as the size of the source.
   if (aRequest->IsLoadingSource()) {
     if (aRequest->mIsInline) {
       AccumulateCategorical(LABELS_DOM_SCRIPT_LOADING_SOURCE::Inline);
       nsAutoString inlineData;
       aRequest->mElement->GetScriptText(inlineData);
       Accumulate(DOM_SCRIPT_INLINE_SIZE, inlineData.Length());
     } else {
@@ -1311,26 +1324,29 @@ ScriptLoader::ProcessExternalScript(nsIS
 
   RefPtr<ScriptLoadRequest> request = LookupPreloadRequest(aElement, aScriptKind);
 
   if (request && NS_FAILED(CheckContentPolicy(mDocument, aElement, request->mURI,
                                               aTypeAttr, false))) {
     // Probably plans have changed; even though the preload was allowed seems
     // like the actual load is not; let's cancel the preload request.
     request->Cancel();
+    AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::RejectedByPolicy);
     return false;
   }
 
   if (request) {
     // Use the preload request.
 
     // It's possible these attributes changed since we started the preload so
     // update them here.
     request->SetScriptMode(aElement->GetScriptDeferred(),
                            aElement->GetScriptAsync());
+
+    AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::Used);
   } else {
     // No usable preload found.
 
     SRIMetadata sriMetadata;
     {
       nsAutoString integrity;
       aScriptContent->AsElement()->GetAttr(kNameSpaceID_None,
                                           nsGkAtoms::integrity,
@@ -1576,16 +1592,17 @@ ScriptLoader::LookupPreloadRequest(nsISc
   // we have now.
   nsAutoString elementCharset;
   aElement->GetScriptCharset(elementCharset);
   if (!elementCharset.Equals(preloadCharset) ||
       aElement->GetCORSMode() != request->mCORSMode ||
       mDocument->GetReferrerPolicy() != request->mReferrerPolicy ||
       aScriptKind != request->mKind) {
     // Drop the preload.
+    AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::RequestMismatch);
     return nullptr;
   }
 
   return request;
 }
 
 void
 ScriptLoader::GetSRIMetadata(const nsAString& aIntegrityAttr,
@@ -2952,16 +2969,17 @@ ScriptLoader::HandleLoadError(ScriptLoad
     nsCOMPtr<nsIScriptElement> oldParserInsertedScript =
       mCurrentParserInsertedScript;
     mCurrentParserInsertedScript = aRequest->mElement;
     FireScriptAvailable(aResult, aRequest);
     ContinueParserAsync(aRequest);
     mCurrentParserInsertedScript = oldParserInsertedScript;
   } else {
     mPreloads.RemoveElement(aRequest, PreloadRequestComparator());
+    AccumulateCategorical(LABELS_DOM_SCRIPT_PRELOAD_RESULT::LoadError);
   }
 }
 
 void
 ScriptLoader::UnblockParser(ScriptLoadRequest* aParserBlockingRequest)
 {
   aParserBlockingRequest->mElement->UnblockParser();
 }
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -6,17 +6,16 @@
 
 
 #include "mozilla/dom/XMLDocument.h"
 #include "nsParserCIID.h"
 #include "nsCharsetSource.h"
 #include "nsIXMLContentSink.h"
 #include "nsPresContext.h"
 #include "nsIContent.h"
-#include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsIDocShell.h"
 #include "nsHTMLParts.h"
 #include "nsIComponentManager.h"
 #include "nsIDOMElement.h"
 #include "nsIBaseWindow.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMDocumentType.h"
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -237,19 +237,19 @@ ClientSingleTiledLayerBuffer::PaintThebe
                   frontBufferOnWhite, dtOnWhite, rect, dest
                 };
                 if (asyncPaint) {
                   paintCopies.push_back(copy);
                 } else {
                   copy.CopyBuffer();
                 }
               }
+            } else {
+              gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
             }
-          } else {
-            gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
           }
         } else {
           gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
         }
 
         TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
 
         // We don't need to repaint valid content that was just copied.
@@ -331,21 +331,15 @@ ClientSingleTiledLayerBuffer::PaintThebe
   // The new buffer is now validated, remove the dirty region from it.
   mTile.mInvalidBack.SubOut(tileDirtyRegion);
 
   dt = nullptr;
 
   mTile.Flip();
   UnlockTile(mTile);
 
-  if (backBuffer->HasIntermediateBuffer()) {
-    // If our new buffer has an internal buffer, we don't want to keep another
-    // TextureClient around unnecessarily, so discard the back-buffer.
-    mTile.DiscardBackBuffer();
-  }
-
   mValidRegion = aNewValidRegion;
   mLastPaintSurfaceMode = mode;
   mLastPaintContentType = content;
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -1990,27 +1990,37 @@ gfxFont::DrawMissingGlyph(const TextRunD
                           const gfxShapedText::DetailedGlyph* aDetails,
                           const gfx::Point&                   aPt)
 {
     // Default-ignorable chars will have zero advance width;
     // we don't have to draw the hexbox for them.
     float advance = aDetails->mAdvance;
     if (aRunParams.drawMode != DrawMode::GLYPH_PATH && advance > 0) {
         auto* textDrawer = aRunParams.context->GetTextDrawer();
+        const Matrix* matPtr = nullptr;
+        Matrix mat;
         if (textDrawer) {
-            textDrawer->FoundUnsupportedFeature();
-            return false;
+            // Generate an orientation matrix for the current writing mode
+            wr::FontInstanceFlags flags = textDrawer->GetWRGlyphFlags();
+            if (flags.bits & wr::FontInstanceFlags::TRANSPOSE) {
+                std::swap(mat._11, mat._12);
+                std::swap(mat._21, mat._22);
+            }
+            mat.PostScale(flags.bits & wr::FontInstanceFlags::FLIP_X ? -1.0f : 1.0f,
+                          flags.bits & wr::FontInstanceFlags::FLIP_Y ? -1.0f : 1.0f);
+            matPtr = &mat;
         }
 
         Point pt(Float(ToDeviceUnits(aPt.x, aRunParams.devPerApp)),
                  Float(ToDeviceUnits(aPt.y, aRunParams.devPerApp)));
         Float advanceDevUnits =
             Float(ToDeviceUnits(advance, aRunParams.devPerApp));
         Float height = GetMetrics(eHorizontal).maxAscent;
-        Rect glyphRect = aFontParams.isVerticalFont ?
+        // Horizontally center if drawing vertically upright with no sideways transform.
+        Rect glyphRect = aFontParams.isVerticalFont && !mat.HasNonAxisAlignedTransform() ?
             Rect(pt.x - height / 2, pt.y,
                  height, advanceDevUnits) :
             Rect(pt.x, pt.y - height,
                  advanceDevUnits, height);
 
         // If there's a fake-italic skew in effect as part
         // of the drawTarget's transform, we need to undo
         // this before drawing the hexbox. (Bug 983985)
@@ -2023,17 +2033,17 @@ gfxFont::DrawMissingGlyph(const TextRunD
                 PreMultiply(gfx::Matrix(1, 0, OBLIQUE_SKEW_FACTOR, 1, 0, 0)).
                 PreTranslate(-pt);
             aRunParams.context->SetMatrix(mat);
         }
 
         gfxFontMissingGlyphs::DrawMissingGlyph(
             aDetails->mGlyphID, glyphRect, *aRunParams.dt,
             PatternFromState(aRunParams.context),
-            1.0 / aRunParams.devPerApp);
+            1.0 / aRunParams.devPerApp, matPtr);
     }
     return true;
 }
 
 // This method is mostly parallel to DrawGlyphs.
 void
 gfxFont::DrawEmphasisMarks(const gfxTextRun* aShapedText, gfx::Point* aPt,
                            uint32_t aOffset, uint32_t aCount,
--- a/gfx/thebes/gfxFontMissingGlyphs.cpp
+++ b/gfx/thebes/gfxFontMissingGlyphs.cpp
@@ -153,23 +153,49 @@ static const Float BOX_BORDER_OPACITY = 
  * would be to fill in an A8 image surface and then use it as a mask
  * to paint the current color. Tragically this doesn't currently work with the
  * Quartz cairo backend which doesn't generally support masking with surfaces.
  * So for now we just paint a bunch of rectangles...
  */
 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
 static void
 DrawHexChar(uint32_t aDigit, const Point& aPt, DrawTarget& aDrawTarget,
-            const Pattern &aPattern)
+            const Pattern &aPattern, const Matrix* aMat)
 {
+    uint32_t glyphBits = glyphMicroFont[aDigit];
+
+    if (aMat) {
+        // If using an orientation matrix instead of a DT transform, step
+        // with the matrix basis vectors, filling individual rectangles of
+        // the size indicated by the matrix.
+        Point stepX(aMat->_11, aMat->_12);
+        Point stepY(aMat->_21, aMat->_22);
+        Point corner = stepX + stepY;
+        // Get the rectangle at the origin that will be stepped into place.
+        Rect startRect(std::min(corner.x, 0.0f), std::min(corner.y, 0.0f),
+                       fabs(corner.x), fabs(corner.y));
+        startRect.MoveBy(aMat->TransformPoint(aPt));
+        for (int y = 0; y < MINIFONT_HEIGHT; ++y) {
+            Rect curRect = startRect;
+            for (int x = 0; x < MINIFONT_WIDTH; ++x) {
+                if (glyphBits & 1) {
+                    aDrawTarget.FillRect(curRect, aPattern);
+                }
+                glyphBits >>= 1;
+                curRect.MoveBy(stepX);
+            }
+            startRect.MoveBy(stepY);
+        }
+        return;
+    }
+
     // To avoid the potential for seams showing between rects when we're under
     // a transform we concat all the rects into a PathBuilder and fill the
     // resulting Path (rather than using DrawTarget::FillRect).
     RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
-    uint32_t glyphBits = glyphMicroFont[aDigit];
     for (int y = 0; y < MINIFONT_HEIGHT; ++y) {
         for (int x = 0; x < MINIFONT_WIDTH; ++x) {
             if (glyphBits & 1) {
                 Rect r(aPt.x + x, aPt.y + y, 1, 1);
                 MaybeSnapToDevicePixels(r, aDrawTarget, true);
                 builder->MoveTo(r.TopLeft());
                 builder->LineTo(r.TopRight());
                 builder->LineTo(r.BottomRight());
@@ -184,93 +210,121 @@ DrawHexChar(uint32_t aDigit, const Point
 }
 #endif // MOZ_GFX_OPTIMIZE_MOBILE
 
 void
 gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
                                        const Rect& aRect,
                                        DrawTarget& aDrawTarget,
                                        const Pattern& aPattern,
-                                       uint32_t aAppUnitsPerDevPixel)
+                                       uint32_t aAppUnitsPerDevPixel,
+                                       const Matrix* aMat)
 {
+    Rect rect(aRect);
+    // If there is an orientation transform, reorient the bounding rect.
+    if (aMat) {
+        rect.MoveBy(-aRect.BottomLeft());
+        rect = aMat->TransformBounds(rect);
+        rect.MoveBy(aRect.BottomLeft());
+    }
+
     // If we're currently drawing with some kind of pattern, we just draw the
     // missing-glyph data in black.
     ColorPattern color = aPattern.GetType() == PatternType::COLOR ?
         static_cast<const ColorPattern&>(aPattern) :
         ColorPattern(ToDeviceColor(Color(0.f, 0.f, 0.f, 1.f)));
 
     // Stroke a rectangle so that the stroke's left edge is inset one pixel
     // from the left edge of the glyph box and the stroke's right edge
     // is inset one pixel from the right edge of the glyph box.
     Float halfBorderWidth = BOX_BORDER_WIDTH / 2.0;
-    Float borderLeft = aRect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth;
-    Float borderRight = aRect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth;
-    Rect borderStrokeRect(borderLeft, aRect.Y() + halfBorderWidth,
+    Float borderLeft = rect.X() + BOX_HORIZONTAL_INSET + halfBorderWidth;
+    Float borderRight = rect.XMost() - BOX_HORIZONTAL_INSET - halfBorderWidth;
+    Rect borderStrokeRect(borderLeft, rect.Y() + halfBorderWidth,
                           borderRight - borderLeft,
-                          aRect.Height() - 2.0 * halfBorderWidth);
+                          rect.Height() - 2.0 * halfBorderWidth);
     if (!borderStrokeRect.IsEmpty()) {
         ColorPattern adjustedColor = color;
         color.mColor.a *= BOX_BORDER_OPACITY;
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
         aDrawTarget.FillRect(borderStrokeRect, adjustedColor);
 #else
         StrokeOptions strokeOptions(BOX_BORDER_WIDTH);
         aDrawTarget.StrokeRect(borderStrokeRect, adjustedColor, strokeOptions);
 #endif
     }
 
 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
-    Point center = aRect.Center();
+    Point center = rect.Center();
     Float halfGap = HEX_CHAR_GAP / 2.f;
     Float top = -(MINIFONT_HEIGHT + halfGap);
     // We always want integer scaling, otherwise the "bitmap" glyphs will look
     // even uglier than usual when zoomed
     int32_t devPixelsPerCSSPx =
         std::max<int32_t>(1, nsDeviceContext::AppUnitsPerCSSPixel() /
                              aAppUnitsPerDevPixel);
-    AutoRestoreTransform autoRestoreTransform(&aDrawTarget);
-    aDrawTarget.SetTransform(
-      aDrawTarget.GetTransform().PreTranslate(center).
-                                 PreScale(devPixelsPerCSSPx,
-                                          devPixelsPerCSSPx));
+
+    Matrix tempMat;
+    if (aMat) {
+        // If there is an orientation transform, since draw target transforms may
+        // not be supported, scale and translate it so that it can be directly used
+        // for rendering the mini font without changing the draw target transform.
+        tempMat = Matrix(*aMat).PostScale(devPixelsPerCSSPx, devPixelsPerCSSPx)
+                               .PostTranslate(center);
+        aMat = &tempMat;
+    } else {
+        // Otherwise, scale and translate the draw target transform assuming it
+        // supports that.
+        tempMat = aDrawTarget.GetTransform();
+        aDrawTarget.SetTransform(
+            Matrix(tempMat).PreTranslate(center)
+                           .PreScale(devPixelsPerCSSPx, devPixelsPerCSSPx));
+    }
+
     if (aChar < 0x10000) {
-        if (aRect.Width() >= 2 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
-            aRect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
+        if (rect.Width() >= 2 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
+            rect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
             // Draw 4 digits for BMP
             Float left = -(MINIFONT_WIDTH + halfGap);
             DrawHexChar((aChar >> 12) & 0xF,
-                        Point(left, top), aDrawTarget, color);
+                        Point(left, top), aDrawTarget, color, aMat);
             DrawHexChar((aChar >> 8) & 0xF,
-                        Point(halfGap, top), aDrawTarget, color);
+                        Point(halfGap, top), aDrawTarget, color, aMat);
             DrawHexChar((aChar >> 4) & 0xF,
-                        Point(left, halfGap), aDrawTarget, color);
+                        Point(left, halfGap), aDrawTarget, color, aMat);
             DrawHexChar(aChar & 0xF,
-                        Point(halfGap, halfGap), aDrawTarget, color);
+                        Point(halfGap, halfGap), aDrawTarget, color, aMat);
         }
     } else {
-        if (aRect.Width() >= 3 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
-            aRect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
+        if (rect.Width() >= 3 * (MINIFONT_WIDTH + HEX_CHAR_GAP) &&
+            rect.Height() >= 2 * MINIFONT_HEIGHT + HEX_CHAR_GAP) {
             // Draw 6 digits for non-BMP
             Float first = -(MINIFONT_WIDTH * 1.5 + HEX_CHAR_GAP);
             Float second = -(MINIFONT_WIDTH / 2.0);
             Float third = (MINIFONT_WIDTH / 2.0 + HEX_CHAR_GAP);
             DrawHexChar((aChar >> 20) & 0xF,
-                        Point(first, top), aDrawTarget, color);
+                        Point(first, top), aDrawTarget, color, aMat);
             DrawHexChar((aChar >> 16) & 0xF,
-                        Point(second, top), aDrawTarget, color);
+                        Point(second, top), aDrawTarget, color, aMat);
             DrawHexChar((aChar >> 12) & 0xF,
-                        Point(third, top), aDrawTarget, color);
+                        Point(third, top), aDrawTarget, color, aMat);
             DrawHexChar((aChar >> 8) & 0xF,
-                        Point(first, halfGap), aDrawTarget, color);
+                        Point(first, halfGap), aDrawTarget, color, aMat);
             DrawHexChar((aChar >> 4) & 0xF,
-                        Point(second, halfGap), aDrawTarget, color);
+                        Point(second, halfGap), aDrawTarget, color, aMat);
             DrawHexChar(aChar & 0xF,
-                        Point(third, halfGap), aDrawTarget, color);
+                        Point(third, halfGap), aDrawTarget, color, aMat);
         }
     }
+
+    if (!aMat) {
+        // The draw target transform was changed, so it must be restored to
+        // the original value.
+        aDrawTarget.SetTransform(tempMat);
+    }
 #endif
 }
 
 Float
 gfxFontMissingGlyphs::GetDesiredMinWidth(uint32_t aChar,
                                          uint32_t aAppUnitsPerDevPixel)
 {
 /**
--- a/gfx/thebes/gfxFontMissingGlyphs.h
+++ b/gfx/thebes/gfxFontMissingGlyphs.h
@@ -33,22 +33,24 @@ public:
     /**
      * Draw hexboxes for a missing glyph.
      * @param aChar the UTF16 codepoint for the character
      * @param aRect the glyph-box for the glyph that is missing
      * @param aDrawTarget the DrawTarget to draw to
      * @param aPattern the pattern currently being used to paint
      * @param aAppUnitsPerDevPixel the appUnits to devPixel ratio we're using,
      *                             (so we can scale glyphs to a sensible size)
+     * @param aMat optional local-space orientation matrix
      */
     static void DrawMissingGlyph(uint32_t aChar,
                                  const Rect& aRect,
                                  DrawTarget& aDrawTarget,
                                  const Pattern& aPattern,
-                                 uint32_t aAppUnitsPerDevPixel);
+                                 uint32_t aAppUnitsPerDevPixel,
+                                 const Matrix* aMat = nullptr);
     /**
      * @return the desired minimum width for a glyph-box that will allow
      * the hexboxes to be drawn reasonably.
      */
     static Float GetDesiredMinWidth(uint32_t aChar,
                                     uint32_t aAppUnitsPerDevUnit);
 };
 
--- a/gfx/webrender_bindings/RenderCompositor.cpp
+++ b/gfx/webrender_bindings/RenderCompositor.cpp
@@ -2,26 +2,36 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "RenderCompositor.h"
 
 #include "GLContext.h"
+#include "mozilla/gfx/gfxVars.h"
 #include "mozilla/layers/SyncObject.h"
 #include "mozilla/webrender/RenderCompositorOGL.h"
 #include "mozilla/widget/CompositorWidget.h"
 
+#ifdef XP_WIN
+#include "mozilla/webrender/RenderCompositorANGLE.h"
+#endif
+
 namespace mozilla {
 namespace wr {
 
 /* static */ UniquePtr<RenderCompositor>
 RenderCompositor::Create(RefPtr<widget::CompositorWidget>&& aWidget)
 {
+#ifdef XP_WIN
+  if (gfx::gfxVars::UseWebRenderANGLE()) {
+    return RenderCompositorANGLE::Create(Move(aWidget));
+  }
+#endif
   return RenderCompositorOGL::Create(Move(aWidget));
 }
 
 RenderCompositor::RenderCompositor(RefPtr<widget::CompositorWidget>&& aWidget)
   : mWidget(aWidget)
 {
 }
 
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.cpp
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "RenderCompositorANGLE.h"
+
+#include "GLContext.h"
+#include "GLContextEGL.h"
+#include "GLContextProvider.h"
+#include "mozilla/gfx/DeviceManagerDx.h"
+#include "mozilla/layers/HelpersD3D11.h"
+#include "mozilla/layers/SyncObject.h"
+#include "mozilla/widget/CompositorWidget.h"
+
+#include <d3d11.h>
+
+namespace mozilla {
+namespace wr {
+
+/* static */ UniquePtr<RenderCompositor>
+RenderCompositorANGLE::Create(RefPtr<widget::CompositorWidget>&& aWidget)
+{
+  UniquePtr<RenderCompositorANGLE> compositor = MakeUnique<RenderCompositorANGLE>(Move(aWidget));
+  if (!compositor->Initialize()) {
+    return nullptr;
+  }
+  return compositor;
+}
+
+RenderCompositorANGLE::RenderCompositorANGLE(RefPtr<widget::CompositorWidget>&& aWidget)
+  : RenderCompositor(Move(aWidget))
+{
+}
+
+RenderCompositorANGLE::~RenderCompositorANGLE()
+{
+}
+
+bool
+RenderCompositorANGLE::Initialize()
+{
+  mDevice = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
+  if (!mDevice) {
+    gfxCriticalNote << "[D3D11] failed to get compositor device.";
+    return false;
+  }
+
+  mDevice->GetImmediateContext(getter_AddRefs(mCtx));
+  if (!mCtx) {
+    gfxCriticalNote << "[D3D11] failed to get immediate context.";
+    return false;
+  }
+
+  mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(mDevice);
+  if (!mSyncObject->Init()) {
+    // Some errors occur. Clear the mSyncObject here.
+    // Then, there will be no texture synchronization.
+    return false;
+  }
+
+  mGL = gl::GLContextProviderEGL::CreateForCompositorWidget(mWidget, true);
+  if (!mGL || !mGL->IsANGLE()) {
+    gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(mGL.get());
+    return false;
+  }
+  if (!mGL->MakeCurrent()) {
+    gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(mGL.get());
+    return false;
+  }
+
+  return true;
+}
+
+bool
+RenderCompositorANGLE::Destroy()
+{
+  return true;
+}
+
+bool
+RenderCompositorANGLE::BeginFrame()
+{
+  if (!mGL->MakeCurrent()) {
+    gfxCriticalNote << "Failed to make render context current, can't draw.";
+    return false;
+  }
+
+  if (mSyncObject) {
+    // XXX: if the synchronization is failed, we should handle the device reset.
+    mSyncObject->Synchronize();
+  }
+  return true;
+}
+
+void
+RenderCompositorANGLE::EndFrame()
+{
+  InsertPresentWaitQuery();
+
+  mGL->SwapBuffers();
+
+  // Note: this waits on the query we inserted in the previous frame,
+  // not the one we just inserted now. Example:
+  //   Insert query #1
+  //   Present #1
+  //   (first frame, no wait)
+  //   Insert query #2
+  //   Present #2
+  //   Wait for query #1.
+  //   Insert query #3
+  //   Present #3
+  //   Wait for query #2.
+  //
+  // This ensures we're done reading textures before swapping buffers.
+  WaitForPreviousPresentQuery();
+}
+
+void
+RenderCompositorANGLE::Pause()
+{
+}
+
+bool
+RenderCompositorANGLE::Resume()
+{
+  return true;
+}
+
+LayoutDeviceIntSize
+RenderCompositorANGLE::GetClientSize()
+{
+  return mWidget->GetClientSize();
+}
+
+void
+RenderCompositorANGLE::InsertPresentWaitQuery()
+{
+  CD3D11_QUERY_DESC desc(D3D11_QUERY_EVENT);
+  HRESULT hr = mDevice->CreateQuery(&desc, getter_AddRefs(mNextWaitForPresentQuery));
+  if (FAILED(hr) || !mNextWaitForPresentQuery) {
+    gfxWarning() << "Could not create D3D11_QUERY_EVENT: " << hexa(hr);
+    return;
+  }
+
+  mCtx->End(mNextWaitForPresentQuery);
+}
+
+void
+RenderCompositorANGLE::WaitForPreviousPresentQuery()
+{
+  if (mWaitForPresentQuery) {
+    BOOL result;
+    layers::WaitForGPUQuery(mDevice, mCtx, mWaitForPresentQuery, &result);
+  }
+  mWaitForPresentQuery = mNextWaitForPresentQuery.forget();
+}
+
+
+} // namespace wr
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/webrender_bindings/RenderCompositorANGLE.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
+#define MOZILLA_GFX_RENDERCOMPOSITOR_ANGLE_H
+
+#include "mozilla/webrender/RenderCompositor.h"
+
+struct ID3D11DeviceContext;
+struct ID3D11Device;
+struct ID3D11Query;
+
+namespace mozilla {
+
+namespace wr {
+
+class RenderCompositorANGLE : public RenderCompositor
+{
+public:
+  static UniquePtr<RenderCompositor> Create(RefPtr<widget::CompositorWidget>&& aWidget);
+
+  explicit RenderCompositorANGLE(RefPtr<widget::CompositorWidget>&& aWidget);
+  virtual ~RenderCompositorANGLE();
+  bool Initialize();
+
+  bool Destroy() override;
+  bool BeginFrame() override;
+  void EndFrame() override;
+  void Pause() override;
+  bool Resume() override;
+
+  gl::GLContext* gl() const override { return mGL; }
+
+  bool UseANGLE() const override { return true; }
+
+  LayoutDeviceIntSize GetClientSize() override;
+
+protected:
+  void InsertPresentWaitQuery();
+  void WaitForPreviousPresentQuery();
+
+  RefPtr<gl::GLContext> mGL;
+
+  RefPtr<ID3D11Device> mDevice;
+  RefPtr<ID3D11DeviceContext> mCtx;
+
+  RefPtr<ID3D11Query> mWaitForPresentQuery;
+  RefPtr<ID3D11Query> mNextWaitForPresentQuery;
+
+};
+
+} // namespace wr
+} // namespace mozilla
+
+#endif
--- a/gfx/webrender_bindings/RenderCompositorOGL.cpp
+++ b/gfx/webrender_bindings/RenderCompositorOGL.cpp
@@ -3,77 +3,39 @@
 /* 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 "RenderCompositorOGL.h"
 
 #include "GLContext.h"
 #include "GLContextProvider.h"
-#include "mozilla/gfx/gfxVars.h"
-#include "mozilla/layers/SyncObject.h"
 #include "mozilla/widget/CompositorWidget.h"
 
-#ifdef XP_WIN
-#include "GLContextEGL.h"
-#endif
-
 namespace mozilla {
 namespace wr {
 
 /* static */ UniquePtr<RenderCompositor>
 RenderCompositorOGL::Create(RefPtr<widget::CompositorWidget>&& aWidget)
 {
   RefPtr<gl::GLContext> gl;
-  if (gfx::gfxVars::UseWebRenderANGLE()) {
-    gl = gl::GLContextProviderEGL::CreateForCompositorWidget(aWidget, true);
-    if (!gl || !gl->IsANGLE()) {
-      gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: " << gfx::hexa(gl.get());
-      return nullptr;
-    }
-  }
-  if (!gl) {
-    gl = gl::GLContextProvider::CreateForCompositorWidget(aWidget, true);
-  }
+  gl = gl::GLContextProvider::CreateForCompositorWidget(aWidget, true);
   if (!gl || !gl->MakeCurrent()) {
     gfxCriticalNote << "Failed GL context creation for WebRender: " << gfx::hexa(gl.get());
     return nullptr;
   }
   return MakeUnique<RenderCompositorOGL>(Move(gl), Move(aWidget));
 }
 
 RenderCompositorOGL::RenderCompositorOGL(RefPtr<gl::GLContext>&& aGL,
-                                             RefPtr<widget::CompositorWidget>&& aWidget)
+                                         RefPtr<widget::CompositorWidget>&& aWidget)
   : RenderCompositor(Move(aWidget))
   , mGL(aGL)
 {
   MOZ_ASSERT(mGL);
-
-#ifdef XP_WIN
-  if (mGL->IsANGLE()) {
-    gl::GLLibraryEGL* egl = &gl::sEGLLibrary;
-
-    // Fetch the D3D11 device.
-    EGLDeviceEXT eglDevice = nullptr;
-    egl->fQueryDisplayAttribEXT(egl->Display(), LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
-    MOZ_ASSERT(eglDevice);
-    ID3D11Device* device = nullptr;
-    egl->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, (EGLAttrib*)&device);
-    MOZ_ASSERT(device);
-
-    mSyncObject = layers::SyncObjectHost::CreateSyncObjectHost(device);
-    if (mSyncObject) {
-      if (!mSyncObject->Init()) {
-        // Some errors occur. Clear the mSyncObject here.
-        // Then, there will be no texture synchronization.
-        mSyncObject = nullptr;
-      }
-    }
-  }
-#endif
 }
 
 RenderCompositorOGL::~RenderCompositorOGL()
 {
 }
 
 bool
 RenderCompositorOGL::Destroy()
@@ -83,21 +45,16 @@ RenderCompositorOGL::Destroy()
 
 bool
 RenderCompositorOGL::BeginFrame()
 {
   if (!mGL->MakeCurrent()) {
     gfxCriticalNote << "Failed to make render context current, can't draw.";
     return false;
   }
-
-  if (mSyncObject) {
-    // XXX: if the synchronization is failed, we should handle the device reset.
-    mSyncObject->Synchronize();
-  }
   return true;
 }
 
 void
 RenderCompositorOGL::EndFrame()
 {
   mGL->SwapBuffers();
 }
@@ -123,22 +80,16 @@ RenderCompositorOGL::Resume()
   }
   // RenewSurface internally calls MakeCurrent.
   return mGL->RenewSurface(mWidget);
 #else
   return true;
 #endif
 }
 
-bool
-RenderCompositorOGL::UseANGLE() const
-{
-  return mGL->IsANGLE();
-}
-
 LayoutDeviceIntSize
 RenderCompositorOGL::GetClientSize()
 {
   return mWidget->GetClientSize();
 }
 
 
 } // namespace wr
--- a/gfx/webrender_bindings/RenderCompositorOGL.h
+++ b/gfx/webrender_bindings/RenderCompositorOGL.h
@@ -5,49 +5,37 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_GFX_RENDERCOMPOSITOR_OGL_H
 #define MOZILLA_GFX_RENDERCOMPOSITOR_OGL_H
 
 #include "mozilla/webrender/RenderCompositor.h"
 
 namespace mozilla {
-/*
-namespace gl {
-class GLContext;
-}
 
-namespace layers {
-class SyncObjectHost;
-}
-
-namespace widget {
-class CompositorWidget;
-}
-*/
 namespace wr {
 
 class RenderCompositorOGL : public RenderCompositor
 {
 public:
   static UniquePtr<RenderCompositor> Create(RefPtr<widget::CompositorWidget>&& aWidget);
 
   RenderCompositorOGL(RefPtr<gl::GLContext>&& aGL,
-                        RefPtr<widget::CompositorWidget>&& aWidget);
+                      RefPtr<widget::CompositorWidget>&& aWidget);
   virtual ~RenderCompositorOGL();
 
   bool Destroy() override;
   bool BeginFrame() override;
   void EndFrame() override;
   void Pause() override;
   bool Resume() override;
 
   gl::GLContext* gl() const override { return mGL; }
 
-  bool UseANGLE() const override;
+  bool UseANGLE() const override { return false; }
 
   LayoutDeviceIntSize GetClientSize() override;
 
 protected:
   RefPtr<gl::GLContext> mGL;
 };
 
 } // namespace wr
--- a/gfx/webrender_bindings/moz.build
+++ b/gfx/webrender_bindings/moz.build
@@ -42,19 +42,21 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'coco
     ]
     UNIFIED_SOURCES += [
         'RenderMacIOSurfaceTextureHostOGL.cpp',
     ]
 
 if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
     DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True
     EXPORTS.mozilla.webrender += [
+        'RenderCompositorANGLE.h',
         'RenderD3D11TextureHostOGL.h',
     ]
     UNIFIED_SOURCES += [
+        'RenderCompositorANGLE.cpp',
         'RenderD3D11TextureHostOGL.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk3'):
     CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
     CXXFLAGS += CONFIG['CAIRO_FT_CFLAGS']
 
 include('/ipc/chromium/chromium-config.mozbuild')
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -1107,16 +1107,115 @@ function ArrayConcat(arg1) {
 
     // Step 6.
     A.length = n;
 
     // Step 7.
     return A;
 }
 
+// https://tc39.github.io/proposal-flatMap/
+// January 16, 2018
+function ArrayFlatMap(mapperFunction/*, thisArg*/) {
+    // Step 1.
+    var O = ToObject(this);
+
+    // Step 2.
+    var sourceLen = ToLength(O.length);
+
+    // Step 3.
+    if (!IsCallable(mapperFunction))
+        ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, mapperFunction));
+
+    // Step 4.
+    var T = arguments.length > 1 ? arguments[1] : undefined;
+
+    // Step 5.
+    var A = ArraySpeciesCreate(O, 0);
+
+    // Step 6.
+    FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T);
+
+    // Step 7.
+    return A;
+}
+
+// https://tc39.github.io/proposal-flatMap/
+// January 16, 2018
+function ArrayFlatten(/* depth */) {
+     // Step 1.
+    var O = ToObject(this);
+
+    // Step 2.
+    var sourceLen = ToLength(O.length);
+
+    // Step 3.
+    var depthNum = 1;
+
+    // Step 4.
+    if (arguments.length > 0 && arguments[0] !== undefined)
+        depthNum = ToInteger(arguments[0]);
+
+    // Step 5.
+    var A = ArraySpeciesCreate(O, 0);
+
+    // Step 6.
+    FlattenIntoArray(A, O, sourceLen, 0, depthNum);
+
+    // Step 7.
+    return A;
+}
+
+function FlattenIntoArray(target, source, sourceLen, start, depth, mapperFunction, thisArg) {
+    // Step 1.
+    var targetIndex = start;
+
+    // Steps 2-3.
+    for (var sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
+        // Steps 3.a-c.
+        if (sourceIndex in source) {
+            // Step 3.c.i.
+            var element = source[sourceIndex];
+
+            if (mapperFunction) {
+                // Step 3.c.ii.1.
+                assert(arguments.length === 7, "thisArg is present");
+
+                // Step 3.c.ii.2.
+                element = callContentFunction(mapperFunction, thisArg, element, sourceIndex, source);
+            }
+
+            // Step 3.c.iii.
+            var flattenable = IsArray(element);
+
+            // Step 3.c.iv.
+            if (flattenable && depth > 0) {
+                // Step 3.c.iv.1.
+                var elementLen = ToLength(element.length);
+
+                // Step 3.c.iv.2.
+                targetIndex = FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1);
+            } else {
+                // Step 3.c.v.1.
+                if (targetIndex >= MAX_NUMERIC_INDEX)
+                    ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
+
+                // Step 3.c.v.2.
+                _DefineDataProperty(target, targetIndex, element);
+
+                // Step 3.c.v.3.
+                targetIndex++;
+            }
+        }
+    }
+
+    // Step 4.
+    return targetIndex;
+}
+
 function ArrayStaticConcat(arr, arg1) {
     if (arguments.length < 1)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "Array.concat");
     var args = callFunction(std_Array_slice, arguments, 1);
     return callFunction(std_Function_apply, ArrayConcat, arr, args);
 }
 
 function ArrayStaticJoin(arr, separator) {
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -35,18 +35,18 @@
     } while (false)
 #define dbg(msg) \
     do { \
         DumpMessage(callFunction(std_Array_pop, \
                                  StringSplitString(__FILE__, '/')) + \
                     '#' + __LINE__ + ': ' + msg) \
     } while (false)
 #else
-#define assert(b, info) do {} while (false) // Elided assertion.
-#define dbg(msg) do {} while (false) // Elided debugging output.
+#define assert(b, info) ; // Elided assertion.
+#define dbg(msg) ; // Elided debugging output.
 #endif
 
 // All C++-implemented standard builtins library functions used in self-hosted
 // code are installed via the std_functions JSFunctionSpec[] in
 // SelfHosting.cpp.
 //
 // Do not create an alias to a self-hosted builtin, otherwise it will be cloned
 // twice.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8530,16 +8530,41 @@ CodeGenerator::visitBoundsCheckRange(LBo
 void
 CodeGenerator::visitBoundsCheckLower(LBoundsCheckLower* lir)
 {
     int32_t min = lir->mir()->minimum();
     bailoutCmp32(Assembler::LessThan, ToRegister(lir->index()), Imm32(min),
                  lir->snapshot());
 }
 
+void
+CodeGenerator::visitSpectreMaskIndex(LSpectreMaskIndex* lir)
+{
+    MOZ_ASSERT(JitOptions.spectreIndexMasking);
+
+    const LAllocation* index = lir->index();
+    const LAllocation* length = lir->length();
+    Register output = ToRegister(lir->output());
+
+    if (index->isConstant()) {
+        int32_t idx = ToInt32(index);
+        if (length->isRegister())
+            masm.spectreMaskIndex(idx, ToRegister(length), output);
+        else
+            masm.spectreMaskIndex(idx, ToAddress(length), output);
+        return;
+    }
+
+    Register indexReg = ToRegister(index);
+    if (length->isRegister())
+        masm.spectreMaskIndex(indexReg, ToRegister(length), output);
+    else
+        masm.spectreMaskIndex(indexReg, ToAddress(length), output);
+}
+
 class OutOfLineStoreElementHole : public OutOfLineCodeBase<CodeGenerator>
 {
     LInstruction* ins_;
     Label rejoinStore_;
     bool strict_;
 
   public:
     explicit OutOfLineStoreElementHole(LInstruction* ins, bool strict)
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -246,16 +246,17 @@ class CodeGenerator final : public CodeG
     void visitSubstr(LSubstr* lir) override;
     void visitInitializedLength(LInitializedLength* lir) override;
     void visitSetInitializedLength(LSetInitializedLength* lir) override;
     void visitNotO(LNotO* ins) override;
     void visitNotV(LNotV* ins) override;
     void visitBoundsCheck(LBoundsCheck* lir) override;
     void visitBoundsCheckRange(LBoundsCheckRange* lir) override;
     void visitBoundsCheckLower(LBoundsCheckLower* lir) override;
+    void visitSpectreMaskIndex(LSpectreMaskIndex* lir) override;
     void visitLoadFixedSlotV(LLoadFixedSlotV* ins) override;
     void visitLoadFixedSlotAndUnbox(LLoadFixedSlotAndUnbox* lir) override;
     void visitLoadFixedSlotT(LLoadFixedSlotT* ins) override;
     void visitStoreFixedSlotV(LStoreFixedSlotV* ins) override;
     void visitStoreFixedSlotT(LStoreFixedSlotT* ins) override;
     void emitGetPropertyPolymorphic(LInstruction* lir, Register obj,
                                     Register scratch, const TypedOrValueRegister& output);
     void visitGetPropertyPolymorphicV(LGetPropertyPolymorphicV* ins) override;
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7830,17 +7830,18 @@ IonBuilder::getElemTryTypedObject(bool* 
     MOZ_CRASH("Bad kind");
 }
 
 bool
 IonBuilder::checkTypedObjectIndexInBounds(uint32_t elemSize,
                                           MDefinition* obj,
                                           MDefinition* index,
                                           TypedObjectPrediction objPrediction,
-                                          LinearSum* indexAsByteOffset)
+                                          LinearSum* indexAsByteOffset,
+                                          BoundsCheckKind kind)
 {
     // Ensure index is an integer.
     MInstruction* idInt32 = MToInt32::New(alloc(), index);
     current->add(idInt32);
 
     // If we know the length statically from the type, just embed it.
     // Otherwise, load it from the appropriate reserved slot on the
     // typed object.  We know it's an int32, so we can convert from
@@ -7857,17 +7858,17 @@ IonBuilder::checkTypedObjectIndexInBound
             trackOptimizationOutcome(TrackedOutcome::TypedObjectHasDetachedBuffer);
             return false;
         }
     } else {
         trackOptimizationOutcome(TrackedOutcome::TypedObjectArrayRange);
         return false;
     }
 
-    index = addBoundsCheck(idInt32, length);
+    index = addBoundsCheck(idInt32, length, kind);
 
     return indexAsByteOffset->add(index, AssertedCast<int32_t>(elemSize));
 }
 
 AbortReasonOr<Ok>
 IonBuilder::getElemTryScalarElemOfTypedObject(bool* emitted,
                                               MDefinition* obj,
                                               MDefinition* index,
@@ -7877,18 +7878,21 @@ IonBuilder::getElemTryScalarElemOfTypedO
 {
     MOZ_ASSERT(objPrediction.ofArrayKind());
 
     // Must always be loading the same scalar type
     ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
     MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
 
     LinearSum indexAsByteOffset(alloc());
-    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
-        return Ok();
+    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
+                                       BoundsCheckKind::IsLoad))
+    {
+        return Ok();
+    }
 
     trackOptimizationSuccess();
     *emitted = true;
 
     return pushScalarLoadFromTypedObject(obj, indexAsByteOffset, elemType);
 }
 
 AbortReasonOr<Ok>
@@ -7899,18 +7903,21 @@ IonBuilder::getElemTryReferenceElemOfTyp
                                                  TypedObjectPrediction elemPrediction)
 {
     MOZ_ASSERT(objPrediction.ofArrayKind());
 
     ReferenceTypeDescr::Type elemType = elemPrediction.referenceType();
     uint32_t elemSize = ReferenceTypeDescr::size(elemType);
 
     LinearSum indexAsByteOffset(alloc());
-    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
-        return Ok();
+    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
+                                       BoundsCheckKind::IsLoad))
+    {
+        return Ok();
+    }
 
     trackOptimizationSuccess();
     *emitted = true;
 
     return pushReferenceLoadFromTypedObject(obj, indexAsByteOffset, elemType, nullptr);
 }
 
 AbortReasonOr<Ok>
@@ -8020,18 +8027,21 @@ IonBuilder::getElemTryComplexElemOfTyped
                                                uint32_t elemSize)
 {
     MOZ_ASSERT(objPrediction.ofArrayKind());
 
     MDefinition* type = loadTypedObjectType(obj);
     MDefinition* elemTypeObj = typeObjectForElementFromArrayStructType(type);
 
     LinearSum indexAsByteOffset(alloc());
-    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
-        return Ok();
+    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
+                                       BoundsCheckKind::IsLoad))
+    {
+        return Ok();
+    }
 
     return pushDerivedTypedObject(emitted, obj, indexAsByteOffset,
                                   elemPrediction, elemTypeObj);
 }
 
 AbortReasonOr<Ok>
 IonBuilder::pushDerivedTypedObject(bool* emitted,
                                    MDefinition* obj,
@@ -8312,17 +8322,17 @@ IonBuilder::getElemTryString(bool* emitt
     // Emit fast path for string[index].
     MInstruction* idInt32 = MToInt32::New(alloc(), index);
     current->add(idInt32);
     index = idInt32;
 
     MStringLength* length = MStringLength::New(alloc(), obj);
     current->add(length);
 
-    index = addBoundsCheck(index, length);
+    index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
 
     MCharCodeAt* charCode = MCharCodeAt::New(alloc(), obj, index);
     current->add(charCode);
 
     MFromCharCode* result = MFromCharCode::New(alloc(), charCode);
     current->add(result);
     current->push(result);
 
@@ -8354,17 +8364,17 @@ IonBuilder::getElemTryArguments(bool* em
     current->add(length);
 
     // Ensure index is an integer.
     MInstruction* idInt32 = MToInt32::New(alloc(), index);
     current->add(idInt32);
     index = idInt32;
 
     // Bailouts if we read more than the number of actual arguments.
-    index = addBoundsCheck(index, length);
+    index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
 
     // Load the argument from the actual arguments.
     bool modifiesArgs = script()->baselineScript()->modifiesArguments();
     MGetFrameArgument* load = MGetFrameArgument::New(alloc(), index, modifiesArgs);
     current->add(load);
     current->push(load);
 
     TemporaryTypeSet* types = bytecodeTypes(pc);
@@ -8442,17 +8452,18 @@ IonBuilder::getElemTryArgumentsInlinedIn
     MInstruction* idInt32 = MToInt32::New(alloc(), index);
     current->add(idInt32);
     index = idInt32;
 
     // Bailout if we read more than the number of actual arguments. This bailout
     // cannot re-enter because reading out of bounds arguments will disable the
     // lazy arguments optimization for this script, when this code would be
     // executed in Baseline. (see GetElemOptimizedArguments)
-    index = addBoundsCheck(index, constantInt(inlineCallInfo_->argc()));
+    index = addBoundsCheck(index, constantInt(inlineCallInfo_->argc()),
+                           BoundsCheckKind::IsLoad);
 
     // Get an instruction to represent the state of the argument vector.
     MInstruction* args = MArgumentState::New(alloc().fallible(), inlineCallInfo_->argv());
     if (!args)
         return abort(AbortReason::Alloc);
     current->add(args);
 
     // Select a value to pick from a vector.
@@ -8641,17 +8652,17 @@ IonBuilder::jsop_getelem_dense(MDefiniti
 
     MInstruction* load;
 
     if (!readOutOfBounds) {
         // This load should not return undefined, so likely we're reading
         // in-bounds elements, and the array is packed or its holes are not
         // read. This is the best case: we can separate the bounds check for
         // hoisting.
-        index = addBoundsCheck(index, initLength);
+        index = addBoundsCheck(index, initLength, BoundsCheckKind::IsLoad);
 
         load = MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble);
         current->add(load);
     } else {
         // This load may return undefined, so assume that we *can* read holes,
         // or that we can read out-of-bounds accesses. In this case, the bounds
         // check is part of the opcode.
         load = MLoadElementHole::New(alloc(), elements, index, initLength, needsHoleCheck);
@@ -8680,17 +8691,18 @@ IonBuilder::addArrayBufferByteLength(MDe
     ins->setResultType(MIRType::Int32);
     return ins;
 }
 
 void
 IonBuilder::addTypedArrayLengthAndData(MDefinition* obj,
                                        BoundsChecking checking,
                                        MDefinition** index,
-                                       MInstruction** length, MInstruction** elements)
+                                       MInstruction** length, MInstruction** elements,
+                                       BoundsCheckKind boundsCheckKind)
 {
     MOZ_ASSERT((index != nullptr) == (elements != nullptr));
 
     JSObject* tarr = nullptr;
 
     if (MConstant* objConst = obj->maybeConstantValue()) {
         if (objConst->type() == MIRType::Object)
             tarr = &objConst->toObject();
@@ -8714,32 +8726,32 @@ IonBuilder::addTypedArrayLengthAndData(M
                 obj->setImplicitlyUsedUnchecked();
 
                 int32_t len = AssertedCast<int32_t>(tarr->as<TypedArrayObject>().length());
                 *length = MConstant::New(alloc(), Int32Value(len));
                 current->add(*length);
 
                 if (index) {
                     if (checking == DoBoundsCheck)
-                        *index = addBoundsCheck(*index, *length);
+                        *index = addBoundsCheck(*index, *length, boundsCheckKind);
 
                     *elements = MConstantElements::New(alloc(), data);
                     current->add(*elements);
                 }
                 return;
             }
         }
     }
 
     *length = MTypedArrayLength::New(alloc(), obj);
     current->add(*length);
 
     if (index) {
         if (checking == DoBoundsCheck)
-            *index = addBoundsCheck(*index, *length);
+            *index = addBoundsCheck(*index, *length, boundsCheckKind);
 
         *elements = MTypedArrayElements::New(alloc(), obj);
         current->add(*elements);
     }
 }
 
 MDefinition*
 IonBuilder::convertShiftToMaskForStaticTypedArray(MDefinition* id,
@@ -8811,17 +8823,18 @@ IonBuilder::jsop_getelem_typed(MDefiniti
         // the array type to determine the result type, even if the opcode has
         // never executed. The known pushed type is only used to distinguish
         // uint32 reads that may produce either doubles or integers.
         MIRType knownType = MIRTypeForTypedArrayRead(arrayType, allowDouble);
 
         // Get length, bounds-check, then get elements, and add all instructions.
         MInstruction* length;
         MInstruction* elements;
-        addTypedArrayLengthAndData(obj, DoBoundsCheck, &index, &length, &elements);
+        addTypedArrayLengthAndData(obj, DoBoundsCheck, &index, &length, &elements,
+                                   BoundsCheckKind::IsLoad);
 
         // Load the element.
         MLoadUnboxedScalar* load = MLoadUnboxedScalar::New(alloc(), elements, index, arrayType);
         current->add(load);
         current->push(load);
 
         // Note: we can ignore the type barrier here, we know the type must
         // be valid and unbarriered.
@@ -8996,18 +9009,21 @@ IonBuilder::setElemTryReferenceElemOfTyp
                                                  TypedObjectPrediction objPrediction,
                                                  MDefinition* value,
                                                  TypedObjectPrediction elemPrediction)
 {
     ReferenceTypeDescr::Type elemType = elemPrediction.referenceType();
     uint32_t elemSize = ReferenceTypeDescr::size(elemType);
 
     LinearSum indexAsByteOffset(alloc());
-    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
-        return Ok();
+    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
+                                       BoundsCheckKind::IsStore))
+    {
+        return Ok();
+    }
 
     return setPropTryReferenceTypedObjectValue(emitted, obj, indexAsByteOffset,
                                                elemType, value, nullptr);
 }
 
 AbortReasonOr<Ok>
 IonBuilder::setElemTryScalarElemOfTypedObject(bool* emitted,
                                               MDefinition* obj,
@@ -9017,18 +9033,21 @@ IonBuilder::setElemTryScalarElemOfTypedO
                                               TypedObjectPrediction elemPrediction,
                                               uint32_t elemSize)
 {
     // Must always be loading the same scalar type
     ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
     MOZ_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
 
     LinearSum indexAsByteOffset(alloc());
-    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset))
-        return Ok();
+    if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction, &indexAsByteOffset,
+                                       BoundsCheckKind::IsStore))
+    {
+        return Ok();
+    }
 
     return setPropTryScalarTypedObjectValue(emitted, obj, indexAsByteOffset, elemType, value);
 }
 
 AbortReasonOr<Ok>
 IonBuilder::setElemTryTypedStatic(bool* emitted, MDefinition* object,
                                   MDefinition* index, MDefinition* value)
 {
@@ -9314,17 +9333,17 @@ IonBuilder::initOrSetElemDense(Temporary
                                                                 newValue, strict);
         store = ins;
         common = ins;
 
         current->add(ins);
     } else {
         MInstruction* initLength = initializedLength(obj, elements);
 
-        id = addBoundsCheck(id, initLength);
+        id = addBoundsCheck(id, initLength, BoundsCheckKind::IsStore);
         bool needsHoleCheck = !packed && hasExtraIndexedProperty;
 
         MStoreElement* ins = MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck);
         store = ins;
         common = ins;
 
         current->add(store);
     }
@@ -9362,17 +9381,18 @@ IonBuilder::jsop_setelem_typed(Scalar::T
     MInstruction* idInt32 = MToInt32::New(alloc(), id);
     current->add(idInt32);
     id = idInt32;
 
     // Get length, bounds-check, then get elements, and add all instructions.
     MInstruction* length;
     MInstruction* elements;
     BoundsChecking checking = expectOOB ? SkipBoundsCheck : DoBoundsCheck;
-    addTypedArrayLengthAndData(obj, checking, &id, &length, &elements);
+    addTypedArrayLengthAndData(obj, checking, &id, &length, &elements,
+                               BoundsCheckKind::IsStore);
 
     // Clamp value to [0, 255] for Uint8ClampedArray.
     MDefinition* toWrite = value;
     if (arrayType == Scalar::Uint8Clamped) {
         toWrite = MClampToUint8::New(alloc(), value);
         current->add(toWrite->toInstruction());
     }
 
@@ -12896,17 +12916,17 @@ IonBuilder::inTryDense(bool* emitted, MD
     // Get the elements vector.
     MElements* elements = MElements::New(alloc(), obj);
     current->add(elements);
 
     MInstruction* initLength = initializedLength(obj, elements);
 
     // If there are no holes, speculate the InArray check will not fail.
     if (!needsHoleCheck && !failedBoundsCheck_) {
-        addBoundsCheck(idInt32, initLength);
+        addBoundsCheck(idInt32, initLength, BoundsCheckKind::UnusedIndex);
         pushConstant(BooleanValue(true));
         return Ok();
     }
 
     // Check if id < initLength and elem[id] not a hole.
     MInArray* ins = MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck);
 
     current->add(ins);
@@ -13241,25 +13261,30 @@ IonBuilder::addMaybeCopyElementsForWrite
     if (!ElementAccessMightBeCopyOnWrite(constraints(), object))
         return object;
     MInstruction* copy = MMaybeCopyElementsForWrite::New(alloc(), object, checkNative);
     current->add(copy);
     return copy;
 }
 
 MInstruction*
-IonBuilder::addBoundsCheck(MDefinition* index, MDefinition* length)
+IonBuilder::addBoundsCheck(MDefinition* index, MDefinition* length, BoundsCheckKind kind)
 {
     MInstruction* check = MBoundsCheck::New(alloc(), index, length);
     current->add(check);
 
     // If a bounds check failed in the past, don't optimize bounds checks.
     if (failedBoundsCheck_)
         check->setNotMovable();
 
+    if (kind == BoundsCheckKind::IsLoad && JitOptions.spectreIndexMasking) {
+        check = MSpectreMaskIndex::New(alloc(), check, length);
+        current->add(check);
+    }
+
     return check;
 }
 
 MInstruction*
 IonBuilder::addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind)
 {
     MGuardShape* guard = MGuardShape::New(alloc(), obj, shape, bailoutKind);
     current->add(guard);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -190,17 +190,20 @@ class IonBuilder
     MDefinition* createThis(JSFunction* target, MDefinition* callee, MDefinition* newTarget);
     MInstruction* createNamedLambdaObject(MDefinition* callee, MDefinition* envObj);
     AbortReasonOr<MInstruction*> createCallObject(MDefinition* callee, MDefinition* envObj);
 
     MDefinition* walkEnvironmentChain(unsigned hops);
 
     MInstruction* addConvertElementsToDoubles(MDefinition* elements);
     MDefinition* addMaybeCopyElementsForWrite(MDefinition* object, bool checkNative);
-    MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length);
+
+    enum class BoundsCheckKind { IsLoad, IsStore, UnusedIndex };
+    MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length, BoundsCheckKind kind);
+
     MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape, BailoutKind bailoutKind);
     MInstruction* addGroupGuard(MDefinition* obj, ObjectGroup* group, BailoutKind bailoutKind);
     MInstruction* addUnboxedExpandoGuard(MDefinition* obj, bool hasExpando, BailoutKind bailoutKind);
     MInstruction* addSharedTypedArrayGuard(MDefinition* obj);
 
     MInstruction*
     addGuardReceiverPolymorphic(MDefinition* obj, const BaselineInspector::ReceiverVector& receivers);
 
@@ -370,17 +373,18 @@ class IonBuilder
                                               int32_t* ownerByteAdjustment);
     MDefinition* typeObjectForElementFromArrayStructType(MDefinition* typedObj);
     MDefinition* typeObjectForFieldFromStructType(MDefinition* type,
                                                   size_t fieldIndex);
     bool checkTypedObjectIndexInBounds(uint32_t elemSize,
                                        MDefinition* obj,
                                        MDefinition* index,
                                        TypedObjectPrediction objTypeDescrs,
-                                       LinearSum* indexAsByteOffset);
+                                       LinearSum* indexAsByteOffset,
+                                       BoundsCheckKind kind);
     AbortReasonOr<Ok> pushDerivedTypedObject(bool* emitted,
                                              MDefinition* obj,
                                              const LinearSum& byteOffset,
                                              TypedObjectPrediction derivedTypeDescrs,
                                              MDefinition* derivedTypeObj);
     AbortReasonOr<Ok> pushScalarLoadFromTypedObject(MDefinition* obj,
                                                     const LinearSum& byteoffset,
                                                     ScalarTypeDescr::Type type);
@@ -459,24 +463,26 @@ class IonBuilder
     // Add instructions to compute a typed array's length and data.  Also
     // optionally convert |*index| into a bounds-checked definition, if
     // requested.
     //
     // If you only need the array's length, use addTypedArrayLength below.
     void addTypedArrayLengthAndData(MDefinition* obj,
                                     BoundsChecking checking,
                                     MDefinition** index,
-                                    MInstruction** length, MInstruction** elements);
+                                    MInstruction** length, MInstruction** elements,
+                                    BoundsCheckKind boundsCheckKind);
 
     // Add an instruction to compute a typed array's length to the current
     // block.  If you also need the typed array's data, use the above method
     // instead.
     MInstruction* addTypedArrayLength(MDefinition* obj) {
         MInstruction* length;
-        addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr);
+        addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr,
+                                   BoundsCheckKind::UnusedIndex);
         return length;
     }
 
     AbortReasonOr<Ok> improveThisTypesForCall();
 
     MDefinition* getCallee();
     MDefinition* getAliasedVar(EnvironmentCoordinate ec);
     AbortReasonOr<MDefinition*> addLexicalCheck(MDefinition* input);
@@ -761,17 +767,17 @@ class IonBuilder
                                      unsigned numVectors);
     InliningResult inlineSimdCheck(CallInfo& callInfo, JSNative native, SimdType type);
     InliningResult inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
                                      SimdType from, SimdType to);
     InliningResult inlineSimdSelect(CallInfo& callInfo, JSNative native, SimdType type);
 
     bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType,
                                  MInstruction** elements, MDefinition** index,
-                                 Scalar::Type* arrayType);
+                                 Scalar::Type* arrayType, BoundsCheckKind boundsCheckKind);
     InliningResult inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type,
                                   unsigned numElems);
     InliningResult inlineSimdStore(CallInfo& callInfo, JSNative native, SimdType type,
                                    unsigned numElems);
 
     InliningResult inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native,
                                         SimdType type);
 
@@ -825,17 +831,18 @@ class IonBuilder
     enum AtomicCheckResult {
         DontCheckAtomicResult,
         DoCheckAtomicResult
     };
 
     bool atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayElementType,
                                    bool* requiresDynamicCheck,
                                    AtomicCheckResult checkResult=DoCheckAtomicResult);
-    void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index);
+    void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index,
+                            BoundsCheckKind kind);
 
     bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo);
 
     AbortReasonOr<MCall*> makeCallHelper(JSFunction* target, CallInfo& callInfo);
     AbortReasonOr<Ok> makeCall(JSFunction* target, CallInfo& callInfo);
 
     MDefinition* patchInlinedReturn(CallInfo& callInfo, MBasicBlock* exit, MBasicBlock* bottom);
     MDefinition* patchInlinedReturns(CallInfo& callInfo, MIRGraphReturns& returns,
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3125,16 +3125,36 @@ LIRGenerator::visitBoundsCheck(MBoundsCh
         check = new(alloc()) LBoundsCheck(useRegisterOrConstant(ins->index()),
                                           useAnyOrConstant(ins->length()));
     }
     assignSnapshot(check, Bailout_BoundsCheck);
     add(check, ins);
 }
 
 void
+LIRGenerator::visitSpectreMaskIndex(MSpectreMaskIndex* ins)
+{
+    MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
+    MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
+    MOZ_ASSERT(ins->type() == MIRType::Int32);
+
+    // On 64-bit platforms, the length must be in a register, so
+    // MacroAssembler::maskIndex can emit more efficient code.
+#if JS_BITS_PER_WORD == 64
+    LAllocation lengthUse = useRegister(ins->length());
+#else
+    LAllocation lengthUse = useAny(ins->length());
+#endif
+
+    LSpectreMaskIndex* lir =
+        new(alloc()) LSpectreMaskIndex(useRegisterOrConstant(ins->index()), lengthUse);
+    define(lir, ins);
+}
+
+void
 LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins)
 {
     MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
 
     if (!ins->fallible())
         return;
 
     LInstruction* check = new(alloc()) LBoundsCheckLower(useRegister(ins->index()));
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -224,16 +224,17 @@ class LIRGenerator : public LIRGenerator
     void visitTypedObjectElements(MTypedObjectElements* ins) override;
     void visitSetTypedObjectOffset(MSetTypedObjectOffset* ins) override;
     void visitTypedObjectDescr(MTypedObjectDescr* ins) override;
     void visitInitializedLength(MInitializedLength* ins) override;
     void visitSetInitializedLength(MSetInitializedLength* ins) override;
     void visitNot(MNot* ins) override;
     void visitBoundsCheck(MBoundsCheck* ins) override;
     void visitBoundsCheckLower(MBoundsCheckLower* ins) override;
+    void visitSpectreMaskIndex(MSpectreMaskIndex* ins) override;
     void visitLoadElement(MLoadElement* ins) override;
     void visitLoadElementHole(MLoadElementHole* ins) override;
     void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins) override;
     void visitLoadUnboxedString(MLoadUnboxedString* ins) override;
     void visitLoadElementFromState(MLoadElementFromState* ins) override;
     void visitStoreElement(MStoreElement* ins) override;
     void visitStoreElementHole(MStoreElementHole* ins) override;
     void visitFallibleStoreElement(MFallibleStoreElement* ins) override;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -1863,17 +1863,17 @@ IonBuilder::inlineStrCharCodeAt(CallInfo
     callInfo.setImplicitlyUsedUnchecked();
 
     MInstruction* index = MToInt32::New(alloc(), callInfo.getArg(0));
     current->add(index);
 
     MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
     current->add(length);
 
-    index = addBoundsCheck(index, length);
+    index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
 
     MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
     current->add(charCode);
     current->push(charCode);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningResult
@@ -1973,17 +1973,17 @@ IonBuilder::inlineStrCharAt(CallInfo& ca
     callInfo.setImplicitlyUsedUnchecked();
 
     MInstruction* index = MToInt32::New(alloc(), callInfo.getArg(0));
     current->add(index);
 
     MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg());
     current->add(length);
 
-    index = addBoundsCheck(index, length);
+    index = addBoundsCheck(index, length, BoundsCheckKind::IsLoad);
 
     // String.charAt(x) = String.fromCharCode(String.charCodeAt(x))
     MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index);
     current->add(charCode);
 
     MFromCharCode* string = MFromCharCode::New(alloc(), charCode);
     current->add(string);
     current->push(string);
@@ -3264,17 +3264,17 @@ IonBuilder::inlineAtomicsCompareExchange
     bool requiresCheck = false;
     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck))
         return InliningStatus_NotInlined;
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MInstruction* elements;
     MDefinition* index;
-    atomicsCheckBounds(callInfo, &elements, &index);
+    atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
 
     if (requiresCheck)
         addSharedTypedArrayGuard(callInfo.getArg(0));
 
     MCompareExchangeTypedArrayElement* cas =
         MCompareExchangeTypedArrayElement::New(alloc(), elements, index, arrayType, oldval, newval);
     cas->setResultType(getInlineReturnType());
     current->add(cas);
@@ -3300,17 +3300,17 @@ IonBuilder::inlineAtomicsExchange(CallIn
     bool requiresCheck = false;
     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck))
         return InliningStatus_NotInlined;
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MInstruction* elements;
     MDefinition* index;
-    atomicsCheckBounds(callInfo, &elements, &index);
+    atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
 
     if (requiresCheck)
         addSharedTypedArrayGuard(callInfo.getArg(0));
 
     MInstruction* exchange =
         MAtomicExchangeTypedArrayElement::New(alloc(), elements, index, value, arrayType);
     exchange->setResultType(getInlineReturnType());
     current->add(exchange);
@@ -3332,17 +3332,17 @@ IonBuilder::inlineAtomicsLoad(CallInfo& 
     bool requiresCheck = false;
     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck))
         return InliningStatus_NotInlined;
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MInstruction* elements;
     MDefinition* index;
-    atomicsCheckBounds(callInfo, &elements, &index);
+    atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
 
     if (requiresCheck)
         addSharedTypedArrayGuard(callInfo.getArg(0));
 
     MLoadUnboxedScalar* load =
         MLoadUnboxedScalar::New(alloc(), elements, index, arrayType,
                                 DoesRequireMemoryBarrier);
     load->setResultType(getInlineReturnType());
@@ -3384,17 +3384,17 @@ IonBuilder::inlineAtomicsStore(CallInfo&
     bool requiresCheck = false;
     if (!atomicsMeetsPreconditions(callInfo, &arrayType, &requiresCheck, DontCheckAtomicResult))
         return InliningStatus_NotInlined;
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MInstruction* elements;
     MDefinition* index;
-    atomicsCheckBounds(callInfo, &elements, &index);
+    atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsStore);
 
     if (requiresCheck)
         addSharedTypedArrayGuard(callInfo.getArg(0));
 
     MDefinition* toWrite = value;
     if (toWrite->type() != MIRType::Int32) {
         toWrite = MTruncateToInt32::New(alloc(), toWrite);
         current->add(toWrite->toInstruction());
@@ -3428,17 +3428,17 @@ IonBuilder::inlineAtomicsBinop(CallInfo&
 
     callInfo.setImplicitlyUsedUnchecked();
 
     if (requiresCheck)
         addSharedTypedArrayGuard(callInfo.getArg(0));
 
     MInstruction* elements;
     MDefinition* index;
-    atomicsCheckBounds(callInfo, &elements, &index);
+    atomicsCheckBounds(callInfo, &elements, &index, BoundsCheckKind::IsLoad);
 
     AtomicOp k = AtomicFetchAddOp;
     switch (target) {
       case InlinableNative::AtomicsAdd:
         k = AtomicFetchAddOp;
         break;
       case InlinableNative::AtomicsSub:
         k = AtomicFetchSubOp;
@@ -3525,24 +3525,25 @@ IonBuilder::atomicsMeetsPreconditions(Ca
         return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Double;
       default:
         // Excludes floating types and Uint8Clamped.
         return false;
     }
 }
 
 void
-IonBuilder::atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index)
+IonBuilder::atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, MDefinition** index,
+                               BoundsCheckKind kind)
 {
     // Perform bounds checking and extract the elements vector.
     MDefinition* obj = callInfo.getArg(0);
     MInstruction* length = nullptr;
     *index = callInfo.getArg(1);
     *elements = nullptr;
-    addTypedArrayLengthAndData(obj, DoBoundsCheck, index, &length, elements);
+    addTypedArrayLengthAndData(obj, DoBoundsCheck, index, &length, elements, kind);
 }
 
 IonBuilder::InliningResult
 IonBuilder::inlineIsConstructing(CallInfo& callInfo)
 {
     MOZ_ASSERT(!callInfo.constructing());
     MOZ_ASSERT(callInfo.argc() == 0);
     MOZ_ASSERT(script()->functionNonDelazifying(),
@@ -4246,17 +4247,18 @@ SimdTypeToArrayElementType(SimdType type
       case SimdType::Int32x4:
       case SimdType::Uint32x4:  return Scalar::Int32x4;
       default:                MOZ_CRASH("unexpected simd type");
     }
 }
 
 bool
 IonBuilder::prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
-                                    MDefinition** index, Scalar::Type* arrayType)
+                                    MDefinition** index, Scalar::Type* arrayType,
+                                    BoundsCheckKind boundsCheckKind)
 {
     MDefinition* array = callInfo.getArg(0);
     *index = callInfo.getArg(1);
 
     if (!ElementAccessIsTypedArray(constraints(), array, *index, arrayType))
         return false;
 
     MInstruction* indexAsInt32 = MToInt32::New(alloc(), *index);
@@ -4276,42 +4278,43 @@ IonBuilder::prepareForSimdLoadStore(Call
         // We're fine even with the add overflows, as long as the generated code
         // for the bounds check uses an unsigned comparison.
         addedIndex->setInt32Specialization();
         current->add(addedIndex);
         indexForBoundsCheck = addedIndex;
     }
 
     MInstruction* length;
-    addTypedArrayLengthAndData(array, SkipBoundsCheck, index, &length, elements);
+    addTypedArrayLengthAndData(array, SkipBoundsCheck, index, &length, elements, boundsCheckKind);
 
     // It can be that the index is out of bounds, while the added index for the
     // bounds check is in bounds, so we actually need two bounds checks here.
-    MInstruction* positiveCheck = MBoundsCheck::New(alloc(), *index, length);
-    current->add(positiveCheck);
-
-    MInstruction* fullCheck = MBoundsCheck::New(alloc(), indexForBoundsCheck, length);
-    current->add(fullCheck);
+    *index = addBoundsCheck(*index, length, boundsCheckKind);
+
+    addBoundsCheck(indexForBoundsCheck, length, BoundsCheckKind::UnusedIndex);
     return true;
 }
 
 IonBuilder::InliningResult
 IonBuilder::inlineSimdLoad(CallInfo& callInfo, JSNative native, SimdType type, unsigned numElems)
 {
     InlineTypedObject* templateObj = nullptr;
     if (!canInlineSimd(callInfo, native, 2, &templateObj))
         return InliningStatus_NotInlined;
 
     Scalar::Type elemType = SimdTypeToArrayElementType(type);
 
     MDefinition* index = nullptr;
     MInstruction* elements = nullptr;
     Scalar::Type arrayType;
-    if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType))
-        return InliningStatus_NotInlined;
+    if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType,
+                                 BoundsCheckKind::IsLoad))
+    {
+        return InliningStatus_NotInlined;
+    }
 
     MLoadUnboxedScalar* load = MLoadUnboxedScalar::New(alloc(), elements, index, arrayType);
     load->setResultType(SimdTypeToMIRType(type));
     load->setSimdRead(elemType, numElems);
 
     return boxSimd(callInfo, load, templateObj);
 }
 
@@ -4322,18 +4325,21 @@ IonBuilder::inlineSimdStore(CallInfo& ca
     if (!canInlineSimd(callInfo, native, 3, &templateObj))
         return InliningStatus_NotInlined;
 
     Scalar::Type elemType = SimdTypeToArrayElementType(type);
 
     MDefinition* index = nullptr;
     MInstruction* elements = nullptr;
     Scalar::Type arrayType;
-    if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType))
-        return InliningStatus_NotInlined;
+    if (!prepareForSimdLoadStore(callInfo, elemType, &elements, &index, &arrayType,
+                                 BoundsCheckKind::IsStore))
+    {
+        return InliningStatus_NotInlined;
+    }
 
     MDefinition* valueToWrite = unboxSimd(callInfo.getArg(2), type);
     MStoreUnboxedScalar* store = MStoreUnboxedScalar::New(alloc(), elements, index,
                                                           valueToWrite, arrayType,
                                                           MStoreUnboxedScalar::TruncateInput);
     store->setSimdWrite(elemType, numElems);
 
     current->add(store);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9544,16 +9544,48 @@ class MBoundsCheckLower
         return AliasSet::None();
     }
     bool fallible() const {
         return fallible_;
     }
     void collectRangeInfoPreTrunc() override;
 };
 
+class MSpectreMaskIndex
+  : public MBinaryInstruction,
+    public MixPolicy<IntPolicy<0>, IntPolicy<1>>::Data
+{
+    MSpectreMaskIndex(MDefinition* index, MDefinition* length)
+      : MBinaryInstruction(classOpcode, index, length)
+    {
+        setGuard();
+        setMovable();
+        MOZ_ASSERT(index->type() == MIRType::Int32);
+        MOZ_ASSERT(length->type() == MIRType::Int32);
+
+        // Returns the masked index.
+        setResultType(MIRType::Int32);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SpectreMaskIndex)
+    TRIVIAL_NEW_WRAPPERS
+    NAMED_OPERANDS((0, index), (1, length))
+
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+    void computeRange(TempAllocator& alloc) override;
+
+    ALLOW_CLONE(MSpectreMaskIndex)
+};
+
 // Instructions which access an object's elements can either do so on a
 // definition accessing that elements pointer, or on the object itself, if its
 // elements are inline. In the latter case there must be an offset associated
 // with the access.
 static inline bool
 IsValidElementsType(MDefinition* elements, int32_t offsetAdjustment)
 {
     return elements->type() == MIRType::Elements ||
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -210,16 +210,17 @@ namespace jit {
     _(TypedObjectDescr)                                                     \
     _(TypedObjectElements)                                                  \
     _(SetTypedObjectOffset)                                                 \
     _(InitializedLength)                                                    \
     _(SetInitializedLength)                                                 \
     _(Not)                                                                  \
     _(BoundsCheck)                                                          \
     _(BoundsCheckLower)                                                     \
+    _(SpectreMaskIndex)                                                     \
     _(InArray)                                                              \
     _(LoadElement)                                                          \
     _(LoadElementHole)                                                      \
     _(LoadUnboxedScalar)                                                    \
     _(LoadUnboxedObjectOrNull)                                              \
     _(LoadUnboxedString)                                                    \
     _(LoadElementFromState)                                                 \
     _(StoreElement)                                                         \
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -3408,16 +3408,83 @@ MacroAssembler::debugAssertIsObject(cons
 #ifdef DEBUG
     Label ok;
     branchTestObject(Assembler::Equal, val, &ok);
     assumeUnreachable("Expected an object!");
     bind(&ok);
 #endif
 }
 
+template <typename T>
+void
+MacroAssembler::spectreMaskIndexImpl(Register index, const T& length, Register output)
+{
+    // mask := ((index - length) & ~index) >> 31
+    // output := index & mask
+    mov(index, output);
+    sub32(length, output);
+    not32(index);
+    and32(index, output);
+    not32(index); // Restore index register to its original value.
+    rshift32Arithmetic(Imm32(31), output);
+    and32(index, output);
+}
+
+template <typename T>
+void
+MacroAssembler::spectreMaskIndexImpl(int32_t index, const T& length, Register output)
+{
+    // mask := ((index - length) & ~index) >> 31
+    // output := index & mask
+    move32(Imm32(index), output);
+    if (index == 0)
+        return;
+    sub32(length, output);
+    and32(Imm32(~index), output);
+    rshift32Arithmetic(Imm32(31), output);
+    and32(Imm32(index), output);
+}
+
+void
+MacroAssembler::spectreMaskIndex(int32_t index, Register length, Register output)
+{
+    spectreMaskIndexImpl(index, length, output);
+}
+
+void
+MacroAssembler::spectreMaskIndex(int32_t index, const Address& length, Register output)
+{
+    spectreMaskIndexImpl(index, length, output);
+}
+
+void
+MacroAssembler::spectreMaskIndex(Register index, Register length, Register output)
+{
+#if JS_BITS_PER_WORD == 64
+    // On 64-bit platforms, we can use a faster algorithm:
+    //
+    //   mask := (uint64_t(index) - uint64_t(length)) >> 32
+    //   output := index & mask
+    //
+    // mask is 0x11…11 if index < length, 0 otherwise.
+    move32(index, output);
+    subPtr(length, output);
+    rshiftPtr(Imm32(32), output);
+    and32(index, output);
+#else
+    spectreMaskIndexImpl(index, length, output);
+#endif
+}
+
+void
+MacroAssembler::spectreMaskIndex(Register index, const Address& length, Register output)
+{
+    spectreMaskIndexImpl(index, length, output);
+}
+
 namespace js {
 namespace jit {
 
 #ifdef DEBUG
 template <class RegisterType>
 AutoGenericRegisterScope<RegisterType>::AutoGenericRegisterScope(MacroAssembler& masm, RegisterType reg)
   : RegisterType(reg), masm_(masm)
 {
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1889,16 +1889,29 @@ class MacroAssembler : public MacroAssem
     using MacroAssemblerSpecific::store32;
     void store32(const RegisterOrInt32Constant& key, const Address& dest) {
         if (key.isRegister())
             store32(key.reg(), dest);
         else
             store32(Imm32(key.constant()), dest);
     }
 
+  private:
+    template <typename T>
+    void spectreMaskIndexImpl(Register index, const T& length, Register output);
+
+    template <typename T>
+    void spectreMaskIndexImpl(int32_t index, const T& length, Register output);
+
+  public:
+    void spectreMaskIndex(int32_t index, Register length, Register output);
+    void spectreMaskIndex(int32_t index, const Address& length, Register output);
+    void spectreMaskIndex(Register index, Register length, Register output);
+    void spectreMaskIndex(Register index, const Address& length, Register output);
+
     template <typename T>
     void guardedCallPreBarrier(const T& address, MIRType type) {
         Label done;
 
         branchTestNeedsIncrementalBarrier(Assembler::Zero, &done);
 
         if (type == MIRType::Value)
             branchTestGCThing(Assembler::NotEqual, address, &done);
@@ -2320,128 +2333,71 @@ class MacroAssembler : public MacroAssem
                                                      FloatRegister temp, Register output,
                                                      Label* fail, IntConversionBehavior behavior);
     void convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister temp, Register output,
                                   Label* fail, IntConversionBehavior behavior);
 
     //
     // Convenience functions for converting values to int32.
     //
-    void convertValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label* fail,
-                             bool negativeZeroCheck)
-    {
-        convertValueToInt(value, temp, output, fail, negativeZeroCheck
-                          ? IntConversion_NegativeZeroCheck
-                          : IntConversion_Normal);
-    }
     void convertValueToInt32(ValueOperand value, MDefinition* input,
                              FloatRegister temp, Register output, Label* fail,
-                             bool negativeZeroCheck, IntConversionInputKind conversion = IntConversion_Any)
+                             bool negativeZeroCheck,
+                             IntConversionInputKind conversion = IntConversion_Any)
     {
         convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
                           negativeZeroCheck
                           ? IntConversion_NegativeZeroCheck
                           : IntConversion_Normal,
                           conversion);
     }
-    MOZ_MUST_USE bool convertValueToInt32(JSContext* cx, const Value& v, Register output,
-                                          Label* fail, bool negativeZeroCheck)
-    {
-        return convertValueToInt(cx, v, output, fail, negativeZeroCheck
-                                 ? IntConversion_NegativeZeroCheck
-                                 : IntConversion_Normal);
-    }
-    MOZ_MUST_USE bool convertConstantOrRegisterToInt32(JSContext* cx,
-                                                       const ConstantOrRegister& src,
-                                                       FloatRegister temp, Register output,
-                                                       Label* fail, bool negativeZeroCheck)
-    {
-        return convertConstantOrRegisterToInt(cx, src, temp, output, fail, negativeZeroCheck
-                                              ? IntConversion_NegativeZeroCheck
-                                              : IntConversion_Normal);
-    }
-    void convertTypedOrValueToInt32(TypedOrValueRegister src, FloatRegister temp, Register output,
-                                    Label* fail, bool negativeZeroCheck)
-    {
-        convertTypedOrValueToInt(src, temp, output, fail, negativeZeroCheck
-                                 ? IntConversion_NegativeZeroCheck
-                                 : IntConversion_Normal);
-    }
 
     //
     // Convenience functions for truncating values to int32.
     //
-    void truncateValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label* fail) {
-        convertValueToInt(value, temp, output, fail, IntConversion_Truncate);
-    }
     void truncateValueToInt32(ValueOperand value, MDefinition* input,
                               Label* handleStringEntry, Label* handleStringRejoin,
                               Label* truncateDoubleSlow,
                               Register stringReg, FloatRegister temp, Register output, Label* fail)
     {
         convertValueToInt(value, input, handleStringEntry, handleStringRejoin, truncateDoubleSlow,
                           stringReg, temp, output, fail, IntConversion_Truncate);
     }
-    void truncateValueToInt32(ValueOperand value, MDefinition* input,
-                              FloatRegister temp, Register output, Label* fail)
+
+    void truncateValueToInt32(ValueOperand value, FloatRegister temp, Register output, Label* fail)
     {
-        convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
-                          IntConversion_Truncate);
+        truncateValueToInt32(value, nullptr, nullptr, nullptr, nullptr, InvalidReg, temp, output,
+                             fail);
     }
-    MOZ_MUST_USE bool truncateValueToInt32(JSContext* cx, const Value& v, Register output,
-                                           Label* fail) {
-        return convertValueToInt(cx, v, output, fail, IntConversion_Truncate);
-    }
+
     MOZ_MUST_USE bool truncateConstantOrRegisterToInt32(JSContext* cx,
                                                         const ConstantOrRegister& src,
                                                         FloatRegister temp, Register output,
                                                         Label* fail)
     {
         return convertConstantOrRegisterToInt(cx, src, temp, output, fail, IntConversion_Truncate);
     }
-    void truncateTypedOrValueToInt32(TypedOrValueRegister src, FloatRegister temp, Register output,
-                                     Label* fail)
-    {
-        convertTypedOrValueToInt(src, temp, output, fail, IntConversion_Truncate);
-    }
 
     // Convenience functions for clamping values to uint8.
-    void clampValueToUint8(ValueOperand value, FloatRegister temp, Register output, Label* fail) {
-        convertValueToInt(value, temp, output, fail, IntConversion_ClampToUint8);
-    }
     void clampValueToUint8(ValueOperand value, MDefinition* input,
                            Label* handleStringEntry, Label* handleStringRejoin,
                            Register stringReg, FloatRegister temp, Register output, Label* fail)
     {
         convertValueToInt(value, input, handleStringEntry, handleStringRejoin, nullptr,
                           stringReg, temp, output, fail, IntConversion_ClampToUint8);
     }
-    void clampValueToUint8(ValueOperand value, MDefinition* input,
-                           FloatRegister temp, Register output, Label* fail)
-    {
-        convertValueToInt(value, input, nullptr, nullptr, nullptr, InvalidReg, temp, output, fail,
-                          IntConversion_ClampToUint8);
-    }
-    MOZ_MUST_USE bool clampValueToUint8(JSContext* cx, const Value& v, Register output,
-                                        Label* fail) {
-        return convertValueToInt(cx, v, output, fail, IntConversion_ClampToUint8);
-    }
+
     MOZ_MUST_USE bool clampConstantOrRegisterToUint8(JSContext* cx,
                                                      const ConstantOrRegister& src,
                                                      FloatRegister temp, Register output,
                                                      Label* fail)
     {
         return convertConstantOrRegisterToInt(cx, src, temp, output, fail,
                                               IntConversion_ClampToUint8);
     }
-    void clampTypedOrValueToUint8(TypedOrValueRegister src, FloatRegister temp, Register output,
-                                  Label* fail)
-    {
-        convertTypedOrValueToInt(src, temp, output, fail, IntConversion_ClampToUint8);
-    }
 
   public:
     class AfterICSaveLive {
         friend class MacroAssembler;
         explicit AfterICSaveLive(uint32_t initialStack)
 #ifdef JS_DEBUG
           : initialStack(initialStack)
 #endif
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -1856,16 +1856,23 @@ MBoundsCheck::computeRange(TempAllocator
 {
     // Just transfer the incoming index range to the output. The length() is
     // also interesting, but it is handled as a bailout check, and we're
     // computing a pre-bailout range here.
     setRange(new(alloc) Range(index()));
 }
 
 void
+MSpectreMaskIndex::computeRange(TempAllocator& alloc)
+{
+    // Just transfer the incoming index range to the output for now.
+    setRange(new(alloc) Range(index()));
+}
+
+void
 MArrayPush::computeRange(TempAllocator& alloc)
 {
     // MArrayPush returns the new array length.
     setRange(Range::NewUInt32Range(alloc, 0, UINT32_MAX));
 }
 
 void
 MMathFunction::computeRange(TempAllocator& alloc)
--- a/js/src/jit/ScalarReplacement.cpp
+++ b/js/src/jit/ScalarReplacement.cpp
@@ -856,16 +856,18 @@ ObjectMemoryView::visitLoadUnboxedString
     loadOffset(ins, offset);
 }
 
 static bool
 IndexOf(MDefinition* ins, int32_t* res)
 {
     MOZ_ASSERT(ins->isLoadElement() || ins->isStoreElement());
     MDefinition* indexDef = ins->getOperand(1); // ins->index();
+    if (indexDef->isSpectreMaskIndex())
+        indexDef = indexDef->toSpectreMaskIndex()->index();
     if (indexDef->isBoundsCheck())
         indexDef = indexDef->toBoundsCheck()->index();
     if (indexDef->isToInt32())
         indexDef = indexDef->toToInt32()->getOperand(0);
     MConstant* indexDefConst = indexDef->maybeConstantValue();
     if (!indexDefConst || indexDefConst->type() != MIRType::Int32)
         return false;
     *res = indexDefConst->toInt32();
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -5545,16 +5545,33 @@ class LBoundsCheckLower : public LInstru
     MBoundsCheckLower* mir() const {
         return mir_->toBoundsCheckLower();
     }
     const LAllocation* index() {
         return getOperand(0);
     }
 };
 
+class LSpectreMaskIndex : public LInstructionHelper<1, 2, 0>
+{
+  public:
+    LIR_HEADER(SpectreMaskIndex)
+
+    LSpectreMaskIndex(const LAllocation& index, const LAllocation& length) {
+        setOperand(0, index);
+        setOperand(1, length);
+    }
+    const LAllocation* index() {
+        return getOperand(0);
+    }
+    const LAllocation* length() {
+        return getOperand(1);
+    }
+};
+
 // Load a value from a dense array's elements vector. Bail out if it's the hole value.
 class LLoadElementV : public LInstructionHelper<BOX_PIECES, 2, 0>
 {
   public:
     LIR_HEADER(LoadElementV)
 
     LLoadElementV(const LAllocation& elements, const LAllocation& index) {
         setOperand(0, elements);
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -272,16 +272,17 @@
     _(PostWriteBarrierV)            \
     _(PostWriteElementBarrierO)     \
     _(PostWriteElementBarrierV)     \
     _(InitializedLength)            \
     _(SetInitializedLength)         \
     _(BoundsCheck)                  \
     _(BoundsCheckRange)             \
     _(BoundsCheckLower)             \
+    _(SpectreMaskIndex)             \
     _(LoadElementV)                 \
     _(LoadElementT)                 \
     _(LoadElementHole)              \
     _(LoadUnboxedScalar)            \
     _(LoadUnboxedPointerV)          \
     _(LoadUnboxedPointerT)          \
     _(LoadElementFromStateV)        \
     _(UnboxObjectOrNull)            \
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3544,16 +3544,22 @@ static const JSFunctionSpec array_method
     JS_SELF_HOSTED_FN("entries",     "ArrayEntries",     0,0),
     JS_SELF_HOSTED_FN("keys",        "ArrayKeys",        0,0),
 #ifdef NIGHTLY_BUILD
     JS_SELF_HOSTED_FN("values",      "ArrayValues",      0,0),
 #endif
 
     /* ES7 additions */
     JS_SELF_HOSTED_FN("includes",    "ArrayIncludes",    2,0),
+
+#ifdef NIGHTLY_BUILD
+    JS_SELF_HOSTED_FN("flatMap",     "ArrayFlatMap",     1,0),
+    JS_SELF_HOSTED_FN("flatten",     "ArrayFlatten",     0,0),
+#endif
+
     JS_FS_END
 };
 
 static const JSFunctionSpec array_static_methods[] = {
     JS_INLINABLE_FN("isArray",       array_isArray,        1,0, ArrayIsArray),
     JS_SELF_HOSTED_FN("concat",      "ArrayStaticConcat", 2,0),
     JS_SELF_HOSTED_FN("lastIndexOf", "ArrayStaticLastIndexOf", 2,0),
     JS_SELF_HOSTED_FN("indexOf",     "ArrayStaticIndexOf", 2,0),
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -44,16 +44,19 @@ skip-if(!this.hasOwnProperty("SIMD")) in
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1415303
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script non262/SIMD/load-sab-buffer-compat.js
 skip-if(!this.hasOwnProperty("Atomics")) include test262/built-ins/Atomics/jstests.list
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) include test262/built-ins/SharedArrayBuffer/jstests.list
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script test262/built-ins/ArrayBuffer/prototype/byteLength/this-is-sharedarraybuffer.js
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script test262/built-ins/ArrayBuffer/prototype/slice/this-is-sharedarraybuffer.js
 skip-if(!this.hasOwnProperty("SharedArrayBuffer")) script test262/built-ins/TypedArrays/internals/Get/indexed-value-sab.js
 
+# flatMap and flatten are Nightly-only
+skip-if(!Array.prototype.flatMap) include test262/built-ins/Array/prototype/flatMap/jstests.list
+skip-if(!Array.prototype.flatten) include test262/built-ins/Array/prototype/flatten/jstests.list
 
 #####################################
 # Test262 tests disabled on browser #
 #####################################
 
 # Defines a non-configurable property on the WindowProxy object.
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-block-decl-eval-global-existing-global-update.js
 skip-if(!xulRuntime.shell) script test262/annexB/language/eval-code/direct/global-if-decl-else-decl-a-eval-global-existing-global-update.js
--- a/js/src/tests/test262-update.py
+++ b/js/src/tests/test262-update.py
@@ -15,18 +15,16 @@ import shutil
 import sys
 
 from functools import partial
 from itertools import chain, imap
 
 # Skip all tests which use features not supported in SpiderMonkey.
 UNSUPPORTED_FEATURES = set([
                             "tail-call-optimization",
-                            "Array.prototype.flatMap",
-                            "Array.prototype.flatten",
                             "BigInt",
                             "class-fields-public",
                             "class-fields-private",
                             "regexp-dotall",
                             "regexp-lookbehind",
                             "regexp-named-groups",
                             "regexp-unicode-property-escapes",
                        ])
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/array-like-objects.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/array-like-objects.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: >
     array-like objects can be flattened
 includes: [compareArray.js]
 features: [Array.prototype.flatMap]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/bound-function-argument.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/bound-function-argument.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: >
     Behavior when given a bound function
 includes: [compareArray.js]
 features: [Array.prototype.flatMap]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/depth-always-one.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/depth-always-one.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: >
     Behavior when array is depth more than 1
 includes: [compareArray.js]
 features: [Array.prototype.flatMap]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/length.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/length.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: Array.prototype.flatMap.length value and descriptor.
 info: >
   17 ECMAScript Standard Built-in Objects
 includes: [propertyHelper.js]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/name.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/name.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatmap
 description: Array.prototype.flatmap name value and descriptor.
 info: >
   17 ECMAScript Standard Built-in Objects
 includes: [propertyHelper.js]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: >
     non callable argument should throw TypeError Exception
 features: [Array.prototype.flatMap]
 ---*/
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/non-object-ctor-throws.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: >
     Behavior when `constructor` property is neither an Object nor undefined
     - if IsConstructor(C) is false, throw a TypeError exception.
 features: [Array.prototype.flatMap]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/null-undefined-input-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/null-undefined-input-throws.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: >
     null or undefined should throw TypeError Exception
 features: [Array.prototype.flatMap]
 ---*/
--- a/js/src/tests/test262/built-ins/Array/prototype/flatMap/thisArg-argument-strict.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatMap/thisArg-argument-strict.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatMap is not supported
 'use strict';
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatMap
 description: >
     Behavior when thisArg is provided
     Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/array-like-objects.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/array-like-objects.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     array-like objects can be flattened
 includes: [compareArray.js]
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/bound-function-call.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/bound-function-call.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     using bound functions
 includes: [compareArray.js]
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/empty-array-elements.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/empty-array-elements.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     arrays with empty arrays elements
 includes: [compareArray.js]
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/empty-object-elements.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/empty-object-elements.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     arrays with empty object elements
 includes: [compareArray.js]
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/length.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/length.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: Array.prototype.flatten.length value and descriptor.
 info: >
   17 ECMAScript Standard Built-in Objects
 includes: [propertyHelper.js]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/name.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/name.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
   Array.prototype.flatten.name value and descriptor.
 info: >
   17 ECMAScript Standard Built-in Objects
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/non-numeric-depth-should-not-throw.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/non-numeric-depth-should-not-throw.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     if the argument is a string or object, the depthNum is 0
 includes: [compareArray.js]
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/non-object-ctor-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/non-object-ctor-throws.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     Behavior when `constructor` property is neither an Object nor undefined
     - if IsConstructor(C) is false, throw a TypeError exception.
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/null-undefined-elements.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/null-undefined-elements.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     arrays with null, and undefined
 includes: [compareArray.js]
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/null-undefined-input-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/null-undefined-input-throws.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     null or undefined should throw TypeError Exception
 features: [Array.prototype.flatten]
 ---*/
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/positive-infinity.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/positive-infinity.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     if the argument is a positive infinity, the depthNum is max depth of the array
 includes: [compareArray.js]
 features: [Array.prototype.flatten]
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/prop-desc.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/prop-desc.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 es6id: 22.1.3
 description: Property type and descriptor.
 info: >
   17 ECMAScript Standard Built-in Objects
--- a/js/src/tests/test262/built-ins/Array/prototype/flatten/symbol-object-create-null-depth-throws.js
+++ b/js/src/tests/test262/built-ins/Array/prototype/flatten/symbol-object-create-null-depth-throws.js
@@ -1,9 +1,8 @@
-// |reftest| skip -- Array.prototype.flatten is not supported
 // Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flatten
 description: >
     if the argument is a Symbol or Object null, it throws exception
 features: [Array.prototype.flatten]
 ---*/
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -802,18 +802,17 @@ GenerateImportJitExit(MacroAssembler& ma
     }
 #endif
 
     Label oolConvert;
     switch (fi.sig().ret()) {
       case ExprType::Void:
         break;
       case ExprType::I32:
-        masm.convertValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert,
-                                 /* -0 check */ false);
+        masm.truncateValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert);
         break;
       case ExprType::I64:
         masm.breakpoint();
         break;
       case ExprType::F32:
         masm.convertValueToFloat(JSReturnOperand, ReturnFloat32Reg, &oolConvert);
         break;
       case ExprType::F64:
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -202,16 +202,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   gPrototypeProperties['Array'] =
     ["length", "toSource", "toString", "toLocaleString", "join", "reverse", "sort", "push",
       "pop", "shift", "unshift", "splice", "concat", "slice", "lastIndexOf", "indexOf",
       "includes", "forEach", "map", "reduce", "reduceRight", "filter", "some", "every", "find",
       "findIndex", "copyWithin", "fill", Symbol.iterator, Symbol.unscopables, "entries", "keys",
       "constructor"];
   if (isNightlyBuild) {
     gPrototypeProperties['Array'].push("values");
+    gPrototypeProperties['Array'].push("flatten", "flatMap");
   }
   gConstructorProperties['Array'] =
     constructorProps(["join", "reverse", "sort", "push", "pop", "shift",
                       "unshift", "splice", "concat", "slice", "isArray",
                       "lastIndexOf", "indexOf", "forEach", "map", "filter",
                       "every", "some", "reduce", "reduceRight", "from", "of",
                       Symbol.species]);
   for (var c of typedArrayClasses) {
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -11,17 +11,16 @@
 #include "mozilla/ServoStyleSet.h"
 #include "nsAutoPtr.h"
 #include "nscore.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsIContent.h"
-#include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentViewerPrint.h"
 #include "mozilla/dom/BeforeUnloadEvent.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsIPresShell.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
@@ -4322,17 +4321,17 @@ nsDocumentViewer::SetIsPrintingInDocShel
       }
       mTopContainerWhilePrinting = do_GetWeakReference(parentItem);
     } else {
       parentItem = do_QueryReferent(mTopContainerWhilePrinting);
     }
   }
 
   // Check to see if the DocShell's ContentViewer is printing/PP
-  nsCOMPtr<nsIContentViewerContainer> viewerContainer(do_QueryInterface(parentItem));
+  nsCOMPtr<nsIDocShell> viewerContainer = do_QueryInterface(parentItem);
   if (viewerContainer) {
     viewerContainer->SetIsPrinting(aIsPrintingOrPP);
   }
 
   if (!aParentNode) {
     return;
   }
 
--- a/layout/generic/TextDrawTarget.h
+++ b/layout/generic/TextDrawTarget.h
@@ -394,24 +394,58 @@ public:
                    const IntRect &aSourceRect,
                    const IntPoint &aDestination) override {
     MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
   }
 
   void FillRect(const Rect &aRect,
                 const Pattern &aPattern,
                 const DrawOptions &aOptions = DrawOptions()) override {
-    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+    MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR);
+
+    auto rect = mSc.ToRelativeLayoutRect(LayoutDeviceRect::FromUnknownRect(aRect));
+    auto color = wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor);
+    mBuilder.PushRect(rect, mClipRect, mBackfaceVisible, color);
   }
 
   void StrokeRect(const Rect &aRect,
                   const Pattern &aPattern,
                   const StrokeOptions &aStrokeOptions,
                   const DrawOptions &aOptions) override {
-    MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
+    MOZ_RELEASE_ASSERT(aPattern.GetType() == PatternType::COLOR &&
+                       aStrokeOptions.mDashLength == 0);
+
+    wr::Line line;
+    line.wavyLineThickness = 0; // dummy value, unused
+    line.color = wr::ToColorF(static_cast<const ColorPattern&>(aPattern).mColor);
+    line.style = wr::LineStyle::Solid;
+
+    // Top horizontal line
+    LayoutDevicePoint top(aRect.x, aRect.y - aStrokeOptions.mLineWidth / 2);
+    LayoutDeviceSize horiSize(aRect.width, aStrokeOptions.mLineWidth);
+    line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(top, horiSize));
+    line.orientation = wr::LineOrientation::Horizontal;
+    mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
+
+    // Bottom horizontal line
+    LayoutDevicePoint bottom(aRect.x, aRect.YMost() - aStrokeOptions.mLineWidth / 2);
+    line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(bottom, horiSize));
+    mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
+
+    // Left vertical line
+    LayoutDevicePoint left(aRect.x + aStrokeOptions.mLineWidth / 2, aRect.y + aStrokeOptions.mLineWidth / 2);
+    LayoutDeviceSize vertSize(aStrokeOptions.mLineWidth, aRect.height - aStrokeOptions.mLineWidth);
+    line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(left, vertSize));
+    line.orientation = wr::LineOrientation::Vertical;
+    mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
+
+    // Right vertical line
+    LayoutDevicePoint right(aRect.XMost() - aStrokeOptions.mLineWidth / 2, aRect.y + aStrokeOptions.mLineWidth / 2);
+    line.bounds = mSc.ToRelativeLayoutRect(LayoutDeviceRect(right, vertSize));
+    mBuilder.PushLine(mClipRect, mBackfaceVisible, line);
   }
 
   void StrokeLine(const Point &aStart,
                   const Point &aEnd,
                   const Pattern &aPattern,
                   const StrokeOptions &aStrokeOptions,
                   const DrawOptions &aOptions) override {
     MOZ_CRASH("TextDrawTarget: Method shouldn't be called");
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -4527,22 +4527,27 @@ nsGridContainerFrame::Tracks::FindUsedFl
   // a flex track with its max-content contribution as 'space to fill'
   for (; !iter.AtEnd(); iter.Next()) {
     const GridItemInfo& item = aGridItems[iter.ItemIndex()];
     if (item.mState[mAxis] & ItemState::eIsFlexing) {
       // XXX optimize: bug 1194446
       auto pb = Some(aState.PercentageBasisFor(mAxis, item));
       nscoord spaceToFill = ContentContribution(item, aState, rc, wm, mAxis, pb,
                                                 nsLayoutUtils::PREF_ISIZE);
+      const LineRange& range =
+        mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
+      MOZ_ASSERT(range.Extent() >= 1);
+      const auto spannedGaps = range.Extent() - 1;
+      if (spannedGaps > 0) {
+        spaceToFill -= mGridGap * spannedGaps;
+      }
       if (spaceToFill <= 0) {
         continue;
       }
       // ... and all its spanned tracks as input.
-      const LineRange& range =
-        mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
       nsTArray<uint32_t> itemFlexTracks;
       for (uint32_t i = range.mStart, end = range.mEnd; i < end; ++i) {
         if (mSizes[i].mState & TrackSize::eFlexMaxSizing) {
           itemFlexTracks.AppendElement(i);
         }
       }
       float itemFr =
         FindFrUnitSize(range, itemFlexTracks, aFunctions, spaceToFill);
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -308,53 +308,88 @@ void UpdateASR(nsDisplayItem* aItem,
                                      aContainerASR.value()));
 }
 
 /**
  * Takes two display lists and merges them into an output list.
  *
  * The basic algorithm is:
  *
- * For-each item in the new list:
+ * For-each item i in the new list:
  *     If the item has a matching item in the old list:
- *         Remove items from the bottom of the old list until we reach the matching item:
+ *         Remove items from the start of the old list up until we reach an item that also exists in the new list (leaving the matched item in place):
  *             Add valid items to the merged list, destroy invalid items.
- *         Destroy the matching item from the old list.
- *     Add the item from the new list into the merged list.
- * Add all remaining valid items from the old list into the merged list.
+ *     Add i into the merged list.
+ *     If the start of the old list matches i, remove and destroy it, otherwise mark the old version of i as used.
+ * Add all remaining valid items from the old list into the merged list, skipping over (and destroying) any that are marked as used.
  *
  * If any item has a child display list, then we recurse into the merge
  * algorithm once we match up the new/old versions (if present).
  *
  * Example 1:
  *
  * Old List: A,B,C,D
- * New List: A,D
+ * Modified List: A,D
  * Invalidations: C,D
  *
  * We first match the A items, and add the new one to the merged list.
  * We then match the D items, copy B into the merged list, but not C
  * (since it's invalid). We then add the new D to the list and we're
  * finished.
  *
  * Merged List: A,B,D
  *
- * Example 2:
+ * Example 2 (layout/reftests/retained-dl-zindex-1.html):
  *
  * Old List: A, B
- * New List, B, A
+ * Modified List: B, A
+ * Invalidations: A
+ *
+ * In this example A has been explicitly moved to the back.
+ *
+ * We match the B items, but don't copy A since it's invalid, and then add the
+ * new B into the merged list. We then add A, and we're done.
+ *
+ * Merged List: B, A
+ *
+ * Example 3:
+ *
+ * Old List: A, B
+ * Modified List: B, A
  * Invalidations: -
  *
  * This can happen because a prior merge might have changed the ordering
  * for non-intersecting items.
  *
  * We match the B items, but don't copy A since it's also present in the new list
  * and then add the new B into the merged list. We then add A, and we're done.
  *
  * Merged List: B, A
+ *
+ * Example 4 (layout/reftests/retained-dl-zindex-2.html):
+ *
+ * Element A has two elements covering it (B and C), that don't intersect each
+ * other. We then move C to the back.
+ *
+ * The correct initial ordering has B and C after A, in any order.
+ *
+ * Old List: A, B, C
+ * Modified List: C, A
+ * Invalidations: C
+ *
+ * We match the C items, but don't add anything from the old list because A is present
+ * in both lists. We add C to the merged list, and mark the old version of C as reused.
+ *
+ * We then match A, add the new version the merged list and delete the old version.
+ *
+ * We then process the remainder of the old list, B is added (since it is valid,
+ * and hasn't been mark as reused), C is destroyed since it's marked as reused and
+ * is already present in the merged list.
+ *
+ * Merged List: C, A, B
  */
 void
 RetainedDisplayListBuilder::MergeDisplayLists(nsDisplayList* aNewList,
                                               nsDisplayList* aOldList,
                                               nsDisplayList* aOutList,
                                               Maybe<const ActiveScrolledRoot*>& aOutContainerASR)
 {
   nsDisplayList merged;
@@ -409,49 +444,59 @@ RetainedDisplayListBuilder::MergeDisplay
     newListLookup.Put({ i->Frame(), i->GetPerFrameKey() }, i);
   }
 
   while (nsDisplayItem* newItem = aNewList->RemoveBottom()) {
     if (nsDisplayItem* oldItem = oldListLookup.Get({ newItem->Frame(), newItem->GetPerFrameKey() })) {
       // The new item has a matching counterpart in the old list that we haven't yet reached,
       // so copy all valid items from the old list into the merged list until we get to the
       // matched item.
-      if (!oldItem->IsReused()) {
-        nsDisplayItem* old = nullptr;
-        while ((old = aOldList->RemoveBottom()) && !IsSameItem(newItem, old)) {
-          if (IsAnyAncestorModified(old->FrameForInvalidation())) {
-            // The old item is invalid, discard it.
-            oldListLookup.Remove({ old->Frame(), old->GetPerFrameKey() });
-            old->Destroy(&mBuilder);
-          } else if (newListLookup.Get({ old->Frame(), old->GetPerFrameKey() })) {
-            // The old item is also in the new list, but we haven't got to it yet.
-            // Mark that we've found it, and we'll deal with it when we get to the new
-            // entry.
-            old->SetReused(true);
-          } else {
-            // Recurse into the child list (without a matching new list) to
-            // ensure that we find and remove any invalidated items.
-            if (old->GetChildren()) {
-              nsDisplayList empty;
-              Maybe<const ActiveScrolledRoot*> containerASRForChildren;
-              MergeDisplayLists(&empty, old->GetChildren(),
-                                old->GetChildren(), containerASRForChildren);
-              UpdateASR(old, containerASRForChildren);
-              old->UpdateBounds(&mBuilder);
-            }
-            ReuseItem(old);
+      nsDisplayItem* old = nullptr;
+      while ((old = aOldList->GetBottom()) && old != oldItem) {
+        if (IsAnyAncestorModified(old->FrameForInvalidation())) {
+          // The old item is invalid, discard it.
+          oldListLookup.Remove({ old->Frame(), old->GetPerFrameKey() });
+          aOldList->RemoveBottom();
+          old->Destroy(&mBuilder);
+        } else if (newListLookup.Get({ old->Frame(), old->GetPerFrameKey() })) {
+          // This old item is also in the new list, but we haven't got to it yet.
+          // Stop now, and we'll deal with it when we get to the new entry.
+          break;
+        } else {
+          // Recurse into the child list (without a matching new list) to
+          // ensure that we find and remove any invalidated items.
+          if (old->GetChildren()) {
+            nsDisplayList empty;
+            Maybe<const ActiveScrolledRoot*> containerASRForChildren;
+            MergeDisplayLists(&empty, old->GetChildren(),
+                              old->GetChildren(), containerASRForChildren);
+            UpdateASR(old, containerASRForChildren);
+            old->UpdateBounds(&mBuilder);
           }
+          aOldList->RemoveBottom();
+          ReuseItem(old);
         }
-        MOZ_ASSERT(old && IsSameItem(newItem, old));
-        MOZ_ASSERT(old == oldItem);
+      }
+      bool destroy = false;
+      if (old == oldItem) {
+        // If we advanced the old list until the matching item then we can pop
+        // the matching item off the old list and make sure we clean it up.
+        aOldList->RemoveBottom();
+        destroy = true;
+      } else {
+        // If we didn't get to the matching item, then mark the old item
+        // as being reused (since we're adding the new version to the new
+        // list now) so that we don't add it twice at the end.
+        oldItem->SetReused(true);
       }
 
       // Recursively merge any child lists, destroy the old item and add
       // the new one to the list.
-      if (oldItem->GetType() == DisplayItemType::TYPE_LAYER_EVENT_REGIONS &&
+      if (destroy &&
+          oldItem->GetType() == DisplayItemType::TYPE_LAYER_EVENT_REGIONS &&
           !IsAnyAncestorModified(oldItem->FrameForInvalidation())) {
         // Event regions items don't have anything interesting other than
         // the lists of regions and frames, so we have no need to use the
         // newer item. Always use the old item instead since we assume it's
         // likely to have the bigger lists and merging will be quicker.
         MergeLayerEventRegions(oldItem, newItem);
         ReuseItem(oldItem);
         newItem->Destroy(&mBuilder);
@@ -461,29 +506,32 @@ RetainedDisplayListBuilder::MergeDisplay
           MOZ_ASSERT(newItem->GetChildren());
           Maybe<const ActiveScrolledRoot*> containerASRForChildren;
           MergeDisplayLists(newItem->GetChildren(), oldItem->GetChildren(),
                             newItem->GetChildren(), containerASRForChildren);
           UpdateASR(newItem, containerASRForChildren);
           newItem->UpdateBounds(&mBuilder);
         }
 
-        oldItem->Destroy(&mBuilder);
+        if (destroy) {
+          oldItem->Destroy(&mBuilder);
+        }
         UseItem(newItem);
       }
     } else {
       // If there was no matching item in the old list, then we only need to
       // add the new item to the merged list.
       UseItem(newItem);
     }
   }
 
   // Reuse the remaining valid items from the old display list.
   while (nsDisplayItem* old = aOldList->RemoveBottom()) {
-    if (!IsAnyAncestorModified(old->FrameForInvalidation())) {
+    if (!IsAnyAncestorModified(old->FrameForInvalidation()) &&
+        !old->IsReused()) {
       if (old->GetChildren()) {
         // We are calling MergeDisplayLists() to ensure that the display items
         // with modified or deleted children will be correctly handled.
         // Passing an empty new display list as an argument skips the merging
         // loop above and jumps back here.
         nsDisplayList empty;
         Maybe<const ActiveScrolledRoot*> containerASRForChildren;
 
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -101,17 +101,16 @@ static const char kPrintingPromptService
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIBaseWindow.h"
 #include "nsILayoutHistoryState.h"
 #include "nsFrameManager.h"
 #include "mozilla/ReflowInput.h"
-#include "nsIContentViewerContainer.h"
 #include "nsIContentViewer.h"
 #include "nsIDocumentViewerPrint.h"
 
 #include "nsFocusManager.h"
 #include "nsRange.h"
 #include "nsCDefaultURIFixup.h"
 #include "nsIURIFixup.h"
 #include "mozilla/dom/Element.h"
--- a/layout/reftests/css-grid/grid-column-gap-002-ref.html
+++ b/layout/reftests/css-grid/grid-column-gap-002-ref.html
@@ -13,17 +13,17 @@ body,html { color:black; background:whit
 .grid {
   display: block;
   border: dashed blue;
   float: left;
   clear: left;
 }
 
 .c1 { grid-column: 1 / span 2; min-width:40px; }
-.r1 { grid-column: 2 / span 3; min-width:70px; margin-left:41px; }
+.r1 { grid-column: 2 / span 3; min-width:70px; margin-left:40px; }
 .c3 { grid-column: 3 / span 1; min-width:0; margin-left:138px; }
 
 span {
   display: block;
   float: left;
   clear: left;
   background: gray;
   border-style: solid;
@@ -34,31 +34,31 @@ span {
 }
 
 x { display:inline-block; width:10px; height:18px; }
   </style>
 </head>
 <body>
 
 <div class="grid">
-<span class="c1" style="width:43px"><x></x></span>
-<span class="r1" style="width:79px"><x></x></span>
+<span class="c1" style="width:40px"><x></x></span>
+<span class="r1" style="width:74px"><x></x></span>
 </div>
 
 <div class="grid">
 <span class="c1" style="width:49px"><x></x></span>
 <span class="r1" style="margin-left:44px; width:88px"><x></x></span>
 <span class="c3" style="margin-left:83px; "><x></x></span>
 </div>
 
 <div class="grid">
-<span class="c1" style="width:43px"><x></x></span>
-<span class="r1" style="width:79px"><x></x></span>
-<span class="r1" style="width:79px"><x></x></span>
-<span class="r1" style="width:79px"><x></x></span>
+<span class="c1" style="width:40px"><x></x></span>
+<span class="r1" style="width:74px"><x></x></span>
+<span class="r1" style="width:74px"><x></x></span>
+<span class="r1" style="width:74px"><x></x></span>
 </div>
 <div class="grid" style="">
 <span class="c1" style="width:413px"><x></x></span>
 <span class="r1" style="margin-left:44px; width:452px"><x></x></span>
 <span class="c3" style="margin-left:447px;"><x></x></span>
 </div>
 
 <div class="grid" style="width:500px;">
@@ -71,20 +71,20 @@ x { display:inline-block; width:10px; he
 <div class="grid" style="">
 <span class="c1" style="width:513px"><x></x></span>
 <span class="r1" style="margin-left:44px; width:552px"><x></x></span>
 <span class="c3" style="margin-left:547px;"><x></x></span>
 </div>
 
 <div class="grid">
 <span class="c1" style="width:100px"><x></x></span>
-<span class="r1" style="margin-left:117px; margin-right:11px; width:300px"><x></x></span>
-<span class="c3" style="margin-left:228px; width:83px"><x></x></span>
+<span class="r1" style="margin-left:115px; margin-right:5px; width:300px"><x></x></span>
+<span class="c3" style="margin-left:224px; width:81px"><x></x></span>
 </div>
 
 <div class="grid">
 <span class="c1" style="width:100px; border-sizing:border-box"><x></x></span>
-<span class="r1" style="margin-left:117px; margin-right:11px; width:300px; border-sizing:border-box"><x></x></span>
-<span class="c3" style="margin-left:228px; width:83px"><x></x></span>
+<span class="r1" style="margin-left:115px; margin-right:5px; width:300px; border-sizing:border-box"><x></x></span>
+<span class="c3" style="margin-left:224px; width:81px"><x></x></span>
 </div>
 
 </body>
 </html>
--- a/layout/reftests/display-list/reftest.list
+++ b/layout/reftests/display-list/reftest.list
@@ -3,14 +3,16 @@ skip-if(!retainedDisplayList) == retaine
 skip-if(!retainedDisplayList) == retained-dl-frame-created-1.html retained-dl-style-change-1-ref.html
 skip-if(!retainedDisplayList) == retained-dl-style-change-stacking-context-1.html retained-dl-style-change-stacking-context-1-ref.html
 skip-if(!retainedDisplayList||!asyncPan) == retained-dl-async-scrolled-1.html retained-dl-async-scrolled-1-ref.html
 skip-if(!retainedDisplayList) == retained-dl-remove-for-ancestor-change-1.html retained-dl-remove-for-ancestor-change-1-ref.html
 skip-if(!retainedDisplayList) == retained-dl-scroll-out-of-view-1.html retained-dl-scroll-out-of-view-1-ref.html
 skip-if(!retainedDisplayList) == retained-dl-displayport-1.html retained-dl-displayport-1-ref.html
 skip-if(!retainedDisplayList) == retained-dl-prerender-transform-1.html retained-dl-prerender-transform-1-ref.html
 == retained-dl-wrap-list.html retained-dl-wrap-list-ref.html
+== retained-dl-zindex-1.html retained-dl-zindex-1-ref.html
+== retained-dl-zindex-2.html retained-dl-zindex-2-ref.html
 fuzzy(1,235200) == 1413073.html 1413073-ref.html
 == 1416291.html 1416291-ref.html
 == 1417601-1.html 1417601-1-ref.html
 == 1418945-1.html 1418945-1-ref.html
 skip-if(Android) == 1428993-1.html 1428993-1-ref.html
 == 1428993-2.html 1428993-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/retained-dl-zindex-1-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div {
+  width: 200px;
+  height: 200px;
+  position:relative;
+  will-change: transform;
+}
+#one {
+  top:120px;
+  background-color:blue;
+}
+#two {
+  top: -200px;
+  left: 100px;
+  background-color:green;
+  z-index: -1;
+}
+</style>
+</head>
+<body>
+  <div id="one"></div>
+  <div id="two"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/retained-dl-zindex-1.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<style>
+div {
+  width: 200px;
+  height: 200px;
+  position:relative;
+  will-change: transform;
+}
+#one {
+  top:120px;
+  background-color:blue;
+}
+#two {
+  top: -200px;
+  left: 100px;
+  background-color:green;
+  z-index: 1;
+}
+</style>
+</head>
+<body>
+  <div id="one"></div>
+  <div id="two"></div>
+</body>
+<script>
+function doTest() {
+  document.getElementById("two").style.zIndex = -1;
+  document.documentElement.removeAttribute("class");
+}
+
+window.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/retained-dl-zindex-2-ref.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div {
+  width: 200px;
+  height: 200px;
+  position:relative;
+  will-change:transform;
+}
+#one {
+  top:120px;
+  background-color:blue;
+}
+#two {
+  top: -200px;
+  left: 100px;
+  background-color:green;
+}
+#three {
+  top: -180px;
+  left: 100px;
+  background-color:red;
+  z-index: -1;
+}
+</style>
+</head>
+<body>
+  <div id="one"></div>
+  <div id="two"></div>
+  <div id="three"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/display-list/retained-dl-zindex-2.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+<style>
+div {
+  width: 200px;
+  height: 200px;
+  position:relative;
+  will-change:transform;
+}
+#one {
+  top:120px;
+  background-color:blue;
+}
+#two {
+  top: -200px;
+  left: 100px;
+  background-color:green;
+}
+#three {
+  top: -180px;
+  left: 100px;
+  background-color:red;
+  z-index: 1;
+}
+</style>
+</head>
+<body>
+  <div id="one"></div>
+  <div id="two"></div>
+  <div id="three"></div>
+</body>
+<script>
+function doTest() {
+  document.getElementById("three").style.zIndex = -1;
+  document.documentElement.removeAttribute("class");
+}
+
+window.addEventListener("MozReftestInvalidate", doTest);
+</script>
+</html>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1284,24 +1284,20 @@ pref("dom.storage.testing", false);
 pref("dom.send_after_paint_to_content", false);
 
 // Timeout clamp in ms for timeouts we clamp
 pref("dom.min_timeout_value", 4);
 // And for background windows
 pref("dom.min_background_timeout_value", 1000);
 // Timeout clamp in ms for tracking timeouts we clamp
 // Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect.
-#ifdef NIGHTLY_BUILD
-pref("dom.min_tracking_timeout_value", 10000);
-#else
 pref("dom.min_tracking_timeout_value", 4);
-#endif
 // And for background windows
 // Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect.
-pref("dom.min_tracking_background_timeout_value", 10000);
+pref("dom.min_tracking_background_timeout_value", 4);
 // Delay in ms from document load until we start throttling background timeouts.
 pref("dom.timeout.throttling_delay", 30000);
 
 // Time (in ms) that it takes to regenerate 1ms.
 pref("dom.timeout.background_budget_regeneration_rate", 100);
 // Maximum value (in ms) for the background budget. Only valid for
 // values greater than 0.
 pref("dom.timeout.background_throttling_max_budget", 50);
--- a/netwerk/cache2/CacheFileMetadata.cpp
+++ b/netwerk/cache2/CacheFileMetadata.cpp
@@ -268,18 +268,20 @@ CacheFileMetadata::WriteMetadata(uint32_
     p += mHashCount * sizeof(CacheHash::Hash16_t);
   }
   mMetaHdr.WriteToBuf(p);
   p += sizeof(CacheFileMetadataHeader);
   memcpy(p, mKey.get(), mKey.Length());
   p += mKey.Length();
   *p = 0;
   p++;
-  memcpy(p, mBuf, mElementsSize);
-  p += mElementsSize;
+  if (mElementsSize) {
+    memcpy(p, mBuf, mElementsSize);
+    p += mElementsSize;
+  }
 
   CacheHash::Hash32_t hash;
   hash = CacheHash::Hash(mWriteBuf + sizeof(uint32_t),
                          p - mWriteBuf - sizeof(uint32_t));
   NetworkEndian::writeUint32(mWriteBuf, hash);
 
   NetworkEndian::writeUint32(p, aOffset);
   p += sizeof(uint32_t);
--- a/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp
+++ b/security/manager/ssl/tests/unit/tlsserver/lib/OCSPCommon.cpp
@@ -2,46 +2,38 @@
  * 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 "OCSPCommon.h"
 
 #include <stdio.h>
 
 #include "pkixtestutil.h"
+#include "pkixtestnss.h"
 #include "TLSServer.h"
 #include "secder.h"
 #include "secerr.h"
 
-namespace mozilla { namespace pkix { namespace test {
-
-// Ownership of privateKey is transfered.
-TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
-                               const SECKEYPublicKey& publicKey,
-                               SECKEYPrivateKey* privateKey);
-
-} } } // namespace mozilla::pkix::test
-
 using namespace mozilla;
 using namespace mozilla::pkix;
 using namespace mozilla::pkix::test;
 using namespace mozilla::test;
 
 static TestKeyPair*
 CreateTestKeyPairFromCert(const UniqueCERTCertificate& cert)
 {
-  UniqueSECKEYPrivateKey privateKey(PK11_FindKeyByAnyCert(cert.get(), nullptr));
+  ScopedSECKEYPrivateKey privateKey(PK11_FindKeyByAnyCert(cert.get(), nullptr));
   if (!privateKey) {
     return nullptr;
   }
-  UniqueSECKEYPublicKey publicKey(CERT_ExtractPublicKey(cert.get()));
+  ScopedSECKEYPublicKey publicKey(CERT_ExtractPublicKey(cert.get()));
   if (!publicKey) {
     return nullptr;
   }
-  return CreateTestKeyPair(RSA_PKCS1(), *publicKey.get(), privateKey.release());
+  return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
 }
 
 SECItemArray*
 GetOCSPResponseForType(OCSPResponseType aORT, const UniqueCERTCertificate& aCert,
                        const UniquePLArenaPool& aArena,
                        const char* aAdditionalCertName, time_t aThisUpdateSkew)
 {
   MOZ_ASSERT(aArena);
--- a/security/nss.symbols
+++ b/security/nss.symbols
@@ -385,16 +385,17 @@ PK11_GetTokenName
 PK11_GetTokenURI
 PK11_HasAttributeSet
 PK11_HashBuf
 PK11_HasRootCerts
 PK11_ImportCert
 PK11_ImportCertForKey
 PK11_ImportCRL
 PK11_ImportDERPrivateKeyInfoAndReturnKey
+PK11_ImportEncryptedPrivateKeyInfoAndReturnKey
 PK11_ImportPublicKey
 PK11_ImportSymKey
 PK11_InitPin
 PK11_IsDisabled
 PK11_IsFIPS
 PK11_IsFriendly
 PK11_IsHW
 PK11_IsInternal
--- a/security/pkix/test/lib/pkixtestnss.cpp
+++ b/security/pkix/test/lib/pkixtestnss.cpp
@@ -18,16 +18,17 @@
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "pkixtestutil.h"
+#include "pkixtestnss.h"
 
 #include <limits>
 
 #include "cryptohi.h"
 #include "keyhi.h"
 #include "nss.h"
 #include "pk11pqg.h"
 #include "pk11pub.h"
@@ -37,27 +38,28 @@
 #include "prinit.h"
 #include "secerr.h"
 #include "secitem.h"
 
 namespace mozilla { namespace pkix { namespace test {
 
 namespace {
 
-typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
-  ScopedSECKEYPublicKey;
-typedef ScopedPtr<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>
-  ScopedSECKEYPrivateKey;
-
 inline void
 SECITEM_FreeItem_true(SECItem* item)
 {
   SECITEM_FreeItem(item, true);
 }
 
+inline void
+SECKEY_DestroyEncryptedPrivateKeyInfo_true(SECKEYEncryptedPrivateKeyInfo* e)
+{
+  SECKEY_DestroyEncryptedPrivateKeyInfo(e, true);
+}
+
 typedef mozilla::pkix::ScopedPtr<SECItem, SECITEM_FreeItem_true> ScopedSECItem;
 
 TestKeyPair* GenerateKeyPairInner();
 
 void
 InitNSSIfNeeded()
 {
   if (NSS_NoDB_Init(nullptr) != SECSuccess) {
@@ -73,22 +75,25 @@ InitReusedKeyPair()
   InitNSSIfNeeded();
   reusedKeyPair.reset(GenerateKeyPairInner());
   return reusedKeyPair ? PR_SUCCESS : PR_FAILURE;
 }
 
 class NSSTestKeyPair final : public TestKeyPair
 {
 public:
-  // NSSTestKeyPair takes ownership of privateKey.
   NSSTestKeyPair(const TestPublicKeyAlgorithm& publicKeyAlg,
                  const ByteString& spk,
-                 SECKEYPrivateKey* privateKey)
+                 const ByteString& encryptedPrivateKey,
+                 const ByteString& encryptionAlgorithm,
+                 const ByteString& encryptionParams)
     : TestKeyPair(publicKeyAlg, spk)
-    , privateKey(privateKey)
+    , encryptedPrivateKey(encryptedPrivateKey)
+    , encryptionAlgorithm(encryptionAlgorithm)
+    , encryptionParams(encryptionParams)
   {
   }
 
   Result SignData(const ByteString& tbs,
                   const TestSignatureAlgorithm& signatureAlgorithm,
                   /*out*/ ByteString& signature) const override
   {
     SECOidTag oidTag;
@@ -116,63 +121,127 @@ public:
           oidTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
           break;
         MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
       }
     } else {
       abort();
     }
 
+    ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
+    if (!slot) {
+      return MapPRErrorCodeToResult(PR_GetError());
+    }
+    SECItem encryptedPrivateKeyInfoItem = {
+      siBuffer,
+      const_cast<uint8_t*>(encryptedPrivateKey.data()),
+      static_cast<unsigned int>(encryptedPrivateKey.length())
+    };
+    SECItem encryptionAlgorithmItem = {
+      siBuffer,
+      const_cast<uint8_t*>(encryptionAlgorithm.data()),
+      static_cast<unsigned int>(encryptionAlgorithm.length())
+    };
+    SECItem encryptionParamsItem = {
+      siBuffer,
+      const_cast<uint8_t*>(encryptionParams.data()),
+      static_cast<unsigned int>(encryptionParams.length())
+    };
+    SECKEYEncryptedPrivateKeyInfo encryptedPrivateKeyInfo = {
+      nullptr,
+      { encryptionAlgorithmItem, encryptionParamsItem },
+      encryptedPrivateKeyInfoItem
+    };
+    SECItem passwordItem = { siBuffer, nullptr, 0 };
+    SECItem publicValueItem = {
+      siBuffer,
+      const_cast<uint8_t*>(subjectPublicKey.data()),
+      static_cast<unsigned int>(subjectPublicKey.length())
+    };
+    SECKEYPrivateKey* privateKey;
+    // This should always be an RSA key (we'll have aborted above if we're not
+    // doing an RSA signature).
+    if (PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(
+          slot.get(), &encryptedPrivateKeyInfo, &passwordItem, nullptr,
+          &publicValueItem, false, false, rsaKey, KU_ALL, &privateKey,
+          nullptr) != SECSuccess) {
+      return MapPRErrorCodeToResult(PR_GetError());
+    }
+    ScopedSECKEYPrivateKey scopedPrivateKey(privateKey);
     SECItem signatureItem;
     if (SEC_SignData(&signatureItem, tbs.data(),
                      static_cast<int>(tbs.length()),
-                     privateKey.get(), oidTag) != SECSuccess) {
+                     scopedPrivateKey.get(), oidTag) != SECSuccess) {
       return MapPRErrorCodeToResult(PR_GetError());
     }
     signature.assign(signatureItem.data, signatureItem.len);
     SECITEM_FreeItem(&signatureItem, false);
     return Success;
   }
 
   TestKeyPair* Clone() const override
   {
-    ScopedSECKEYPrivateKey
-      privateKeyCopy(SECKEY_CopyPrivateKey(privateKey.get()));
-    if (!privateKeyCopy) {
-      return nullptr;
-    }
     return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
                                              subjectPublicKey,
-                                             privateKeyCopy.release());
+                                             encryptedPrivateKey,
+                                             encryptionAlgorithm,
+                                             encryptionParams);
   }
 
 private:
-  ScopedSECKEYPrivateKey privateKey;
+  const ByteString encryptedPrivateKey;
+  const ByteString encryptionAlgorithm;
+  const ByteString encryptionParams;
 };
 
 } // namespace
 
 // This private function is also used by Gecko's PSM test framework
 // (OCSPCommon.cpp).
-//
-// Ownership of privateKey is transfered.
 TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
-                               const SECKEYPublicKey& publicKey,
-                               SECKEYPrivateKey* privateKey)
+                               const ScopedSECKEYPublicKey& publicKey,
+                               const ScopedSECKEYPrivateKey& privateKey)
 {
   ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
-    spki(SECKEY_CreateSubjectPublicKeyInfo(&publicKey));
+    spki(SECKEY_CreateSubjectPublicKeyInfo(publicKey.get()));
   if (!spki) {
     return nullptr;
   }
   SECItem spkDER = spki->subjectPublicKey;
   DER_ConvertBitString(&spkDER); // bits to bytes
-  return new (std::nothrow) NSSTestKeyPair(publicKeyAlg,
-                                           ByteString(spkDER.data, spkDER.len),
-                                           privateKey);
+  ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
+  if (!slot) {
+    return nullptr;
+  }
+  // Because NSSTestKeyPair isn't tracked by XPCOM and won't otherwise be aware
+  // of shutdown, we don't have a way to release NSS resources at the
+  // appropriate time. To work around this, NSSTestKeyPair doesn't hold on to
+  // NSS resources. Instead, we export the generated private key part as an
+  // encrypted blob (with an empty password and fairly lame encryption). When we
+  // need to use it (e.g. to sign something), we decrypt it and create a
+  // temporary key object.
+  SECItem passwordItem = { siBuffer, nullptr, 0 };
+  ScopedPtr<SECKEYEncryptedPrivateKeyInfo,
+            SECKEY_DestroyEncryptedPrivateKeyInfo_true> encryptedPrivateKey(
+    PK11_ExportEncryptedPrivKeyInfo(
+      slot.get(), SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
+      &passwordItem, privateKey.get(), 1, nullptr));
+  if (!encryptedPrivateKey) {
+    return nullptr;
+  }
+
+  return new (std::nothrow) NSSTestKeyPair(
+    publicKeyAlg,
+    ByteString(spkDER.data, spkDER.len),
+    ByteString(encryptedPrivateKey->encryptedData.data,
+               encryptedPrivateKey->encryptedData.len),
+    ByteString(encryptedPrivateKey->algorithm.algorithm.data,
+               encryptedPrivateKey->algorithm.algorithm.len),
+    ByteString(encryptedPrivateKey->algorithm.parameters.data,
+               encryptedPrivateKey->algorithm.parameters.len));
 }
 
 namespace {
 
 TestKeyPair*
 GenerateKeyPairInner()
 {
   ScopedPtr<PK11SlotInfo, PK11_FreeSlot> slot(PK11_GetInternalSlot());
@@ -189,17 +258,17 @@ GenerateKeyPairInner()
     params.pe = 3;
     SECKEYPublicKey* publicKeyTemp = nullptr;
     ScopedSECKEYPrivateKey
       privateKey(PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN,
                                       &params, &publicKeyTemp, false, true,
                                       nullptr));
     ScopedSECKEYPublicKey publicKey(publicKeyTemp);
     if (privateKey) {
-      return CreateTestKeyPair(RSA_PKCS1(), *publicKey, privateKey.release());
+      return CreateTestKeyPair(RSA_PKCS1(), publicKey, privateKey);
     }
 
     assert(!publicKeyTemp);
 
     if (PR_GetError() != SEC_ERROR_PKCS11_FUNCTION_FAILED) {
       break;
     }
 
@@ -270,17 +339,17 @@ GenerateDSSKeyPair()
   ScopedSECKEYPrivateKey
     privateKey(PK11_GenerateKeyPair(slot.get(), CKM_DSA_KEY_PAIR_GEN,
                                     const_cast<PQGParams*>(&PARAMS),
                                     &publicKeyTemp, false, true, nullptr));
   if (!privateKey) {
     return nullptr;
   }
   ScopedSECKEYPublicKey publicKey(publicKeyTemp);
-  return CreateTestKeyPair(DSS(), *publicKey, privateKey.release());
+  return CreateTestKeyPair(DSS(), publicKey, privateKey);
 }
 
 Result
 TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
                             Input subjectPublicKeyInfo)
 {
   InitNSSIfNeeded();
   return VerifyECDSASignedDigestNSS(signedDigest, subjectPublicKeyInfo,
new file mode 100644
--- /dev/null
+++ b/security/pkix/test/lib/pkixtestnss.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* 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/.
+ */
+/* Copyright 2018 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file provides some implementation-specific test utilities. This is only
+// necessary because some PSM xpcshell test utilities overlap in functionality
+// with these test utilities, so the underlying implementation is shared.
+
+#ifndef mozilla_pkix_test_pkixtestnss_h
+#define mozilla_pkix_test_pkixtestnss_h
+
+#include "keyhi.h"
+#include "keythi.h"
+#include "pkixtestutil.h"
+
+namespace mozilla { namespace pkix { namespace test {
+
+typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey>
+  ScopedSECKEYPublicKey;
+typedef ScopedPtr<SECKEYPrivateKey, SECKEY_DestroyPrivateKey>
+  ScopedSECKEYPrivateKey;
+
+TestKeyPair* CreateTestKeyPair(const TestPublicKeyAlgorithm publicKeyAlg,
+                               const ScopedSECKEYPublicKey& publicKey,
+                               const ScopedSECKEYPrivateKey& privateKey);
+
+} } } // namespace mozilla::pkix::test
+
+#endif // mozilla_pkix_test_pkixtestnss_h
--- a/security/pkix/test/lib/pkixtestutil.h
+++ b/security/pkix/test/lib/pkixtestutil.h
@@ -17,18 +17,18 @@
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
-#ifndef mozilla_pkix_test_pkixtestutils_h
-#define mozilla_pkix_test_pkixtestutils_h
+#ifndef mozilla_pkix_test_pkixtestutil_h
+#define mozilla_pkix_test_pkixtestutil_h
 
 #include <ctime>
 #include <stdint.h> // Some Mozilla-supported compilers lack <cstdint>
 #include <string>
 #include <cstring>
 
 #include "pkix/pkixtypes.h"
 #include "../../lib/ScopedPtr.h"
@@ -440,9 +440,9 @@ public:
   std::time_t nextUpdate;
   bool includeNextUpdate;
 };
 
 ByteString CreateEncodedOCSPResponse(OCSPResponseContext& context);
 
 } } } // namespace mozilla::pkix::test
 
-#endif // mozilla_pkix_test_pkixtestutils_h
+#endif // mozilla_pkix_test_pkixtestutil_h
--- a/security/sandbox/linux/moz.build
+++ b/security/sandbox/linux/moz.build
@@ -73,16 +73,19 @@ SOURCES += [
     'SandboxUtil.cpp',
 ]
 
 if CONFIG['MOZ_GMP_SANDBOX']:
     SOURCES += [
         'SandboxOpenedFiles.cpp',
     ]
 
+if CONFIG['MOZ_ALSA']:
+    DEFINES['MOZ_ALSA'] = True
+
 # This copy of SafeSPrintf doesn't need to avoid the Chromium logging
 # dependency like the one in libxul does, but this way the behavior is
 # consistent.  See also the comment in SandboxLogging.h.
 SOURCES['../chromium/base/strings/safe_sprintf.cc'].flags += ['-DNDEBUG']
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     # Keep clang from warning about intentional 'switch' fallthrough in icu_utf.cc:
     SOURCES['../chromium/base/third_party/icu/icu_utf.cc'].flags += ['-Wno-implicit-fallthrough']
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -12445,16 +12445,25 @@
     "record_in_processes": ["main", "content"],
     "alert_emails": ["gfx-telemetry-alerts@mozilla.com","msreckovic@mozilla.com"],
     "expires_in_version": "never",
     "kind": "enumerated",
     "bug_numbers": [1229961],
     "n_values": 12,
     "description": "Plugin drawing model. 0 when windowed, otherwise NPDrawingModel + 1."
   },
+  "DOM_SCRIPT_KIND": {
+    "record_in_processes": ["main", "content"],
+    "alert_emails": ["jcoppeard@mozilla.com"],
+    "expires_in_version": "63",
+    "kind": "categorical",
+    "bug_numbers": [1430145],
+    "labels": ["ClassicScript", "ModuleScript"],
+    "description": "Record the kind of every script loaded in a document."
+  },
   "DOM_SCRIPT_SRC_ENCODING": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["dteller@mozilla.com"],
     "expires_in_version": "61",
     "kind": "count",
     "keyed": true,
     "bug_numbers": [1344152],
     "description": "Note the encoding (e.g. 'UTF-8', 'windows-1252', 'ASCII') of each external <script> element that is successfully loaded and decoded."
@@ -12597,16 +12606,25 @@
     "expires_in_version": "62",
     "kind": "linear",
     "low": 1,
     "high": 200,
     "n_buckets": 50,
     "bug_numbers": [1362114],
     "description": "Number of script tags evaluated per document."
   },
+  "DOM_SCRIPT_PRELOAD_RESULT": {
+    "record_in_processes": ["main", "content"],
+    "alert_emails": ["jcoppeard@mozilla.com"],
+    "expires_in_version": "63",
+    "kind": "categorical",
+    "bug_numbers": [1430145],
+    "labels": ["Used", "RejectedByPolicy", "RequestMismatch", "LoadError", "NotUsed"],
+    "description": "Whether a preloaded script was used or the reason it was not used."
+  },
   "VIDEO_FASTSEEK_USED": {
     "record_in_processes": ["main", "content"],
     "alert_emails": ["cpearce@mozilla.com", "tkuo@mozilla.com"],
     "expires_in_version": "60",
     "bug_numbers": [1245982],
     "kind": "count",
     "description": "Uses of HTMLMediaElement.fastSeek"
   },
--- a/toolkit/content/preferencesBindings.js
+++ b/toolkit/content/preferencesBindings.js
@@ -355,20 +355,31 @@ const Preferences = window.Preferences =
       /**
        * Initialize a UI element property with a value. Handles the case
        * where an element has not yet had a XBL binding attached for it and
        * the property setter does not yet exist by setting the same attribute
        * on the XUL element using DOM apis and assuming the element's
        * constructor or property getters appropriately handle this state.
        */
       function setValue(element, attribute, value) {
-        if (attribute in element)
+        if (attribute in element) {
           element[attribute] = value;
-        else
+        } else if (attribute === "checked") {
+          // The "checked" attribute can't simply be set to the specified value;
+          // it has to be set if the value is true and removed if the value
+          // is false in order to be interpreted correctly by the element.
+          if (value) {
+            // We can set it to anything; convention is to set it to itself.
+            element.setAttribute(attribute, attribute);
+          } else {
+            element.removeAttribute(attribute);
+          }
+        } else {
           element.setAttribute(attribute, value);
+        }
       }
       if (aElement.localName == "checkbox" ||
           aElement.localName == "listitem")
         setValue(aElement, "checked", val);
       else if (aElement.localName == "colorpicker")
         setValue(aElement, "color", val);
       else if (aElement.localName == "textbox") {
         // XXXmano Bug 303998: Avoid a caret placement issue if either the
--- a/xpcom/string/nsTDependentString.h
+++ b/xpcom/string/nsTDependentString.h
@@ -100,21 +100,31 @@ public:
   }
 
   // Create a nsTDependentSubstring to be bound later
   nsTDependentString()
     : string_type()
   {
   }
 
-  // XXX are you sure??
-  // auto-generated copy-constructor OK
-  // auto-generated copy-assignment operator OK
   // auto-generated destructor OK
 
+  nsTDependentString(self_type&& aStr)
+    : string_type()
+  {
+    Rebind(aStr, /* aStartPos = */ 0);
+    aStr.SetToEmptyBuffer();
+  }
+
+  explicit
+  nsTDependentString(const self_type& aStr)
+    : string_type()
+  {
+    Rebind(aStr, /* aStartPos = */ 0);
+  }
 
   /**
    * allow this class to be bound to a different string...
    */
 
   using nsTString<T>::Rebind;
   void Rebind(const char_type* aData)
   {
@@ -123,14 +133,15 @@ public:
 
   void Rebind(const char_type* aStart, const char_type* aEnd);
   void Rebind(const string_type&, uint32_t aStartPos);
 
 private:
 
   // NOT USED
   nsTDependentString(const substring_tuple_type&) = delete;
+  self_type& operator=(const self_type& aStr) = delete;
 };
 
 extern template class nsTDependentString<char>;
 extern template class nsTDependentString<char16_t>;
 
 #endif
--- a/xpcom/tests/gtest/TestStrings.cpp
+++ b/xpcom/tests/gtest/TestStrings.cpp
@@ -63,16 +63,62 @@ TEST(Strings, IsChar)
   a_ctest.AssignLiteral("hello");
   // This should cause a compilation failure.
   a_ctest.AssignLiteral(u"hello");
   a_test.AssignLiteral(u"hello");
   a_test.AssignLiteral("hello");
 #endif
 }
 
+TEST(Strings, DependentStrings)
+{
+  // A few tests that make sure copying nsTDependentStrings behaves properly.
+  using DataFlags = mozilla::detail::StringDataFlags;
+
+  {
+    // Test copy ctor.
+    nsDependentCString tmp("foo");
+    auto data = tmp.Data();
+    nsDependentCString foo(tmp);
+    // Neither string should be using a shared buffer.
+    EXPECT_FALSE(tmp.GetDataFlags() & DataFlags::SHARED);
+    EXPECT_FALSE(foo.GetDataFlags() & DataFlags::SHARED);
+    // Both strings should be pointing to the original buffer.
+    EXPECT_EQ(data, tmp.Data());
+    EXPECT_EQ(data, foo.Data());
+  }
+  {
+    // Test move ctor.
+    nsDependentCString tmp("foo");
+    auto data = tmp.Data();
+    nsDependentCString foo(mozilla::Move(tmp));
+    // Neither string should be using a shared buffer.
+    EXPECT_FALSE(tmp.GetDataFlags() & DataFlags::SHARED);
+    EXPECT_FALSE(foo.GetDataFlags() & DataFlags::SHARED);
+    // First string should be reset, the second should be pointing to the
+    // original buffer.
+    EXPECT_NE(data, tmp.Data());
+    EXPECT_EQ(data, foo.Data());
+    EXPECT_TRUE(tmp.IsEmpty());
+  }
+  {
+    // Test copying to a nsCString.
+    nsDependentCString tmp("foo");
+    auto data = tmp.Data();
+    nsCString foo(tmp);
+    // Original string should not be shared, copy should be shared.
+    EXPECT_FALSE(tmp.GetDataFlags() & DataFlags::SHARED);
+    EXPECT_TRUE(foo.GetDataFlags() & DataFlags::SHARED);
+    // First string should remain the same, the second should be pointing to
+    // a new buffer.
+    EXPECT_EQ(data, tmp.Data());
+    EXPECT_NE(data, foo.Data());
+  }
+}
+
 TEST(Strings, assign)
 {
   nsCString result;
   test_assign_helper(NS_LITERAL_CSTRING("a") + NS_LITERAL_CSTRING("b"), result);
   EXPECT_STREQ(result.get(), "ab");
 }
 
 TEST(Strings, assign_c)