merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 01 Jul 2016 11:17:36 +0200
changeset 303345 fdcee57b4e4f66a82831ab01e61500da98a858e8
parent 303276 a77894b804f45d8ae013d37be9c6fe2242deec47 (current diff)
parent 303344 0a03bb6af6043ce323142d24fb43c2d63deefbcb (diff)
child 303359 499d8875de7a011a863ed14dfddb5167b7f1f386
child 303409 0a0baf81a9a7269455f77bb22b70207f9597abb7
child 303508 081a02f8e58b1febd1618743276572871e5ba918
push id30386
push usercbook@mozilla.com
push dateFri, 01 Jul 2016 09:17:55 +0000
treeherdermozilla-central@fdcee57b4e4f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone50.0a1
first release with
nightly linux32
fdcee57b4e4f / 50.0a1 / 20160701030235 / files
nightly linux64
fdcee57b4e4f / 50.0a1 / 20160701030235 / files
nightly mac
fdcee57b4e4f / 50.0a1 / 20160701030201 / files
nightly win32
fdcee57b4e4f / 50.0a1 / 20160701030235 / files
nightly win64
fdcee57b4e4f / 50.0a1 / 20160701030235 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
dom/media/systemservices/CamerasUtils.cpp
dom/media/systemservices/CamerasUtils.h
security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
security/nss/lib/freebl/ecl/Makefile
testing/web-platform/meta/content-security-policy/blink-contrib/shared-worker-connect-src-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/blink-contrib/worker-connect-src-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/blink-contrib/worker-eval-blocked.sub.html.ini
testing/web-platform/meta/content-security-policy/blink-contrib/worker-function-function-blocked.sub.html.ini
testing/web-platform/meta/fetch/api/policies/csp-blocked-worker.html.ini
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1016,19 +1016,17 @@ pref("services.mobileid.server.uri", "ht
 
 pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1");
 pref("identity.fxaccounts.remote.profile.uri", "https://profile.accounts.firefox.com/v1");
 
 // Disable Firefox Accounts device registration until bug 1238895 is fixed.
 pref("identity.fxaccounts.skipDeviceRegistration", true);
 
 // Enable mapped array buffer.
-#ifndef XP_WIN
 pref("dom.mapped_arraybuffer.enabled", true);
-#endif
 
 // SystemUpdate API
 pref("dom.system_update.enabled", true);
 
 // UDPSocket API
 pref("dom.udpsocket.enabled", true);
 
 // Enable TV Manager API
--- a/browser/base/content/test/social/browser.ini
+++ b/browser/base/content/test/social/browser.ini
@@ -29,16 +29,17 @@ support-files =
 [browser_aboutHome_activation.js]
 [browser_addons.js]
 [browser_blocklist.js]
 [browser_share.js]
 [browser_social_activation.js]
 [browser_social_chatwindow.js]
 [browser_social_chatwindow_resize.js]
 [browser_social_chatwindowfocus.js]
+skip-if = asan # Bug 1260177
 [browser_social_contextmenu.js]
 skip-if = (os == 'linux' && e10s) # Bug 1072669 context menu relies on target element
 [browser_social_errorPage.js]
 [browser_social_flyout.js]
 [browser_social_isVisible.js]
 [browser_social_marks.js]
 [browser_social_marks_context.js]
 [browser_social_multiprovider.js]
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/crashtests/1277272-1-inner.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<head>
+<script>
+function start() {
+  var animation = document.body.animate([{marks: 'crop'},{marks: 'crop'}], 12);
+  document.write('<html><body></body></html>');
+
+  setTimeout(function() { animation.play(); }, 4);
+  setTimeout(function() {
+    animation.timeline = undefined;
+    SpecialPowers.Cu.forceGC();
+    window.top.continueTest();
+  }, 5);
+}
+</script>
+</head>
+<body onload="start()"></body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/crashtests/1277272-1.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html class="reftest-wait">
+<head>
+<script>
+var count = 0;
+
+function start() {
+  if (++count > 10) {
+    document.documentElement.className = "";
+    return;
+  }
+
+  var frame = document.getElementById("frame");
+  frame.src = "./1277272-1-inner.html";
+}
+
+function continueTest() {
+  setTimeout(start.bind(window), 1);
+}
+
+</script>
+</head>
+<body onload="start()"></body>
+<iframe id="frame">
+</html>
+
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -1,8 +1,9 @@
 pref(dom.animations-api.core.enabled,true) load 1239889-1.html
 pref(dom.animations-api.core.enabled,true) load 1244595-1.html
 pref(dom.animations-api.core.enabled,true) load 1216842-1.html
 pref(dom.animations-api.core.enabled,true) load 1216842-2.html
 pref(dom.animations-api.core.enabled,true) load 1216842-3.html
 pref(dom.animations-api.core.enabled,true) load 1216842-4.html
 pref(dom.animations-api.core.enabled,true) load 1216842-5.html
 pref(dom.animations-api.core.enabled,true) load 1216842-6.html
+pref(dom.animations-api.core.enabled,true) load 1277272-1.html
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -2742,28 +2742,16 @@ ToCString(const MediaKeySystemConfigurat
     str.AppendLiteral(", audioCapabilities=");
     str.Append(ToCString(aConfig.mAudioCapabilities.Value()));
   }
   if (aConfig.mVideoCapabilities.WasPassed()) {
     str.AppendLiteral(", videoCapabilities=");
     str.Append(ToCString(aConfig.mVideoCapabilities.Value()));
   }
 
-  if (!aConfig.mAudioType.IsEmpty()) {
-    str.AppendPrintf(", audioType='%s'",
-      NS_ConvertUTF16toUTF8(aConfig.mAudioType).get());
-  }
-  if (!aConfig.mInitDataType.IsEmpty()) {
-    str.AppendPrintf(", initDataType='%s'",
-      NS_ConvertUTF16toUTF8(aConfig.mInitDataType).get());
-  }
-  if (!aConfig.mVideoType.IsEmpty()) {
-    str.AppendPrintf(", videoType='%s'",
-      NS_ConvertUTF16toUTF8(aConfig.mVideoType).get());
-  }
   str.AppendLiteral("}");
 
   return str;
 }
 
 static nsCString
 RequestKeySystemAccessLogString(const nsAString& aKeySystem,
                                 const Sequence<MediaKeySystemConfiguration>& aConfigs)
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6417,41 +6417,39 @@ nsContentUtils::WidgetForDocument(const 
       }
     }
   }
 
   return nullptr;
 }
 
 static already_AddRefed<LayerManager>
-LayerManagerForDocumentInternal(const nsIDocument *aDoc, bool aRequirePersistent,
-                                bool* aAllowRetaining)
+LayerManagerForDocumentInternal(const nsIDocument *aDoc, bool aRequirePersistent)
 {
   nsIWidget *widget = nsContentUtils::WidgetForDocument(aDoc);
   if (widget) {
     RefPtr<LayerManager> manager =
       widget->GetLayerManager(aRequirePersistent ? nsIWidget::LAYER_MANAGER_PERSISTENT : 
-                              nsIWidget::LAYER_MANAGER_CURRENT,
-                              aAllowRetaining);
+                              nsIWidget::LAYER_MANAGER_CURRENT);
     return manager.forget();
   }
 
   return nullptr;
 }
 
 already_AddRefed<LayerManager>
-nsContentUtils::LayerManagerForDocument(const nsIDocument *aDoc, bool *aAllowRetaining)
-{
-  return LayerManagerForDocumentInternal(aDoc, false, aAllowRetaining);
+nsContentUtils::LayerManagerForDocument(const nsIDocument *aDoc)
+{
+  return LayerManagerForDocumentInternal(aDoc, false);
 }
 
 already_AddRefed<LayerManager>
-nsContentUtils::PersistentLayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining)
-{
-  return LayerManagerForDocumentInternal(aDoc, true, aAllowRetaining);
+nsContentUtils::PersistentLayerManagerForDocument(nsIDocument *aDoc)
+{
+  return LayerManagerForDocumentInternal(aDoc, true);
 }
 
 bool
 nsContentUtils::AllowXULXBLForPrincipal(nsIPrincipal* aPrincipal)
 {
   if (IsSystemPrincipal(aPrincipal)) {
     return true;
   }
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1911,34 +1911,34 @@ public:
    * a presentation with an associated widget, and use that widget's
    * layer manager.
    *
    * @param aDoc the document for which to return a layer manager.
    * @param aAllowRetaining an outparam that states whether the returned
    * layer manager should be used for retained layers
    */
   static already_AddRefed<mozilla::layers::LayerManager>
-  LayerManagerForDocument(const nsIDocument *aDoc, bool *aAllowRetaining = nullptr);
+  LayerManagerForDocument(const nsIDocument *aDoc);
 
   /**
    * Returns a layer manager to use for the given document. Basically we
    * look up the document hierarchy for the first document which has
    * a presentation with an associated widget, and use that widget's
    * layer manager. In addition to the normal layer manager lookup this will
    * specifically request a persistent layer manager. This means that the layer
    * manager is expected to remain the layer manager for the document in the
    * forseeable future. This function should be used carefully as it may change
    * the document's layer manager.
    *
    * @param aDoc the document for which to return a layer manager.
    * @param aAllowRetaining an outparam that states whether the returned
    * layer manager should be used for retained layers
    */
   static already_AddRefed<mozilla::layers::LayerManager>
-  PersistentLayerManagerForDocument(nsIDocument *aDoc, bool *aAllowRetaining = nullptr);
+  PersistentLayerManagerForDocument(nsIDocument *aDoc);
 
   /**
    * Determine whether a content node is focused or not,
    *
    * @param aContent the content node to check
    * @return true if the content node is focused, false otherwise.
    */
   static bool IsFocusedContent(const nsIContent *aContent);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -417,27 +417,24 @@ nsDOMWindowUtils::SetDisplayPortForEleme
 
     // If we are hiding something that is a display root then send empty paint
     // transaction in order to release retained layers because it won't get
     // any more paint requests when it is hidden.
     if (displayport.IsEmpty() &&
         rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) {
       nsCOMPtr<nsIWidget> widget = GetWidget();
       if (widget) {
-        bool isRetainingManager;
-        LayerManager* manager = widget->GetLayerManager(&isRetainingManager);
-        if (isRetainingManager) {
-          manager->BeginTransaction();
-          using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
-          nsLayoutUtils::PaintFrame(nullptr, rootFrame, nsRegion(),
-                                    NS_RGB(255, 255, 255),
-                                    nsDisplayListBuilderMode::PAINTING,
-                                    PaintFrameFlags::PAINT_WIDGET_LAYERS |
-                                    PaintFrameFlags::PAINT_EXISTING_TRANSACTION);
-        }
+        LayerManager* manager = widget->GetLayerManager();
+        manager->BeginTransaction();
+        using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags;
+        nsLayoutUtils::PaintFrame(nullptr, rootFrame, nsRegion(),
+                                  NS_RGB(255, 255, 255),
+                                  nsDisplayListBuilderMode::PAINTING,
+                                  PaintFrameFlags::PAINT_WIDGET_LAYERS |
+                                  PaintFrameFlags::PAINT_EXISTING_TRANSACTION);
       }
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -177,16 +177,17 @@
 #include "SVGElementFactory.h"
 
 #include "nsRefreshDriver.h"
 
 // FOR CSP (autogenerated by xpidl)
 #include "nsIContentSecurityPolicy.h"
 #include "mozilla/dom/nsCSPContext.h"
 #include "mozilla/dom/nsCSPService.h"
+#include "mozilla/dom/nsCSPUtils.h"
 #include "nsHTMLStyleSheet.h"
 #include "nsHTMLCSSStyleSheet.h"
 #include "SVGAttrAnimationRuleProcessor.h"
 #include "mozilla/dom/DOMImplementation.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/dom/Comment.h"
 #include "nsTextNode.h"
 #include "mozilla/dom/Link.h"
@@ -2641,39 +2642,16 @@ nsDocument::SendToConsole(nsCOMArray<nsI
 
     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                     NS_ConvertUTF16toUTF8(category),
                                     this, nsContentUtils::eSECURITY_PROPERTIES,
                                     NS_ConvertUTF16toUTF8(messageTag).get());
   }
 }
 
-static nsresult
-AppendCSPFromHeader(nsIContentSecurityPolicy* csp,
-                    const nsAString& aHeaderValue,
-                    bool aReportOnly)
-{
-  // Need to tokenize the header value since multiple headers could be
-  // concatenated into one comma-separated list of policies.
-  // See RFC2616 section 4.2 (last paragraph)
-  nsresult rv = NS_OK;
-  nsCharSeparatedTokenizer tokenizer(aHeaderValue, ',');
-  while (tokenizer.hasMoreTokens()) {
-      const nsSubstring& policy = tokenizer.nextToken();
-      rv = csp->AppendPolicy(policy, aReportOnly, false);
-      NS_ENSURE_SUCCESS(rv, rv);
-      {
-        MOZ_LOG(gCspPRLog, LogLevel::Debug,
-                ("CSP refined with policy: \"%s\"",
-                NS_ConvertUTF16toUTF8(policy).get()));
-      }
-  }
-  return NS_OK;
-}
-
 bool
 nsDocument::IsLoopDocument(nsIChannel *aChannel)
 {
   nsCOMPtr<nsIURI> chanURI;
   nsresult rv = aChannel->GetOriginalURI(getter_AddRefs(chanURI));
   NS_ENSURE_SUCCESS(rv, false);
 
   bool isAbout = false;
@@ -2926,23 +2904,23 @@ nsDocument::InitCSP(nsIChannel* aChannel
     // If the pref has been removed, we continue without setting a CSP
     if (loopCSP) {
       csp->AppendPolicy(loopCSP, false, false);
     }
   }
 
   // ----- if there's a full-strength CSP header, apply it.
   if (!cspHeaderValue.IsEmpty()) {
-    rv = AppendCSPFromHeader(csp, cspHeaderValue, false);
+    rv = CSP_AppendCSPFromHeader(csp, cspHeaderValue, false);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // ----- if there's a report-only CSP header, apply it.
   if (!cspROHeaderValue.IsEmpty()) {
-    rv = AppendCSPFromHeader(csp, cspROHeaderValue, true);
+    rv = CSP_AppendCSPFromHeader(csp, cspROHeaderValue, true);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // ----- Enforce sandbox policy if supplied in CSP header
   // The document may already have some sandbox flags set (e.g. if the document
   // is an iframe with the sandbox attribute set). If we have a CSP sandbox
   // directive, intersect the CSP sandbox flags with the existing flags. This
   // corresponds to the _least_ permissive policy.
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -15,13 +15,11 @@ support-files = file_navigator_resolve_i
 [test_sendQueryContentAndSelectionSetEvent.html]
 [test_bug1016960.html]
 [test_copypaste.xul]
 subsuite = clipboard
 [test_messagemanager_principal.html]
 [test_messagemanager_send_principal.html]
 skip-if = buildapp == 'mulet'
 [test_bug945152.html]
-run-if = os == 'linux'
 [test_bug1008126.html]
-run-if = os == 'linux'
 [test_sandboxed_blob_uri.html]
 [test_websocket_frame.html]
--- a/dom/base/test/test_youtube_flash_embed.html
+++ b/dom/base/test/test_youtube_flash_embed.html
@@ -15,18 +15,22 @@
        let msg = JSON.parse(e.data);
        if (msg.fn == "finish") {
          SimpleTest.finish();
          return;
        }
        self[msg.fn].apply(null, msg.args);
      }
      function onLoad() {
-       // The test file must be loaded into youtube.com domain
-       // because it needs unprivileged access to fullscreenEnabled.
-       ifr.src = "https://mochitest.youtube.com" + path;
+       SpecialPowers.pushPrefEnv({
+         "set": [["full-screen-api.unprefix.enabled", true]]
+       }, function() {
+         // The test file must be loaded into youtube.com domain
+         // because it needs unprivileged access to fullscreenEnabled.
+         ifr.src = "https://mochitest.youtube.com" + path;
+       });
      }
     </script>
   </head>
   <body onload="onLoad()">
     <iframe id="ifr" allowfullscreen></iframe>
   </body>
 </html>
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -108,16 +108,17 @@ WebGLContextOptions::WebGLContextOptions
 
 WebGLContext::WebGLContext()
     : WebGLContextUnchecked(nullptr)
     , mBufferFetchingIsVerified(false)
     , mBufferFetchingHasPerVertex(false)
     , mMaxFetchedVertices(0)
     , mMaxFetchedInstances(0)
     , mBypassShaderValidation(false)
+    , mContextLossHandler(this)
     , mNeedsFakeNoAlpha(false)
     , mNeedsFakeNoDepth(false)
     , mNeedsFakeNoStencil(false)
     , mNeedsEmulatedLoneDepthStencil(false)
 {
     mGeneration = 0;
     mInvalidated = false;
     mCapturedFrameInvalidated = false;
@@ -169,17 +170,16 @@ WebGLContext::WebGLContext()
 
     if (NS_IsMainThread()) {
         // XXX mtseng: bug 709490, not thread safe
         WebGLMemoryTracker::AddWebGLContext(this);
     }
 
     mAllowContextRestore = true;
     mLastLossWasSimulated = false;
-    mContextLossHandler = new WebGLContextLossHandler(this);
     mContextStatus = ContextNotLost;
     mLoseContextOnMemoryPressure = false;
     mCanLoseContextInForeground = true;
     mRestoreWhenVisible = false;
 
     mAlreadyGeneratedWarnings = 0;
     mAlreadyWarnedAboutFakeVertexAttrib0 = false;
     mAlreadyWarnedAboutViewportLargerThanDest = false;
@@ -205,19 +205,16 @@ WebGLContext::~WebGLContext()
 {
     RemovePostRefreshObserver();
 
     DestroyResourcesAndContext();
     if (NS_IsMainThread()) {
         // XXX mtseng: bug 709490, not thread safe
         WebGLMemoryTracker::RemoveWebGLContext(this);
     }
-
-    mContextLossHandler->DisableTimer();
-    mContextLossHandler = nullptr;
 }
 
 template<typename T>
 static void
 ClearLinkedList(LinkedList<T>& list)
 {
     while (!list.isEmpty()) {
         list.getLast()->DeleteOnce();
@@ -1618,17 +1615,17 @@ WebGLContext::TryToRestoreContext()
         return false;
 
     return true;
 }
 
 void
 WebGLContext::RunContextLossTimer()
 {
-    mContextLossHandler->RunTimer();
+    mContextLossHandler.RunTimer();
 }
 
 class UpdateContextLossStatusTask : public CancelableRunnable
 {
     RefPtr<WebGLContext> mWebGL;
 
 public:
     explicit UpdateContextLossStatusTask(WebGLContext* webgl)
@@ -1760,17 +1757,17 @@ WebGLContext::UpdateContextLossStatus()
             // We might decide this after thinking we'd be OK restoring
             // the context, so downgrade.
             mContextStatus = ContextLost;
             return;
         }
 
         if (!TryToRestoreContext()) {
             // Failed to restore. Try again later.
-            mContextLossHandler->RunTimer();
+            mContextLossHandler.RunTimer();
             return;
         }
 
         // Revival!
         mContextStatus = ContextNotLost;
 
         if (mCanvasElement) {
             nsContentUtils::DispatchTrustedEvent(
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -14,31 +14,31 @@
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/UniquePtr.h"
-#include "mozilla/WeakPtr.h"
 #include "nsCycleCollectionNoteChild.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsLayoutUtils.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "SurfaceTypes.h"
 #include "ScopedGLHelpers.h"
 #include "TexUnpackBlob.h"
 
 #ifdef XP_MACOSX
 #include "ForceDiscreteGPUHelperCGL.h"
 #endif
 
 // Local
+#include "WebGLContextLossHandler.h"
 #include "WebGLContextUnchecked.h"
 #include "WebGLFormats.h"
 #include "WebGLObjectModel.h"
 #include "WebGLStrongTypes.h"
 #include "WebGLTexture.h"
 
 // Generated
 #include "nsIDOMEventListener.h"
@@ -85,17 +85,16 @@ class nsIDocShell;
 #define LOCAL_GL_UNPACK_FLIP_Y_WEBGL                         0x9240
 #define LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL              0x9241
 
 namespace mozilla {
 class ScopedCopyTexImageSource;
 class ScopedResolveTexturesForDraw;
 class ScopedUnpackReset;
 class WebGLActiveInfo;
-class WebGLContextLossHandler;
 class WebGLBuffer;
 class WebGLExtensionBase;
 class WebGLFramebuffer;
 class WebGLProgram;
 class WebGLQuery;
 class WebGLRenderbuffer;
 class WebGLSampler;
 class WebGLShader;
@@ -182,17 +181,16 @@ public:
 
 class WebGLContext
     : public nsIDOMWebGLRenderingContext
     , public nsICanvasRenderingContextInternal
     , public nsSupportsWeakReference
     , public WebGLContextUnchecked
     , public WebGLRectangleObject
     , public nsWrapperCache
-    , public SupportsWeakPtr<WebGLContext>
 {
     friend class WebGL2Context;
     friend class WebGLContextUserData;
     friend class WebGLExtensionCompressedTextureATC;
     friend class WebGLExtensionCompressedTextureES3;
     friend class WebGLExtensionCompressedTextureETC1;
     friend class WebGLExtensionCompressedTexturePVRTC;
     friend class WebGLExtensionCompressedTextureS3TC;
@@ -218,18 +216,16 @@ class WebGLContext
 
 public:
     WebGLContext();
 
 protected:
     virtual ~WebGLContext();
 
 public:
-    MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLContext)
-
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext,
                                                            nsIDOMWebGLRenderingContext)
 
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override = 0;
 
     NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
@@ -1486,17 +1482,17 @@ protected:
     GLfloat mDepthClearValue;
 
     GLint mViewportX;
     GLint mViewportY;
     GLsizei mViewportWidth;
     GLsizei mViewportHeight;
     bool mAlreadyWarnedAboutViewportLargerThanDest;
 
-    RefPtr<WebGLContextLossHandler> mContextLossHandler;
+    WebGLContextLossHandler mContextLossHandler;
     bool mAllowContextRestore;
     bool mLastLossWasSimulated;
     ContextStatus mContextStatus;
     bool mContextLostErrorSet;
 
     // Used for some hardware (particularly Tegra 2 and 4) that likes to
     // be Flushed while doing hundreds of draw calls.
     int mDrawCallsSinceLastFlush;
--- a/dom/canvas/WebGLContextLossHandler.cpp
+++ b/dom/canvas/WebGLContextLossHandler.cpp
@@ -1,241 +1,103 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "WebGLContextLossHandler.h"
 
+#include "mozilla/DebugOnly.h"
+#include "nsISupportsImpl.h"
 #include "nsITimer.h"
 #include "nsThreadUtils.h"
 #include "WebGLContext.h"
-#include "mozilla/dom/WorkerPrivate.h"
 
 namespace mozilla {
 
-// -------------------------------------------------------------------
-// Begin worker specific code
-// -------------------------------------------------------------------
+class WatchdogTimerEvent final : public nsITimerCallback
+{
+    const WeakPtr<WebGLContextLossHandler> mHandler;
 
-// On workers we can only dispatch CancelableRunnables, so we have to wrap the
-// timer's EventTarget to use our own cancelable runnable
-
-class ContextLossWorkerEventTarget final : public nsIEventTarget
-{
 public:
-    explicit ContextLossWorkerEventTarget(nsIEventTarget* aEventTarget)
-        : mEventTarget(aEventTarget)
-    {
-        MOZ_ASSERT(aEventTarget);
-    }
+    NS_DECL_ISUPPORTS
 
-    NS_DECL_NSIEVENTTARGET
-    NS_DECL_THREADSAFE_ISUPPORTS
-
-protected:
-    ~ContextLossWorkerEventTarget() {}
+    explicit WatchdogTimerEvent(WebGLContextLossHandler* handler)
+        : mHandler(handler)
+    { }
 
 private:
-    nsCOMPtr<nsIEventTarget> mEventTarget;
-};
+    virtual ~WatchdogTimerEvent() { }
 
-class ContextLossWorkerRunnable final : public CancelableRunnable
-{
-public:
-    explicit ContextLossWorkerRunnable(nsIRunnable* aRunnable)
-        : mRunnable(aRunnable)
-    {
+    NS_IMETHOD Notify(nsITimer*) override {
+        if (mHandler) {
+            mHandler->TimerCallback();
+        }
+        return NS_OK;
     }
-
-    nsresult Cancel() override;
-
-    NS_FORWARD_NSIRUNNABLE(mRunnable->)
-
-protected:
-    ~ContextLossWorkerRunnable() {}
-
-private:
-    nsCOMPtr<nsIRunnable> mRunnable;
 };
 
-NS_IMPL_ISUPPORTS(ContextLossWorkerEventTarget, nsIEventTarget,
-                  nsISupports)
-
-NS_IMETHODIMP
-ContextLossWorkerEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
-{
-    nsCOMPtr<nsIRunnable> event(aEvent);
-    return Dispatch(event.forget(), aFlags);
-}
-
-NS_IMETHODIMP
-ContextLossWorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent,
-                                       uint32_t aFlags)
-{
-    nsCOMPtr<nsIRunnable> eventRef(aEvent);
-    RefPtr<ContextLossWorkerRunnable> wrappedEvent =
-        new ContextLossWorkerRunnable(eventRef);
-    return mEventTarget->Dispatch(wrappedEvent, aFlags);
-}
+NS_IMPL_ISUPPORTS(WatchdogTimerEvent, nsITimerCallback, nsISupports)
 
-NS_IMETHODIMP
-ContextLossWorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>,
-                                              uint32_t)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-ContextLossWorkerEventTarget::IsOnCurrentThread(bool* aResult)
-{
-    return mEventTarget->IsOnCurrentThread(aResult);
-}
-
-nsresult
-ContextLossWorkerRunnable::Cancel()
-{
-    mRunnable = nullptr;
-    return NS_OK;
-}
-
-// -------------------------------------------------------------------
-// End worker-specific code
-// -------------------------------------------------------------------
+////////////////////////////////////////
 
 WebGLContextLossHandler::WebGLContextLossHandler(WebGLContext* webgl)
-    : mWeakWebGL(webgl)
+    : mWebGL(webgl)
     , mTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
-    , mIsTimerRunning(false)
+    , mTimerPending(false)
     , mShouldRunTimerAgain(false)
-    , mIsDisabled(false)
-    , mWorkerHolderAdded(false)
 #ifdef DEBUG
     , mThread(NS_GetCurrentThread())
 #endif
 {
+    MOZ_ASSERT(mThread);
 }
 
 WebGLContextLossHandler::~WebGLContextLossHandler()
 {
-    MOZ_ASSERT(!mIsTimerRunning);
+    // NS_GetCurrentThread() returns null during shutdown.
+    const DebugOnly<nsIThread*> callingThread = NS_GetCurrentThread();
+    MOZ_ASSERT(callingThread == mThread || !callingThread);
 }
 
+////////////////////
+
 void
-WebGLContextLossHandler::StartTimer(unsigned long delayMS)
+WebGLContextLossHandler::RunTimer()
 {
-    // We can't pass an already_AddRefed through InitWithFuncCallback, so we
-    // should do the AddRef/Release manually.
-    this->AddRef();
+    MOZ_ASSERT(NS_GetCurrentThread() == mThread);
 
-    mTimer->InitWithFuncCallback(StaticTimerCallback,
-                                 static_cast<void*>(this),
-                                 delayMS,
-                                 nsITimer::TYPE_ONE_SHOT);
+    // If the timer was already running, don't restart it here. Instead,
+    // wait until the previous call is done, then fire it one more time.
+    // This is also an optimization to prevent unnecessary
+    // cross-communication between threads.
+    if (mTimerPending) {
+        mShouldRunTimerAgain = true;
+        return;
+    }
+
+    const RefPtr<WatchdogTimerEvent> event = new WatchdogTimerEvent(this);
+    const uint32_t kDelayMS = 1000;
+    mTimer->InitWithCallback(event, kDelayMS, nsITimer::TYPE_ONE_SHOT);
+
+    mTimerPending = true;
 }
 
-/*static*/ void
-WebGLContextLossHandler::StaticTimerCallback(nsITimer*, void* voidHandler)
-{
-    typedef WebGLContextLossHandler T;
-    T* handler = static_cast<T*>(voidHandler);
-
-    handler->TimerCallback();
-
-    // Release the AddRef from StartTimer.
-    handler->Release();
-}
+////////////////////
 
 void
 WebGLContextLossHandler::TimerCallback()
 {
     MOZ_ASSERT(NS_GetCurrentThread() == mThread);
-    MOZ_ASSERT(mIsTimerRunning);
-    mIsTimerRunning = false;
 
-    if (mIsDisabled)
-        return;
+    mTimerPending = false;
 
-    // If we need to run the timer again, restart it immediately.
-    // Otherwise, the code we call into below might *also* try to
-    // restart it.
-    if (mShouldRunTimerAgain) {
+    const bool runOnceMore = mShouldRunTimerAgain;
+    mShouldRunTimerAgain = false;
+
+    mWebGL->UpdateContextLossStatus();
+
+    if (runOnceMore && !mTimerPending) {
         RunTimer();
-        MOZ_ASSERT(mIsTimerRunning);
-    }
-
-    if (mWeakWebGL) {
-        mWeakWebGL->UpdateContextLossStatus();
     }
 }
 
-void
-WebGLContextLossHandler::RunTimer()
-{
-    MOZ_ASSERT(!mIsDisabled);
-
-    // If the timer was already running, don't restart it here. Instead,
-    // wait until the previous call is done, then fire it one more time.
-    // This is an optimization to prevent unnecessary
-    // cross-communication between threads.
-    if (mIsTimerRunning) {
-        mShouldRunTimerAgain = true;
-        return;
-    }
-
-    if (!NS_IsMainThread()) {
-        dom::workers::WorkerPrivate* workerPrivate =
-            dom::workers::GetCurrentThreadWorkerPrivate();
-        nsCOMPtr<nsIEventTarget> target = workerPrivate->GetEventTarget();
-        mTimer->SetTarget(new ContextLossWorkerEventTarget(target));
-        if (!mWorkerHolderAdded) {
-            HoldWorker(workerPrivate);
-            mWorkerHolderAdded = true;
-        }
-    }
-
-    StartTimer(1000);
-
-    mIsTimerRunning = true;
-    mShouldRunTimerAgain = false;
-}
-
-void
-WebGLContextLossHandler::DisableTimer()
-{
-    if (mIsDisabled)
-        return;
-
-    mIsDisabled = true;
-
-    if (mWorkerHolderAdded) {
-        dom::workers::WorkerPrivate* workerPrivate =
-            dom::workers::GetCurrentThreadWorkerPrivate();
-        MOZ_RELEASE_ASSERT(workerPrivate, "GFX: No private worker created.");
-        ReleaseWorker();
-        mWorkerHolderAdded = false;
-    }
-
-    // We can't just Cancel() the timer, as sometimes we end up
-    // receiving a callback after calling Cancel(). This could cause us
-    // to receive the callback after object destruction.
-
-    // Instead, we let the timer finish, but ignore it.
-
-    if (!mIsTimerRunning)
-        return;
-
-    mTimer->SetDelay(0);
-}
-
-bool
-WebGLContextLossHandler::Notify(dom::workers::Status aStatus)
-{
-    bool isWorkerRunning = aStatus < dom::workers::Closing;
-    if (!isWorkerRunning && mIsTimerRunning) {
-        mIsTimerRunning = false;
-        this->Release();
-    }
-
-    return true;
-}
-
 } // namespace mozilla
--- a/dom/canvas/WebGLContextLossHandler.h
+++ b/dom/canvas/WebGLContextLossHandler.h
@@ -1,52 +1,44 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 WEBGL_CONTEXT_LOSS_HANDLER_H_
 #define WEBGL_CONTEXT_LOSS_HANDLER_H_
 
-#include "mozilla/DebugOnly.h"
 #include "mozilla/WeakPtr.h"
 #include "nsCOMPtr.h"
-#include "nsISupportsImpl.h"
-#include "WorkerHolder.h"
 
 class nsIThread;
 class nsITimer;
 
 namespace mozilla {
 class WebGLContext;
 
-class WebGLContextLossHandler : public dom::workers::WorkerHolder
+class WebGLContextLossHandler final : public SupportsWeakPtr<WebGLContextLossHandler>
 {
-    WeakPtr<WebGLContext> mWeakWebGL;
-    nsCOMPtr<nsITimer> mTimer;
-    bool mIsTimerRunning;
-    bool mShouldRunTimerAgain;
-    bool mIsDisabled;
-    bool mWorkerHolderAdded;
+    WebGLContext* const mWebGL;
+    const nsCOMPtr<nsITimer> mTimer; // If we don't hold a ref to the timer, it will think
+    bool mTimerPending;              // that it's been discarded, and be canceled 'for our
+    bool mShouldRunTimerAgain;       // convenience'.
 #ifdef DEBUG
-    nsIThread* mThread;
+    nsIThread* const mThread;
 #endif
 
+    friend class WatchdogTimerEvent;
+
 public:
-    NS_INLINE_DECL_REFCOUNTING(WebGLContextLossHandler)
+    MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLContextLossHandler)
 
     explicit WebGLContextLossHandler(WebGLContext* webgl);
+    ~WebGLContextLossHandler();
 
     void RunTimer();
-    void DisableTimer();
-    bool Notify(dom::workers::Status aStatus) override;
 
-protected:
-    ~WebGLContextLossHandler();
-
-    void StartTimer(unsigned long delayMS);
-    static void StaticTimerCallback(nsITimer*, void* tempRefForTimer);
+private:
     void TimerCallback();
 };
 
 } // namespace mozilla
 
-#endif
+#endif // WEBGL_CONTEXT_LOSS_HANDLER_H_
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -4,18 +4,18 @@
 # 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/.
 
 TEST_DIRS += [
     'compiledtest', 
     'gtest'
 ]
 
-# Change the following line to avoid bug 1081323 (clobber after changing a manifest):
-# Add test for webglcontextcreationerror.
+# Change the following line(s) to avoid bug 1081323 (clobber after changing a manifest):
+# * Add a regression test for triangle-then-point rendering.
 
 MOCHITEST_MANIFESTS += [
     'test/crash/mochitest.ini',
     'test/crossorigin/mochitest.ini',
     'test/mochitest.ini',
     'test/webgl-conf/generated-mochitest.ini',
     'test/webgl-mochitest/mochitest.ini',
 ]
--- a/dom/canvas/test/mochitest.ini
+++ b/dom/canvas/test/mochitest.ini
@@ -271,37 +271,45 @@ skip-if = (e10s && debug && os == 'win')
 [test_filter_tainted_source_graphics.html]
 skip-if = (e10s && debug && os == 'win')
 [test_filter_tainted_displacement_map.html]
 skip-if = (e10s && debug && os == 'win')
 [test_filter_tainted_displacement_map_source_graphics.html]
 [test_offscreencanvas_toblob.html]
 subsuite = gpu
 tags = offscreencanvas
+skip-if = 1
 [test_offscreencanvas_toimagebitmap.html]
 subsuite = gpu
 tags = offscreencanvas
+skip-if = 1
 [test_offscreencanvas_basic_webgl.html]
 subsuite = gpu
 tags = offscreencanvas
-skip-if = (os == 'mac')
+skip-if = 1
 [test_offscreencanvas_dynamic_fallback.html]
 subsuite = gpu
 tags = offscreencanvas
-skip-if = (os == 'mac')
+skip-if = 1
 [test_offscreencanvas_sharedworker.html]
+subsuite = gpu
 tags = offscreencanvas
-skip-if = (os == 'mac')
+skip-if = 1
 [test_offscreencanvas_serviceworker.html]
 subsuite = gpu
 tags = offscreencanvas
-skip-if = (buildapp == 'b2g' || (os == 'mac'))
+skip-if = 1
 [test_offscreencanvas_neuter.html]
+subsuite = gpu
 tags = offscreencanvas
+skip-if = 1
 [test_offscreencanvas_many.html]
+subsuite = gpu
 tags = offscreencanvas
-skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3' || (os == 'mac'))
+skip-if = 1
 [test_offscreencanvas_sizechange.html]
 subsuite = gpu
 tags = offscreencanvas
+skip-if = 1
 [test_offscreencanvas_subworker.html]
+subsuite = gpu
 tags = offscreencanvas
-skip-if = (toolkit == 'android' || toolkit == 'gonk' || toolkit == 'windows' || toolkit == 'gtk2' || toolkit == 'gtk3' || (os == 'mac'))
+skip-if = 1
--- a/dom/canvas/test/webgl-mochitest/mochitest.ini
+++ b/dom/canvas/test/webgl-mochitest/mochitest.ini
@@ -41,16 +41,19 @@ fail-if = (os == 'android') || (os == 'l
 [ensure-exts/test_WEBGL_depth_texture.html]
 fail-if = (os == 'mac' && os_version == '10.6')
 [ensure-exts/test_WEBGL_draw_buffers.html]
 fail-if = (os == 'android') || (os == 'win' && os_version == '5.1')
 
 [ensure-exts/test_common.html]
 
 
+[regress/test_bug_1268096.html]
+
+
 [test_backends.html]
 [test_backbuffer_channels.html]
 fail-if = (os == 'b2g')
 [test_depth_readpixels.html]
 [test_capture.html]
 support-files = ../captureStream_common.js
 # Even though we use ../ here, in the test HTML, we need to omit this. Sub-CWD relative
 # paths are fine, but they locate the file and dump it in the current directory.
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/webgl-mochitest/regress/test_bug_1268096.html
@@ -0,0 +1,140 @@
+<!DOCTYPE HTML>
+<html>
+  <head>
+    <meta charset='UTF-8'/>
+    <script src='/tests/SimpleTest/SimpleTest.js'></script>
+    <link rel='stylesheet' href='/tests/SimpleTest/test.css'>
+    <script src='../webgl-util.js'></script>
+    <script id='vs' type='x-shader/x-vertex'>
+
+attribute vec2 aPosition;
+
+void main(void) {
+  gl_PointSize = 16.0;
+  gl_Position = vec4(aPosition, 0, 1);
+}
+
+    </script>
+    <script id='fs' type='x-shader/x-fragment'>
+
+precision mediump float;
+
+uniform vec4 uColor;
+
+void main(void) {
+  gl_FragColor = uColor;
+}
+
+    </script>
+  </head>
+  <body>
+    <script>
+
+function GetPixel(gl, x, y) {
+  var pixel = new Uint8Array(4);
+  gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
+  return pixel;
+}
+
+function ColorStr(arr) {
+  return '{' + arr.map(function(x) { return '' + x; }).join(', ') + '}';
+}
+
+function PixelShouldBe(gl, x, y, ref, prefix) {
+  if (prefix) {
+    prefix += ': ';
+  }
+
+  var test = GetPixel(gl, x, y);
+
+  var testStr = ColorStr(test);
+  var refStr = ColorStr(ref.map(x => x * 255));
+  ok(testStr == refStr, prefix + 'Should be ' + refStr + ', was ' + testStr + '.');
+}
+
+function GetProgram(gl) {
+  var prog = WebGLUtil.createProgramByIds(gl, 'vs', 'fs');
+
+  prog.aPosition = gl.getAttribLocation(prog, 'aPosition');
+  ok(prog.aPosition >= 0, '`aPosition` should be valid.');
+
+  prog.uColor = gl.getUniformLocation(prog, 'uColor');
+  ok(prog.uColor, '`uColor` should be valid.');
+
+  return prog;
+}
+
+// Give ourselves a scope to return early from:
+(function () {
+  var c = document.createElement('canvas');
+  document.body.appendChild(c);
+  var gl = c.getContext('webgl', { depth: false, antialias: false });
+  if (!gl) {
+    todo(false, 'WebGL is unavailable.');
+    return;
+  }
+
+  ////////
+
+  // With default culling, it works fine.
+  // The problem seems to be that the virtual quads generated from points are wound 'backwards'.
+  gl.enable(gl.CULL_FACE);
+  gl.cullFace(gl.BACK); // Cull back faces.
+
+  ////////
+
+  var vertArr = new Float32Array([
+    -1, -1,
+    +1, -1,
+    -1, +1,
+  ]);
+
+  var vbo = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
+  gl.bufferData(gl.ARRAY_BUFFER, vertArr, gl.STATIC_DRAW);
+
+  ////////
+
+  var triProg = GetProgram(gl);
+  var pointProg = GetProgram(gl);
+  if (!triProg || !pointProg) {
+    ok(false, 'Program linking should succeed.');
+    return;
+  }
+
+  ok(triProg.aPosition == pointProg.aPosition, 'aPosition should match.');
+  gl.enableVertexAttribArray(triProg.aPosition);
+  gl.vertexAttribPointer(triProg.aPosition, 2, gl.FLOAT, false, 0, 0);
+
+  ////////
+
+  gl.useProgram(triProg);
+  var triColor = [1, 0, 0, 1];
+  gl.uniform4fv(triProg.uColor, triColor);
+
+  gl.useProgram(pointProg);
+  var pointColor = [0, 1, 0, 1];
+  gl.uniform4fv(pointProg.uColor, pointColor);
+
+  ////////
+
+  gl.clearColor(0, 0, 0, 1);
+  gl.clear(gl.COLOR_BUFFER_BIT);
+
+  gl.useProgram(triProg);
+  gl.drawArrays(gl.TRIANGLES, 0, 3);
+
+  gl.useProgram(pointProg);
+  gl.drawArrays(gl.POINTS, 0, 3);
+
+  ////////
+
+  PixelShouldBe(gl, 32, 32, triColor, 'Tri');
+  PixelShouldBe(gl, 0, 0, pointColor, 'Point');
+
+  ok(true, 'Test complete');
+})();
+
+    </script>
+  </body>
+</html>
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -489,28 +489,28 @@ private:
   // Empty string: no-referrer
   // "about:client": client (default)
   // URL: an URL
   nsString mReferrer;
   ReferrerPolicy mReferrerPolicy;
 
   RequestMode mMode;
   RequestCredentials mCredentialsMode;
-  LoadTainting mResponseTainting;
+  MOZ_INIT_OUTSIDE_CTOR LoadTainting mResponseTainting;
   RequestCache mCacheMode;
   RequestRedirect mRedirectMode;
 
-  bool mAuthenticationFlag;
-  bool mForceOriginHeader;
-  bool mPreserveContentCodings;
-  bool mSameOriginDataURL;
-  bool mSkipServiceWorker;
-  bool mSynchronous;
-  bool mUnsafeRequest;
-  bool mUseURLCredentials;
+  MOZ_INIT_OUTSIDE_CTOR bool mAuthenticationFlag;
+  MOZ_INIT_OUTSIDE_CTOR bool mForceOriginHeader;
+  MOZ_INIT_OUTSIDE_CTOR bool mPreserveContentCodings;
+  MOZ_INIT_OUTSIDE_CTOR bool mSameOriginDataURL;
+  MOZ_INIT_OUTSIDE_CTOR bool mSkipServiceWorker;
+  MOZ_INIT_OUTSIDE_CTOR bool mSynchronous;
+  MOZ_INIT_OUTSIDE_CTOR bool mUnsafeRequest;
+  MOZ_INIT_OUTSIDE_CTOR bool mUseURLCredentials;
   // This is only set when a Request object is created by a fetch event.  We
   // use it to check if Service Workers are simply fetching intercepted Request
   // objects without modifying them.
   bool mCreatedByFetchEvent = false;
   // This is only set when Request.overrideContentPolicyType() has been set.
   // It is illegal to pass such a Request object to a fetch() method unless
   // if the caller has chrome privileges.
   bool mContentPolicyTypeOverridden = false;
--- a/dom/gamepad/moz.build
+++ b/dom/gamepad/moz.build
@@ -1,74 +1,75 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-EXPORTS.mozilla.dom += [
-    'Gamepad.h',
-    'GamepadButton.h',
-    'GamepadManager.h',
-    'GamepadMonitoring.h',
-    'GamepadPlatformService.h',
-    'GamepadServiceTest.h',
-    'ipc/GamepadEventChannelChild.h',
-    'ipc/GamepadEventChannelParent.h',
-    'ipc/GamepadTestChannelChild.h',
-    'ipc/GamepadTestChannelParent.h'
-    ]
-
-UNIFIED_SOURCES = [
-    'Gamepad.cpp',
-    'GamepadButton.cpp',
-    'GamepadManager.cpp',
-    'GamepadMonitoring.cpp',
-    'GamepadPlatformService.cpp',
-    'GamepadServiceTest.cpp',
-    'ipc/GamepadEventChannelChild.cpp',
-    'ipc/GamepadEventChannelParent.cpp',
-    'ipc/GamepadTestChannelChild.cpp',
-    'ipc/GamepadTestChannelParent.cpp'
-    ]
-
-if CONFIG['MOZ_GAMEPAD_BACKEND'] == 'stub':
-    UNIFIED_SOURCES += [
-        'fallback/FallbackGamepad.cpp'
-    ]
-elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'cocoa':
-    UNIFIED_SOURCES += [
-        'cocoa/CocoaGamepad.cpp'
-    ]
-elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'windows':
-    UNIFIED_SOURCES += [
-        'windows/WindowsGamepad.cpp'
-    ]
-elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'linux':
-    UNIFIED_SOURCES += [
-        'linux/LinuxGamepad.cpp'
-    ]
-elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'android':
-    UNIFIED_SOURCES += [
-        'android/AndroidGamepad.cpp'
-    ]
-
-LOCAL_INCLUDES += [
-    'ipc',
-]
-
 IPDL_SOURCES += [
     'ipc/GamepadEventTypes.ipdlh',
     'ipc/PGamepadEventChannel.ipdl',
     'ipc/PGamepadTestChannel.ipdl'
 ]
 
-include('/ipc/chromium/chromium-config.mozbuild')
+if CONFIG['MOZ_GAMEPAD']:
+    EXPORTS.mozilla.dom += [
+        'Gamepad.h',
+        'GamepadButton.h',
+        'GamepadManager.h',
+        'GamepadMonitoring.h',
+        'GamepadPlatformService.h',
+        'GamepadServiceTest.h',
+        'ipc/GamepadEventChannelChild.h',
+        'ipc/GamepadEventChannelParent.h',
+        'ipc/GamepadTestChannelChild.h',
+        'ipc/GamepadTestChannelParent.h'
+        ]
+
+    UNIFIED_SOURCES = [
+        'Gamepad.cpp',
+        'GamepadButton.cpp',
+        'GamepadManager.cpp',
+        'GamepadMonitoring.cpp',
+        'GamepadPlatformService.cpp',
+        'GamepadServiceTest.cpp',
+        'ipc/GamepadEventChannelChild.cpp',
+        'ipc/GamepadEventChannelParent.cpp',
+        'ipc/GamepadTestChannelChild.cpp',
+        'ipc/GamepadTestChannelParent.cpp'
+        ]
 
-FINAL_LIBRARY = 'xul'
-LOCAL_INCLUDES += [
-    '/dom/base',
-]
+    if CONFIG['MOZ_GAMEPAD_BACKEND'] == 'stub':
+        UNIFIED_SOURCES += [
+            'fallback/FallbackGamepad.cpp'
+        ]
+    elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'cocoa':
+        UNIFIED_SOURCES += [
+            'cocoa/CocoaGamepad.cpp'
+        ]
+    elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'windows':
+        UNIFIED_SOURCES += [
+            'windows/WindowsGamepad.cpp'
+        ]
+    elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'linux':
+        UNIFIED_SOURCES += [
+            'linux/LinuxGamepad.cpp'
+        ]
+    elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'android':
+        UNIFIED_SOURCES += [
+            'android/AndroidGamepad.cpp'
+        ]
 
-CFLAGS += CONFIG['GLIB_CFLAGS']
-CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
-CXXFLAGS += CONFIG['GLIB_CFLAGS']
-CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
+    LOCAL_INCLUDES += [
+        'ipc',
+    ]
+
+    include('/ipc/chromium/chromium-config.mozbuild')
+
+    FINAL_LIBRARY = 'xul'
+    LOCAL_INCLUDES += [
+        '/dom/base',
+    ]
+
+    CFLAGS += CONFIG['GLIB_CFLAGS']
+    CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
+    CXXFLAGS += CONFIG['GLIB_CFLAGS']
+    CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -440,27 +440,25 @@ HTMLImageElement::AfterSetAttr(int32_t a
              HTMLPictureElement::IsPictureEnabled()) {
     PictureSourceSizesChanged(this, attrVal.String(), aNotify);
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
                                             aValue, aNotify);
 }
 
-
 nsresult
 HTMLImageElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
-  // If we are a map and get a mouse click, don't let it be handled by
-  // the Generic Element as this could cause a click event to fire
-  // twice, once by the image frame for the map and once by the Anchor
-  // element. (bug 39723)
+  // We handle image element with attribute ismap in its corresponding frame
+  // element. Set mMultipleActionsPrevented here to prevent the click event
+  // trigger the behaviors in Element::PostHandleEventForLinks
   WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
   if (mouseEvent && mouseEvent->IsLeftClickEvent() && IsMap()) {
-    aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
+    mouseEvent->mFlags.mMultipleActionsPrevented = true;
   }
   return nsGenericHTMLElement::PreHandleEvent(aVisitor);
 }
 
 bool
 HTMLImageElement::IsHTMLFocusable(bool aWithMouse,
                                   bool *aIsFocusable, int32_t *aTabIndex)
 {
new file mode 100644
--- /dev/null
+++ b/dom/html/test/bug1260704_iframe.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript">
+    var noDefault = (location.search.indexOf("noDefault=true") !== -1);
+    var isMap = (location.search.indexOf("isMap=true") !== -1);
+
+    window.addEventListener("load", () => {
+      let image = document.getElementById("testImage");
+      isMap ? image.setAttribute("ismap", "") : image.removeAttribute("ismap");
+      image.addEventListener("click", event => {
+        if (noDefault) {
+          ok(true, "image element prevents default");
+          event.preventDefault();
+        }
+      }, false);
+
+      window.addEventListener("click", event => {
+        ok(true, "expected prevent default = " + noDefault);
+        ok(true, "actual prevent default = " + event.defaultPrevented);
+        ok(event.defaultPrevented == noDefault, "PreventDefault should work fine");
+        if (noDefault) {
+          window.parent.postMessage("finished", "http://mochi.test:8888");
+        }
+      }, false);
+      window.parent.postMessage("started", "http://mochi.test:8888");
+    }, false);
+  </script>
+</head>
+<body>
+<a href="bug1260704_iframe_empty.html">
+  <img id="testImage" src="file_bug1260704.png" width="100" height="100"/>
+</a>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/html/test/bug1260704_iframe_empty.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript">
+    window.addEventListener("load", () => {
+      window.parent.postMessage("empty_frame_loaded", "http://mochi.test:8888");
+    }, false);
+  </script>
+</head>
+<body>
+</body>
+</html>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..df421453c25631353cfe86bde5973fdca15b1ea9
GIT binary patch
literal 91
zc%17D@N?(olHy`uVBq!ia0vp^DIm<q3?#jD*u{YqbAV5XtC5k>QX|f*K(4T-i(`m{
lWU>V7;slYNra*^q1_ss&2F5$COwvGU22WQ%mvv4FO#rqO5n=!U
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -31,24 +31,27 @@ support-files =
   bug448564-echo.sjs
   bug448564-iframe-1.html
   bug448564-iframe-2.html
   bug448564-iframe-3.html
   bug448564-submit.js
   bug499092.html
   bug499092.xml
   bug514856_iframe.html
+  bug1260704_iframe.html
+  bug1260704_iframe_empty.html
   ../../plugins/test/mochitest/plugin-utils.js
   test_non-ascii-cookie.html^headers^
   file_bug209275_1.html
   file_bug209275_2.html
   file_bug209275_3.html
   file_bug297761.html
   file_bug417760.png
   file_bug893537.html
+  file_bug1260704.png
   file_formSubmission_img.jpg
   file_formSubmission_text.txt
   file_fullscreen-api.html
   file_fullscreen-backdrop.html
   file_fullscreen-denied-inner.html
   file_fullscreen-denied.html
   file_fullscreen-esc-exit-inner.html
   file_fullscreen-esc-exit.html
@@ -615,9 +618,10 @@ skip-if = buildapp == 'b2g' # bug 112901
 [test_bug1203668.html]
 [test_bug1166138.html]
 [test_bug1230665.html]
 [test_filepicker_default_directory.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
 [test_bug1233598.html]
 [test_bug1250401.html]
 [test_bug1260664.html]
+[test_bug1260704.html]
 [test_allowMedia.html]
new file mode 100644
--- /dev/null
+++ b/dom/html/test/test_bug1260704.html
@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1260704
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1260704</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript">
+    /** Test for Bug 1260704 **/
+
+function runTests() {
+  let testIdx = -1;
+  let testUrls = [
+    "bug1260704_iframe.html?noDefault=true&isMap=true",
+    "bug1260704_iframe.html?noDefault=true&isMap=false",
+    "bug1260704_iframe.html?noDefault=false&isMap=true",
+    "bug1260704_iframe.html?noDefault=false&isMap=false"
+  ];
+
+  let runningTest = false;
+  let iframe = document.getElementById("testFrame");
+  let iframeWin = iframe.contentWindow;
+  let emptySearch = "";
+  let searchWithCoordinates;
+
+  window.addEventListener("message", event => {
+    if (event.data == "started") {
+      ok(!runningTest, "Start to test " + testIdx);
+      runningTest = true;
+
+      let rect = iframeWin.document.getElementById("testImage").getBoundingClientRect();
+      let x = rect.left + rect.width / 2;
+      let y = rect.top + rect.height / 2;
+      searchWithCoordinates = "?" + rect.width / 2 + "," + rect.height / 2;
+      synthesizeMouseAtPoint(x, y, { type: 'mousedown' }, iframeWin);
+      synthesizeMouseAtPoint(x, y, { type: 'mouseup' }, iframeWin);
+    }
+    else if (runningTest && event.data == "empty_frame_loaded") {
+      ok(testUrls[testIdx].includes("noDefault=false"), "Page unload");
+      let search = iframeWin.location.search;
+        
+      //url trigger by image with ismap attribute should contains coordinates
+      let expectSearch = testUrls[testIdx].includes("isMap=true") ?
+                         searchWithCoordinates : emptySearch;
+      ok(search == expectSearch, "expect:" + expectSearch + " got:" + search);
+      nextTest();
+    }
+    else if (runningTest && event.data == "finished") {
+      ok(testUrls[testIdx].includes("noDefault=true"), "Page should not leave");
+      nextTest();
+    }
+  }, false);
+
+  function nextTest() {
+    testIdx++;
+    runningTest = false;
+    if (testIdx >= testUrls.length) {
+      SimpleTest.finish();
+    } else {
+      ok(true, "Test " + testIdx + " - Set url to " + testUrls[testIdx]);
+      iframeWin.location.href = testUrls[testIdx];
+    }
+  }
+  nextTest();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(runTests);
+
+  </script>
+</head>
+<body>
+
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<iframe id="testFrame" src="about:blank" width="400" height="400">
+</iframe>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -180,16 +180,21 @@ public:
     ContentParentIterator(CPIteratorPolicy aPolicy, ContentParent* aCurrent)
       : mCurrent(aCurrent),
         mPolicy(aPolicy)
     {
     }
 
     ContentParentIterator begin()
     {
+      // Move the cursor to the first element that matches the policy.
+      while (mPolicy != eAll && mCurrent && !mCurrent->mIsAlive) {
+        mCurrent = mCurrent->LinkedListElement<ContentParent>::getNext();
+      }
+
       return *this;
     }
     ContentParentIterator end()
     {
       return ContentParentIterator(mPolicy, nullptr);
     }
 
     const ContentParentIterator& operator++()
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -157,34 +157,45 @@ public:
   NS_IMETHOD IsReportForBrowser(nsIFrameLoader* aFrameLoader, bool* aResult) override;
 
   // Called when a content process shuts down.
   void Clear() {
     mContentParent = nullptr;
     mActor = nullptr;
   }
 
+  /** Sets the information associated with this hang: this includes the ID of
+   * the plugin which caused the hang as well as the content PID.
+   *
+   * @param aHangData The hang information
+   */
   void SetHangData(const HangData& aHangData) { mHangData = aHangData; }
-  void SetBrowserDumpId(nsAutoString& aId) {
-    mBrowserDumpId = aId;
+
+  /** Sets the ID of the crash dump associated with this hang. When the ID has
+   * been set then the corresponding crash dump will be used for reporting
+   * instead of generating a new one.
+   *
+   * @param aId The ID of the crash dump taken when the hang was detected. */
+  void SetDumpId(nsString& aId) {
+    mDumpId = aId;
   }
 
   void ClearHang() {
     mHangData = HangData();
-    mBrowserDumpId.Truncate();
+    mDumpId.Truncate();
   }
 
 private:
   ~HangMonitoredProcess() {}
 
   // Everything here is main thread-only.
   HangMonitorParent* mActor;
   ContentParent* mContentParent;
   HangData mHangData;
-  nsAutoString mBrowserDumpId;
+  nsAutoString mDumpId;
 };
 
 class HangMonitorParent
   : public PProcessHangMonitorParent
 {
 public:
   explicit HangMonitorParent(ProcessHangMonitor* aMonitor);
   virtual ~HangMonitorParent();
@@ -546,18 +557,26 @@ public:
       mBrowserDumpId(aBrowserDumpId)
   {}
 
   NS_IMETHOD
   Run()
   {
     // chrome process, main thread
     MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+    nsString dumpId;
+    if (mHangData.type() == HangData::TPluginHangData) {
+      const PluginHangData& phd = mHangData.get_PluginHangData();
+      plugins::TakeFullMinidump(phd.pluginId(), phd.contentProcessId(),
+                                mBrowserDumpId, dumpId);
+    }
+
     mProcess->SetHangData(mHangData);
-    mProcess->SetBrowserDumpId(mBrowserDumpId);
+    mProcess->SetDumpId(dumpId);
 
     nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
     observerService->NotifyObservers(mProcess, "process-hang-report", nullptr);
     return NS_OK;
   }
 
 private:
@@ -856,22 +875,21 @@ HangMonitoredProcess::EndStartingDebugge
 NS_IMETHODIMP
 HangMonitoredProcess::TerminatePlugin()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (mHangData.type() != HangData::TPluginHangData) {
     return NS_ERROR_UNEXPECTED;
   }
 
-  // generates a crash report that includes a browser report taken here
-  // earlier, the content process, and any plugin process(es).
+  // Use the multi-process crash report generated earlier.
   uint32_t id = mHangData.get_PluginHangData().pluginId();
   base::ProcessId contentPid = mHangData.get_PluginHangData().contentProcessId();
   plugins::TerminatePlugin(id, contentPid, NS_LITERAL_CSTRING("HangMonitor"),
-                           mBrowserDumpId);
+                           mDumpId);
 
   if (mActor) {
     mActor->CleanupPluginHang(id, false);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -389,17 +389,17 @@ GMPDecryptsAndGeckoDecodesAAC(mozIGeckoM
 
   if (HaveGMPFor(aGMPService,
     NS_ConvertUTF16toUTF8(aKeySystem),
     NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER),
     NS_LITERAL_CSTRING("aac"))) {
     // We do have a GMP for AAC -> Gecko itself does *not* decode AAC.
     return false;
   }
-#if defined(MOZ_WIDEVINE_EME) && defined(XP_WIN)
+#if defined(XP_WIN)
   // Widevine CDM doesn't include an AAC decoder. So if WMF can't
   // decode AAC, and a codec wasn't specified, be conservative
   // and reject the MediaKeys request, since our policy is to prevent
   //  the Adobe GMP's unencrypted AAC decoding path being used to
   // decode content decrypted by the Widevine CDM.
   if (aKeySystem.EqualsLiteral("com.widevine.alpha") &&
       !WMFDecoderModule::HasAAC()) {
     if (aDiagnostics) {
@@ -495,56 +495,23 @@ IsSupportedVideo(mozIGeckoMediaPluginSer
   }
   if (IsVP9ContentType(aVideoType) && aKeySystem.EqualsLiteral("org.w3.clearkey")) {
     return GMPDecryptsAndGeckoDecodesVP9(aGMPService, aKeySystem, aVideoType, aDiagnostics);
   }
   return false;
 }
 
 static bool
-IsSupported(mozIGeckoMediaPluginService* aGMPService,
-            const nsAString& aKeySystem,
-            const MediaKeySystemConfiguration& aConfig,
-            DecoderDoctorDiagnostics* aDiagnostics)
-{
-  if (aConfig.mInitDataType.IsEmpty() &&
-      aConfig.mAudioType.IsEmpty() &&
-      aConfig.mVideoType.IsEmpty()) {
-    // Not an old-style request.
-    return false;
-  }
-
-  // Backwards compatibility with legacy MediaKeySystemConfiguration method.
-  if (!aConfig.mInitDataType.IsEmpty() &&
-      !aConfig.mInitDataType.EqualsLiteral("cenc")) {
-    return false;
-  }
-  if (!aConfig.mAudioType.IsEmpty() &&
-      !IsSupportedAudio(aGMPService, aKeySystem, aConfig.mAudioType, aDiagnostics)) {
-    return false;
-  }
-  if (!aConfig.mVideoType.IsEmpty() &&
-      !IsSupportedVideo(aGMPService, aKeySystem, aConfig.mVideoType, aDiagnostics)) {
-    return false;
-  }
-
-  return true;
-}
-
-static bool
 IsSupportedInitDataType(const nsString& aCandidate, const nsAString& aKeySystem)
 {
   // All supported keySystems can handle "cenc" initDataType.
   // ClearKey also supports "keyids" and "webm" initDataTypes.
   return aCandidate.EqualsLiteral("cenc") ||
     ((aKeySystem.EqualsLiteral("org.w3.clearkey")
-#ifdef MOZ_WIDEVINE_EME
-    || aKeySystem.EqualsLiteral("com.widevine.alpha")
-#endif
-    ) &&
+    || aKeySystem.EqualsLiteral("com.widevine.alpha")) &&
     (aCandidate.EqualsLiteral("keyids") || aCandidate.EqualsLiteral("webm")));
 }
 
 static bool
 GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
                    const nsAString& aKeySystem,
                    const MediaKeySystemConfiguration& aCandidate,
                    MediaKeySystemConfiguration& aOutConfig,
@@ -587,17 +554,17 @@ GetSupportedConfig(mozIGeckoMediaPluginS
     }
     if (caps.IsEmpty()) {
       return false;
     }
     config.mVideoCapabilities.Construct();
     config.mVideoCapabilities.Value().Assign(caps);
   }
 
-#if defined(MOZ_WIDEVINE_EME) && defined(XP_WIN)
+#if defined(XP_WIN)
   // Widevine CDM doesn't include an AAC decoder. So if WMF can't decode AAC,
   // and a codec wasn't specified, be conservative and reject the MediaKeys request.
   if (aKeySystem.EqualsLiteral("com.widevine.alpha") &&
       (!aCandidate.mAudioCapabilities.WasPassed() ||
        !aCandidate.mVideoCapabilities.WasPassed()) &&
      !WMFDecoderModule::HasAAC()) {
     if (aDiagnostics) {
       aDiagnostics->SetKeySystemIssue(
@@ -607,44 +574,16 @@ GetSupportedConfig(mozIGeckoMediaPluginS
   }
 #endif
 
   aOutConfig = config;
 
   return true;
 }
 
-// Backwards compatibility with legacy requestMediaKeySystemAccess with fields
-// from old MediaKeySystemOptions dictionary.
-/* static */
-bool
-MediaKeySystemAccess::IsSupported(const nsAString& aKeySystem,
-                                  const Sequence<MediaKeySystemConfiguration>& aConfigs,
-                                  DecoderDoctorDiagnostics* aDiagnostics)
-{
-  nsCOMPtr<mozIGeckoMediaPluginService> mps =
-    do_GetService("@mozilla.org/gecko-media-plugin-service;1");
-  if (NS_WARN_IF(!mps)) {
-    return false;
-  }
-
-  if (!HaveGMPFor(mps,
-                  NS_ConvertUTF16toUTF8(aKeySystem),
-                  NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
-    return false;
-  }
-
-  for (const MediaKeySystemConfiguration& config : aConfigs) {
-    if (mozilla::dom::IsSupported(mps, aKeySystem, config, aDiagnostics)) {
-      return true;
-    }
-  }
-  return false;
-}
-
 /* static */
 bool
 MediaKeySystemAccess::GetSupportedConfig(const nsAString& aKeySystem,
                                          const Sequence<MediaKeySystemConfiguration>& aConfigs,
                                          MediaKeySystemConfiguration& aOutConfig,
                                          DecoderDoctorDiagnostics* aDiagnostics)
 {
   nsCOMPtr<mozIGeckoMediaPluginService> mps =
--- a/dom/media/eme/MediaKeySystemAccessManager.cpp
+++ b/dom/media/eme/MediaKeySystemAccessManager.cpp
@@ -164,20 +164,17 @@ MediaKeySystemAccessManager::Request(Det
     aPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
                           NS_LITERAL_CSTRING("GetKeySystemAccess failed"));
     diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
                                           aKeySystem, false, __func__);
     return;
   }
 
   MediaKeySystemConfiguration config;
-  // TODO: Remove IsSupported() check here once we remove backwards
-  // compatibility with initial implementation...
-  if (MediaKeySystemAccess::GetSupportedConfig(keySystem, aConfigs, config, &diagnostics) ||
-      MediaKeySystemAccess::IsSupported(keySystem, aConfigs, &diagnostics)) {
+  if (MediaKeySystemAccess::GetSupportedConfig(keySystem, aConfigs, config, &diagnostics)) {
     RefPtr<MediaKeySystemAccess> access(
       new MediaKeySystemAccess(mWindow, keySystem, NS_ConvertUTF8toUTF16(cdmVersion), config));
     aPromise->MaybeResolve(access);
     diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(),
                                           aKeySystem, true, __func__);
     return;
   }
   // Not to inform user, because nothing to do if the corresponding keySystem
--- a/dom/media/systemservices/CamerasChild.cpp
+++ b/dom/media/systemservices/CamerasChild.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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 "CamerasChild.h"
-#include "CamerasUtils.h"
 
 #include "webrtc/video_engine/include/vie_capture.h"
 #undef FF
 
 #include "mozilla/Assertions.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/Logging.h"
@@ -48,19 +47,18 @@ public:
 
   NS_IMETHOD Run() override {
     // Try to get the PBackground handle
     ipc::PBackgroundChild* existingBackgroundChild =
       ipc::BackgroundChild::GetForCurrentThread();
     // If it's not spun up yet, block until it is, and retry
     if (!existingBackgroundChild) {
       LOG(("No existingBackgroundChild"));
-      SynchronouslyCreatePBackground();
       existingBackgroundChild =
-        ipc::BackgroundChild::GetForCurrentThread();
+        ipc::BackgroundChild::SynchronouslyCreateForCurrentThread();
       LOG(("BackgroundChild: %p", existingBackgroundChild));
     }
     // By now PBackground is guaranteed to be up
     MOZ_RELEASE_ASSERT(existingBackgroundChild);
 
     // Create CamerasChild
     // We will be returning the resulting pointer (synchronously) to our caller.
     mCamerasChild =
@@ -89,17 +87,18 @@ GetCamerasChild() {
     if (NS_FAILED(rv)) {
       LOG(("Error launching IPC Thread"));
       return nullptr;
     }
 
     // At this point we are in the MediaManager thread, and the thread we are
     // dispatching to is the specific Cameras IPC thread that was just made
     // above, so now we will fire off a runnable to run
-    // SynchronouslyCreatePBackground there, while we block in this thread.
+    // BackgroundChild::SynchronouslyCreateForCurrentThread there, while we
+    // block in this thread.
     // We block until the following happens in the Cameras IPC thread:
     // 1) Creation of PBackground finishes
     // 2) Creation of PCameras finishes by sending a message to the parent
     RefPtr<InitializeIPCThread> runnable = new InitializeIPCThread();
     RefPtr<SyncRunnable> sr = new SyncRunnable(runnable);
     sr->DispatchToThread(CamerasSingleton::Thread());
     CamerasSingleton::Child() = runnable->GetCamerasChild();
   }
@@ -482,24 +481,24 @@ Shutdown(void)
     return;
   }
   child->ShutdownAll();
 }
 
 class ShutdownRunnable : public Runnable {
 public:
   explicit
-  ShutdownRunnable(RefPtr<Runnable> aReplyEvent)
+  ShutdownRunnable(already_AddRefed<Runnable>&& aReplyEvent)
     : mReplyEvent(aReplyEvent) {};
 
   NS_IMETHOD Run() override {
     LOG(("Closing BackgroundChild"));
     ipc::BackgroundChild::CloseForCurrentThread();
 
-    NS_DispatchToMainThread(mReplyEvent);
+    NS_DispatchToMainThread(mReplyEvent.forget());
 
     return NS_OK;
   }
 
 private:
   RefPtr<Runnable> mReplyEvent;
 };
 
@@ -539,20 +538,20 @@ CamerasChild::ShutdownParent()
 void
 CamerasChild::ShutdownChild()
 {
   // Called with CamerasSingleton::Mutex() held
   if (CamerasSingleton::Thread()) {
     LOG(("PBackground thread exists, dispatching close"));
     // Dispatch closing the IPC thread back to us when the
     // BackgroundChild is closed.
-    RefPtr<Runnable> event =
-      new ThreadDestructor(CamerasSingleton::Thread());
-    RefPtr<ShutdownRunnable> runnable = new ShutdownRunnable(event);
-    CamerasSingleton::Thread()->Dispatch(runnable, NS_DISPATCH_NORMAL);
+    RefPtr<ShutdownRunnable> runnable =
+      new ShutdownRunnable(NewRunnableMethod(CamerasSingleton::Thread(),
+                                             &nsIThread::Shutdown));
+    CamerasSingleton::Thread()->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
   } else {
     LOG(("Shutdown called without PBackground thread"));
   }
   LOG(("Erasing sCameras & thread refs (original thread)"));
   CamerasSingleton::Child() = nullptr;
   CamerasSingleton::Thread() = nullptr;
 }
 
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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 "CamerasParent.h"
-#include "CamerasUtils.h"
 #include "MediaEngine.h"
 #include "MediaUtils.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/unused.h"
 #include "mozilla/Services.h"
 #include "mozilla/Logging.h"
 #include "mozilla/ipc/BackgroundParent.h"
deleted file mode 100644
--- a/dom/media/systemservices/CamerasUtils.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et ft=cpp : */
-/* 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 "mozilla/unused.h"
-#include "nsThreadUtils.h"
-#include "nsCOMPtr.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/ipc/BackgroundChild.h"
-#include "mozilla/ipc/PBackgroundChild.h"
-#include "nsIIPCBackgroundChildCreateCallback.h"
-
-namespace mozilla {
-namespace camera {
-
-class WorkerBackgroundChildCallback final :
-  public nsIIPCBackgroundChildCreateCallback
-{
-  bool* mDone;
-
-public:
-  explicit WorkerBackgroundChildCallback(bool* aDone)
-  : mDone(aDone)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-    MOZ_ASSERT(mDone);
-  }
-
-  NS_DECL_ISUPPORTS
-
-private:
-  ~WorkerBackgroundChildCallback() { }
-
-  virtual void
-  ActorCreated(PBackgroundChild* aActor) override
-  {
-    *mDone = true;
-  }
-
-  virtual void
-  ActorFailed() override
-  {
-    *mDone = true;
-  }
-};
-NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
-
-nsresult
-SynchronouslyCreatePBackground()
-{
-  using mozilla::ipc::BackgroundChild;
-
-  MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
-
-  bool done = false;
-  nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
-    new WorkerBackgroundChildCallback(&done);
-
-  if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsIThread *thread = NS_GetCurrentThread();
-
-  while (!done) {
-    if (NS_WARN_IF(!NS_ProcessNextEvent(thread, true /* aMayWait */))) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
-}
-}
deleted file mode 100644
--- a/dom/media/systemservices/CamerasUtils.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set sw=2 ts=8 et ft=cpp : */
-/* 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_CameraUtils_h
-#define mozilla_CameraUtils_h
-
-#include "nsThreadUtils.h"
-#include "nsCOMPtr.h"
-#include "mozilla/UniquePtr.h"
-
-#include "base/thread.h"
-
-namespace mozilla {
-namespace camera {
-
-nsresult SynchronouslyCreatePBackground();
-
-class ThreadDestructor : public Runnable
-{
-  DISALLOW_COPY_AND_ASSIGN(ThreadDestructor);
-
-public:
-  explicit ThreadDestructor(nsIThread* aThread)
-    : mThread(aThread) {}
-
-  NS_IMETHOD Run() override
-  {
-    if (mThread) {
-      mThread->Shutdown();
-    }
-    return NS_OK;
-  }
-
-private:
-  ~ThreadDestructor() {}
-  nsCOMPtr<nsIThread> mThread;
-};
-
-}
-}
-
-#endif // mozilla_CameraUtils_h
--- a/dom/media/systemservices/moz.build
+++ b/dom/media/systemservices/moz.build
@@ -3,25 +3,23 @@
 # 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/.
 
 if CONFIG['MOZ_WEBRTC']:
     EXPORTS += [
         'CamerasChild.h',
         'CamerasParent.h',
-        'CamerasUtils.h',
         'LoadManager.h',
         'LoadManagerFactory.h',
         'LoadMonitor.h',
     ]
     UNIFIED_SOURCES += [
         'CamerasChild.cpp',
         'CamerasParent.cpp',
-        'CamerasUtils.cpp',
         'LoadManager.cpp',
         'LoadManagerFactory.cpp',
         'LoadMonitor.cpp',
         'ShmemPool.cpp',
     ]
     LOCAL_INCLUDES += [
         '/media/webrtc/signaling',
         '/media/webrtc/trunk',
--- a/dom/media/test/test_eme_detach_media_keys.html
+++ b/dom/media/test/test_eme_detach_media_keys.html
@@ -14,17 +14,17 @@
 
 SimpleTest.waitForExplicitFinish();
 
 const keysystem = 'org.w3.clearkey';
 
 function createAndSet() {
   return new Promise(function(resolve, reject) {
     var m;
-    navigator.requestMediaKeySystemAccess(keysystem, [{initDataType: 'cenc'}])
+    navigator.requestMediaKeySystemAccess(keysystem, [{initDataTypes: ['cenc']}])
     .then(function (access) {
       return access.createMediaKeys();
     }).then(function (mediaKeys) {
       m = mediaKeys;
       return document.getElementById("v").setMediaKeys(mediaKeys);
     }).then(function() {
       resolve(m);
     });
--- a/dom/media/test/test_eme_initDataTypes.html
+++ b/dom/media/test/test_eme_initDataTypes.html
@@ -103,17 +103,17 @@ function PrepareInitData(initDataType, i
     return new TextEncoder().encode(initData);
   } else if (initDataType == "webm") {
     return StringToArrayBuffer(atob(initData));
   }
 }
 
 function Test(test) {
   return new Promise(function(resolve, reject) {
-    navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{initDataTypes: ['keyids']}]).then(
+    navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{initDataTypes: [test.initDataType]}]).then(
       (access) => access.createMediaKeys()
       ).then(
         (mediaKeys) => {
           var session = mediaKeys.createSession(test.sessionType);
           session.addEventListener("message", function(event) {
             is(event.messageType, "license-request", "'" + test.name + "' MediaKeyMessage type should be license-request.");
             var text = new TextDecoder().decode(event.message);
             is(text, test.expectedRequest, "'" + test.name + "' got expected response.");
--- a/dom/media/test/test_eme_requestKeySystemAccess.html
+++ b/dom/media/test/test_eme_requestKeySystemAccess.html
@@ -523,60 +523,16 @@ var tests = [
     options: [
       {
         initDataTypes: ['cenc'],
         videoCapabilities: [{contentType: 'video/mp4'}],
       }
     ],
     shouldPass: false
   },
-
-  // Test legacy support. Remove when we remove backwards compatibility.
-  {
-    name: 'Legacy CENC',
-    keySystem: CLEARKEY_ID,
-    options: [
-      {
-        initDataType: 'cenc',
-      }
-    ],
-    expectedConfig: {
-      label: ''
-    },
-    shouldPass: true,
-  },
-  {
-    name: 'Legacy CENC + MP4 video',
-    keySystem: CLEARKEY_ID,
-    options: [
-      {
-        initDataType: 'cenc',
-        videoType: 'video/mp4; codecs="avc1.42E01E"',
-      }
-    ],
-    expectedConfig: {
-      label: ''
-    },
-    shouldPass: true,
-  },
-  {
-    name: 'Legacy CENC + MP4 video + MP4 audio',
-    keySystem: CLEARKEY_ID,
-    options: [
-      {
-        initDataType: 'cenc',
-        videoType: 'video/mp4; codecs="avc1.42E01E"',
-        audioType: 'audio/mp4; codecs="mp4a.40.2"',
-      }
-    ],
-    expectedConfig: {
-      label: ''
-    },
-    shouldPass: true,
-  },
 ];
 
 function beginTest() {
   Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); });
 }
 
 if (!IsMacOSSnowLeopardOrEarlier()) {
   SimpleTest.waitForExplicitFinish();
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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 "nsIPrefService.h"
 #include "nsIPrefBranch.h"
-#include "CamerasUtils.h"
 
 #include "CSFLog.h"
 #include "prenv.h"
 
 #include "mozilla/Logging.h"
 #ifdef XP_WIN
 #include "mozilla/WindowsVersion.h"
 #endif
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -56,16 +56,17 @@ DIRS += [
     'devicestorage',
     'encoding',
     'events',
     'fetch',
     'filehandle',
     'filesystem',
     'flyweb',
     'fmradio',
+    'gamepad',
     'geolocation',
     'html',
     'icc',
     'inputport',
     'json',
     'jsurl',
     'asmjscache',
     'mathml',
@@ -130,19 +131,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
 if CONFIG['MOZ_B2G_RIL']:
     DIRS += [
         'wappush',
     ]
 
 if CONFIG['MOZ_PAY']:
     DIRS += ['payment']
 
-if CONFIG['MOZ_GAMEPAD']:
-    DIRS += ['gamepad']
-
 if CONFIG['MOZ_NFC']:
     DIRS += ['nfc']
 
 if CONFIG['MOZ_SIMPLEPUSH']:
     DIRS += ['simplepush']
 else:
     DIRS += ['push']
 
--- a/dom/plugins/ipc/PluginBridge.h
+++ b/dom/plugins/ipc/PluginBridge.h
@@ -22,17 +22,23 @@ SetupBridge(uint32_t aPluginId, dom::Con
             bool aForceBridgeNow, nsresult* aResult, uint32_t* aRunID);
 
 nsresult
 FindPluginsForContent(uint32_t aPluginEpoch,
                       nsTArray<PluginTag>* aPlugins,
                       uint32_t* aNewPluginEpoch);
 
 void
+TakeFullMinidump(uint32_t aPluginId,
+                 base::ProcessId aContentProcessId,
+                 const nsAString& aBrowserDumpId,
+                 nsString& aDumpId);
+
+void
 TerminatePlugin(uint32_t aPluginId,
                 base::ProcessId aContentProcessId,
                 const nsCString& aMonitorDescription,
-                const nsAString& aBrowserDumpId);
+                const nsAString& aDumpId);
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // mozilla_plugins_PluginBridge_h
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -348,36 +348,60 @@ private:
 
 PRCList PluginModuleMapping::sModuleListHead =
     PR_INIT_STATIC_CLIST(&PluginModuleMapping::sModuleListHead);
 
 bool PluginModuleMapping::sIsLoadModuleOnStack = false;
 
 } // namespace
 
+static PluginModuleChromeParent*
+PluginModuleChromeParentForId(const uint32_t aPluginId)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
+  nsPluginTag* pluginTag = host->PluginWithId(aPluginId);
+  if (!pluginTag || !pluginTag->mPlugin) {
+    return nullptr;
+  }
+  RefPtr<nsNPAPIPlugin> plugin = pluginTag->mPlugin;
+
+  return static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
+}
+
+void
+mozilla::plugins::TakeFullMinidump(uint32_t aPluginId,
+                                   base::ProcessId aContentProcessId,
+                                   const nsAString& aBrowserDumpId,
+                                   nsString& aDumpId)
+{
+  PluginModuleChromeParent* chromeParent =
+    PluginModuleChromeParentForId(aPluginId);
+
+  if (chromeParent) {
+    chromeParent->TakeFullMinidump(aContentProcessId, aBrowserDumpId, aDumpId);
+  }
+}
+
 void
 mozilla::plugins::TerminatePlugin(uint32_t aPluginId,
                                   base::ProcessId aContentProcessId,
                                   const nsCString& aMonitorDescription,
-                                  const nsAString& aBrowserDumpId)
+                                  const nsAString& aDumpId)
 {
-    MOZ_ASSERT(XRE_IsParentProcess());
-
-    RefPtr<nsPluginHost> host = nsPluginHost::GetInst();
-    nsPluginTag* pluginTag = host->PluginWithId(aPluginId);
-    if (!pluginTag || !pluginTag->mPlugin) {
-        return;
-    }
-    RefPtr<nsNPAPIPlugin> plugin = pluginTag->mPlugin;
-    PluginModuleChromeParent* chromeParent =
-        static_cast<PluginModuleChromeParent*>(plugin->GetLibrary());
+  PluginModuleChromeParent* chromeParent =
+    PluginModuleChromeParentForId(aPluginId);
+
+  if (chromeParent) {
     chromeParent->TerminateChildProcess(MessageLoop::current(),
                                         aContentProcessId,
                                         aMonitorDescription,
-                                        aBrowserDumpId);
+                                        aDumpId);
+  }
 }
 
 /* static */ PluginLibrary*
 PluginModuleContentParent::LoadModule(uint32_t aPluginId,
                                       nsPluginTag* aPluginTag)
 {
     PluginModuleMapping::NotifyLoadingModule loadingModule;
     nsAutoPtr<PluginModuleMapping> mapping(
@@ -1193,48 +1217,29 @@ PluginModuleContentParent::ShouldContinu
 
 void
 PluginModuleContentParent::OnExitedSyncSend()
 {
     ProcessHangMonitor::ClearHang();
 }
 
 void
-PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
-                                                base::ProcessId aContentPid,
-                                                const nsCString& aMonitorDescription,
-                                                const nsAString& aBrowserDumpId)
+PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid,
+                                           const nsAString& aBrowserDumpId,
+                                           nsString& aDumpId)
 {
 #ifdef MOZ_CRASHREPORTER
 #ifdef XP_WIN
     mozilla::MutexAutoLock lock(mCrashReporterMutex);
-    CrashReporterParent* crashReporter = mCrashReporter;
+#endif // XP_WIN
+
+    CrashReporterParent* crashReporter = CrashReporter();
     if (!crashReporter) {
-        // If mCrashReporter is null then the hang has ended, the plugin module
-        // is shutting down. There's nothing to do here.
         return;
     }
-#else
-    CrashReporterParent* crashReporter = CrashReporter();
-#endif
-    crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"),
-                                       NS_LITERAL_CSTRING("1"));
-    crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("HangMonitorDescription"),
-                                       aMonitorDescription);
-#ifdef XP_WIN
-    if (mHangUIParent) {
-        unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
-        if (hangUIDuration) {
-            nsPrintfCString strHangUIDuration("%u", hangUIDuration);
-            crashReporter->AnnotateCrashReport(
-                    NS_LITERAL_CSTRING("PluginHangUIDuration"),
-                    strHangUIDuration);
-        }
-    }
-#endif // XP_WIN
 
     bool reportsReady = false;
 
     // Check to see if we already have a browser dump id - with e10s plugin
     // hangs we take this earlier (see ProcessHangMonitor) from a background
     // thread. We do this before we message the main thread about the hang
     // since the posted message will trash our browser stack state.
     bool exists;
@@ -1261,16 +1266,17 @@ PluginModuleChromeParent::TerminateChild
     if (!reportsReady) {
         reportsReady = crashReporter->GeneratePairedMinidump(this);
     }
 
     if (reportsReady) {
         // Important to set this here, it tells the ActorDestroy handler
         // that we have an existing crash report that needs to be finalized.
         mPluginDumpID = crashReporter->ChildDumpID();
+        aDumpId = mPluginDumpID;
         PLUGIN_LOG_DEBUG(
                 ("generated paired browser/plugin minidumps: %s)",
                  NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
         nsAutoCString additionalDumps("browser");
         nsCOMPtr<nsIFile> pluginDumpFile;
         if (GetMinidumpForID(mPluginDumpID, getter_AddRefs(pluginDumpFile)) &&
             pluginDumpFile) {
 #ifdef MOZ_CRASHREPORTER_INJECTOR
@@ -1279,33 +1285,77 @@ PluginModuleChromeParent::TerminateChild
             if (CreatePluginMinidump(mFlashProcess1, 0, pluginDumpFile,
                                      NS_LITERAL_CSTRING("flash1"))) {
                 additionalDumps.AppendLiteral(",flash1");
             }
             if (CreatePluginMinidump(mFlashProcess2, 0, pluginDumpFile,
                                      NS_LITERAL_CSTRING("flash2"))) {
                 additionalDumps.AppendLiteral(",flash2");
             }
-#endif
+#endif // MOZ_CRASHREPORTER_INJECTOR
             if (aContentPid != mozilla::ipc::kInvalidProcessId) {
                 // Include the content process minidump
                 if (CreatePluginMinidump(aContentPid, 0,
                                          pluginDumpFile,
                                          NS_LITERAL_CSTRING("content"))) {
                     additionalDumps.AppendLiteral(",content");
                 }
             }
         }
         crashReporter->AnnotateCrashReport(
             NS_LITERAL_CSTRING("additional_minidumps"),
             additionalDumps);
     } else {
         NS_WARNING("failed to capture paired minidumps from hang");
     }
-#endif
+#endif // MOZ_CRASHREPORTER
+}
+
+void
+PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
+                                                base::ProcessId aContentPid,
+                                                const nsCString& aMonitorDescription,
+                                                const nsAString& aDumpId)
+{
+#ifdef MOZ_CRASHREPORTER
+    // Start by taking a full minidump if necessary, this is done early
+    // because it also needs to lock the mCrashReporterMutex and Mutex doesn't
+    // support recrusive locking.
+    nsAutoString dumpId;
+    if (aDumpId.IsEmpty()) {
+        TakeFullMinidump(aContentPid, EmptyString(), dumpId);
+    }
+
+#ifdef XP_WIN
+    mozilla::MutexAutoLock lock(mCrashReporterMutex);
+    CrashReporterParent* crashReporter = mCrashReporter;
+    if (!crashReporter) {
+        // If mCrashReporter is null then the hang has ended, the plugin module
+        // is shutting down. There's nothing to do here.
+        return;
+    }
+#else
+    CrashReporterParent* crashReporter = CrashReporter();
+#endif // XP_WIN
+    crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"),
+                                       NS_LITERAL_CSTRING("1"));
+    crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("HangMonitorDescription"),
+                                       aMonitorDescription);
+#ifdef XP_WIN
+    if (mHangUIParent) {
+        unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
+        if (hangUIDuration) {
+            nsPrintfCString strHangUIDuration("%u", hangUIDuration);
+            crashReporter->AnnotateCrashReport(
+                    NS_LITERAL_CSTRING("PluginHangUIDuration"),
+                    strHangUIDuration);
+        }
+    }
+#endif // XP_WIN
+#endif // MOZ_CRASHREPORTER
 
     mozilla::ipc::ScopedProcessHandle geckoChildProcess;
     bool childOpened = base::OpenProcessHandle(OtherPid(),
                                                &geckoChildProcess.rwget());
 
 #ifdef XP_WIN
     // collect cpu usage for plugin processes
 
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -414,36 +414,55 @@ class PluginModuleChromeParent
      * was instantiated by the plugin host.
      */
     static void ClearInstantiationFlag() { sInstantiated = false; }
     static bool DidInstantiate() { return sInstantiated; }
 
     virtual ~PluginModuleChromeParent();
 
     /*
+     * Takes a full multi-process dump including the plugin process and the
+     * content process. If aBrowserDumpId is not empty then the browser dump
+     * associated with it will be paired to the resulting minidump.
+     * Takes ownership of the file associated with aBrowserDumpId.
+     *
+     * @param aContentPid PID of the e10s content process from which a hang was
+     *   reported. May be kInvalidProcessId if not applicable.
+     * @param aBrowserDumpId (optional) previously taken browser dump id. If
+     *   provided TakeFullMinidump will use this dump file instead of
+     *   generating a new one. If not provided a browser dump will be taken at
+     *   the time of this call.
+     * @param aDumpId Returns the ID of the newly generated crash dump. Left
+     *   untouched upon failure.
+     */
+    void TakeFullMinidump(base::ProcessId aContentPid,
+                          const nsAString& aBrowserDumpId,
+                          nsString& aDumpId);
+
+    /*
      * Terminates the plugin process associated with this plugin module. Also
-     * generates appropriate crash reports. Takes ownership of the file
-     * associated with aBrowserDumpId on success.
+     * generates appropriate crash reports unless an existing one is provided.
+     * Takes ownership of the file associated with aDumpId on success.
      *
      * @param aMsgLoop the main message pump associated with the module
      *   protocol.
      * @param aContentPid PID of the e10s content process from which a hang was
      *   reported. May be kInvalidProcessId if not applicable.
      * @param aMonitorDescription a string describing the hang monitor that
      *   is making this call. This string is added to the crash reporter
      *   annotations for the plugin process.
-     * @param aBrowserDumpId (optional) previously taken browser dump id. If
-     *   provided TerminateChildProcess will use this browser dump file in
-     *   generating a multi-process crash report. If not provided a browser
-     *   dump will be taken at the time of this call.
+     * @param aDumpId (optional) previously taken dump id. If provided
+     *   TerminateChildProcess will use this dump file instead of generating a
+     *   multi-process crash report. If not provided a multi-process dump will
+     *   be taken at the time of this call.
      */
     void TerminateChildProcess(MessageLoop* aMsgLoop,
                                base::ProcessId aContentPid,
                                const nsCString& aMonitorDescription,
-                               const nsAString& aBrowserDumpId);
+                               const nsAString& aDumpId);
 
 #ifdef XP_WIN
     /**
      * Called by Plugin Hang UI to notify that the user has clicked continue.
      * Used for chrome hang annotations.
      */
     void
     OnHangUIContinue();
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -311,16 +311,49 @@ permitsScheme(const nsAString& aEnforcem
   // See nsHttpChannel::Connect() and also WebSocket.cpp. Please note,
   // the report only policies should not allow the load and report
   // the error back to the page.
   return ((aUpgradeInsecure && !aReportOnly) &&
           ((scheme.EqualsASCII("http") && aEnforcementScheme.EqualsASCII("https")) ||
            (scheme.EqualsASCII("ws") && aEnforcementScheme.EqualsASCII("wss"))));
 }
 
+/*
+ * A helper function for appending a CSP header to an existing CSP
+ * policy.
+ *
+ * @param aCsp           the CSP policy
+ * @param aHeaderValue   the header
+ * @param aReportOnly    is this a report-only header?
+ */
+
+nsresult
+CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp,
+                        const nsAString& aHeaderValue,
+                        bool aReportOnly)
+{
+  NS_ENSURE_ARG(aCsp);
+
+  // Need to tokenize the header value since multiple headers could be
+  // concatenated into one comma-separated list of policies.
+  // See RFC2616 section 4.2 (last paragraph)
+  nsresult rv = NS_OK;
+  nsCharSeparatedTokenizer tokenizer(aHeaderValue, ',');
+  while (tokenizer.hasMoreTokens()) {
+    const nsSubstring& policy = tokenizer.nextToken();
+    rv = aCsp->AppendPolicy(policy, aReportOnly, false);
+    NS_ENSURE_SUCCESS(rv, rv);
+    {
+      CSPUTILSLOG(("CSP refined with policy: \"%s\"",
+                   NS_ConvertUTF16toUTF8(policy).get()));
+    }
+  }
+  return NS_OK;
+}
+
 /* ===== nsCSPSrc ============================ */
 
 nsCSPBaseSrc::nsCSPBaseSrc()
 {
 }
 
 nsCSPBaseSrc::~nsCSPBaseSrc()
 {
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -171,16 +171,20 @@ inline CSPKeyword CSP_KeywordToEnum(cons
     if (lowerKey.EqualsASCII(CSPStrKeywords[i])) {
       return static_cast<CSPKeyword>(i);
     }
   }
   NS_ASSERTION(false, "Can not convert unknown Keyword to Enum");
   return CSP_LAST_KEYWORD_VALUE;
 }
 
+nsresult CSP_AppendCSPFromHeader(nsIContentSecurityPolicy* aCsp,
+                                 const nsAString& aHeaderValue,
+                                 bool aReportOnly);
+
 /* =============== Helpers ================== */
 
 class nsCSPHostSrc;
 
 nsCSPHostSrc* CSP_CreateHostSrcFromURI(nsIURI* aURI);
 bool CSP_IsValidDirective(const nsAString& aDir);
 bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir);
 bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey);
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child_worker.js
@@ -0,0 +1,39 @@
+function doXHR(uri) {
+  try {
+    var xhr = new XMLHttpRequest();
+    xhr.open("GET", uri);
+    xhr.send();
+  } catch(ex) {}
+}
+
+var sameBase = "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=";
+var crossBase = "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=";
+
+onmessage = (e) => {
+  for (base of [sameBase, crossBase]) {
+    var prefix;
+    var suffix;
+    if (e.data.inherited == "parent") {
+      //Worker inherits CSP from parent worker
+      prefix = base + "worker_child_inherited_parent_";
+      suffix = base == sameBase ? "_good" : "_bad";
+    } else if (e.data.inherited == "document") {
+      //Worker inherits CSP from owner document -> parent worker -> subworker
+      prefix = base + "worker_child_inherited_document_";
+      suffix = base == sameBase ? "_good" : "_bad";
+    } else {
+      // Worker delivers CSP from HTTP header
+      prefix = base + "worker_child_";
+      suffix = base == sameBase ? "_same_bad" : "_cross_bad";
+    }
+
+    doXHR(prefix + "xhr" + suffix);
+    // Fetch is likely failed in subworker
+    // See Bug 1273070 - Failed to fetch in subworker
+    // Enable fetch test after the bug is fixed
+    // fetch(prefix + "xhr" + suffix);
+    try {
+      importScripts(prefix + "script" + suffix);
+    } catch(ex) {}
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_child_worker.js^headers^
@@ -0,0 +1,1 @@
+Content-Security-Policy: default-src 'none'
--- a/dom/security/test/csp/file_main.js
+++ b/dom/security/test/csp/file_main.js
@@ -1,28 +1,53 @@
-function doXHR(uri) {
+function doXHR(uri, callback) {
   try {
     var xhr = new XMLHttpRequest();
     xhr.open("GET", uri);
+    xhr.responseType = "blob";
     xhr.send();
+    xhr.onload = function () {
+      if (callback) callback(xhr.response);
+    }
   } catch(ex) {}
 }
 
 doXHR("http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_good");
 doXHR("http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_bad");
 fetch("http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_good");
 fetch("http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_bad");
 navigator.sendBeacon("http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_good");
 try {
   navigator.sendBeacon("http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_bad");
 } catch(ex) {}
 
+var topWorkerBlob;
+var nestedWorkerBlob;
 
-new Worker("file_main_worker.js").postMessage({inherited : false});
+doXHR("file_main_worker.js", function (topResponse) {
+  topWorkerBlob = URL.createObjectURL(topResponse);
+  doXHR("file_child_worker.js", function (response) {
+    nestedWorkerBlob = URL.createObjectURL(response);
+    runWorker();
+  });
+});
 
+function runWorker() {
+  // Top level worker, no subworker
+  // Worker does not inherit CSP from owner document
+  new Worker("file_main_worker.js").postMessage({inherited : "none"});
 
-var blobxhr = new XMLHttpRequest();
-blobxhr.open("GET", "file_main_worker.js")
-blobxhr.responseType = "blob";
-blobxhr.send();
-blobxhr.onload = () => {
-  new Worker(URL.createObjectURL(blobxhr.response)).postMessage({inherited : true});
+  // Top level worker, no subworker
+  // Worker inherits CSP from owner document
+  new Worker(topWorkerBlob).postMessage({inherited : "document"});
+
+  // Subworker
+  // Worker does not inherit CSP from parent worker
+  new Worker("file_main_worker.js").postMessage({inherited : "none", nested : nestedWorkerBlob});
+
+  // Subworker
+  // Worker inherits CSP from parent worker
+  new Worker("file_main_worker.js").postMessage({inherited : "parent", nested : nestedWorkerBlob});
+
+  // Subworker
+  // Worker inherits CSP from owner document -> parent worker -> subworker
+  new Worker(topWorkerBlob).postMessage({inherited : "document", nested : nestedWorkerBlob});
 }
--- a/dom/security/test/csp/file_main_worker.js
+++ b/dom/security/test/csp/file_main_worker.js
@@ -5,24 +5,44 @@ function doXHR(uri) {
     xhr.send();
   } catch(ex) {}
 }
 
 var sameBase = "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=";
 var crossBase = "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=";
 
 onmessage = (e) => {
+  // Tests of nested worker
+  if (e.data.nested) {
+    if (e.data.inherited != "none") {
+      // Worker inherits CSP
+      new Worker(e.data.nested).postMessage({inherited : e.data.inherited});
+    }
+    else {
+      // Worker does not inherit CSP
+      new Worker("file_child_worker.js").postMessage({inherited : e.data.inherited});
+    }
+    return;
+  }
+
+  //Tests of top level worker
   for (base of [sameBase, crossBase]) {
     var prefix;
     var suffix;
-    if (e.data.inherited) {
-      prefix = base + "worker_inherited_"
+    if (e.data.inherited != "none") {
+      // Top worker inherits CSP from owner document
+      prefix = base + "worker_inherited_";
       suffix = base == sameBase ? "_good" : "_bad";
     }
     else {
-      prefix = base + "worker_"
-      suffix = base == sameBase ? "_same_good" : "_cross_good";
+      // Top worker delivers CSP from HTTP header
+      prefix = base + "worker_";
+      suffix = base == sameBase ? "_same_bad" : "_cross_good";
     }
+
     doXHR(prefix + "xhr" + suffix);
     fetch(prefix + "fetch" + suffix);
-    try { importScripts(prefix + "script" + suffix); } catch(ex) {}
+    try {
+      if (e.data.inherited == "none") suffix = base == sameBase ? "_same_good" : "_cross_bad";
+      importScripts(prefix + "script" + suffix);
+    } catch(ex) {}
   }
 }
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_main_worker.js^headers^
@@ -0,0 +1,1 @@
+Content-Security-Policy: default-src 'self' blob: ; connect-src http://example.com
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -36,16 +36,19 @@ support-files =
   file_inlinestyle_main.html^headers^
   file_inlinestyle_main_allowed.html
   file_inlinestyle_main_allowed.html^headers^
   file_invalid_source_expression.html
   file_main.html
   file_main.html^headers^
   file_main.js
   file_main_worker.js
+  file_main_worker.js^headers^
+  file_child_worker.js
+  file_child_worker.js^headers^
   file_web_manifest.html
   file_web_manifest_remote.html
   file_web_manifest_https.html
   file_web_manifest.json
   file_web_manifest.json^headers^
   file_web_manifest_https.json
   file_web_manifest_mixed_content.html
   file_bug836922_npolicies.html
--- a/dom/security/test/csp/test_CSP.html
+++ b/dom/security/test/csp/test_CSP.html
@@ -24,28 +24,40 @@ window.tests = {
   script_good: -1,
   script_bad: -1,
   xhr_good: -1,
   xhr_bad: -1,
   fetch_good: -1,
   fetch_bad: -1,
   beacon_good: -1,
   beacon_bad: -1,
-  worker_xhr_same_good: -1,
+  worker_xhr_same_bad: -1,
   worker_xhr_cross_good: -1,
-  worker_fetch_same_good: -1,
+  worker_fetch_same_bad: -1,
   worker_fetch_cross_good: -1,
   worker_script_same_good: -1,
-  worker_script_cross_good: -1,
+  worker_script_cross_bad: -1,
   worker_inherited_xhr_good: -1,
   worker_inherited_xhr_bad: -1,
   worker_inherited_fetch_good: -1,
   worker_inherited_fetch_bad: -1,
   worker_inherited_script_good: -1,
   worker_inherited_script_bad: -1,
+  worker_child_xhr_same_bad: -1,
+  worker_child_xhr_cross_bad: -1,
+  worker_child_script_same_bad: -1,
+  worker_child_script_cross_bad: -1,
+  worker_child_inherited_parent_xhr_bad: -1,
+  worker_child_inherited_parent_xhr_good: -1,
+  worker_child_inherited_parent_script_good: -1,
+  worker_child_inherited_parent_script_bad: -1,
+  worker_child_inherited_document_xhr_good: -1,
+  worker_child_inherited_document_xhr_bad: -1,
+  worker_child_inherited_document_script_good: -1,
+  worker_child_inherited_document_script_bad: -1,
   media_good: -1,
   media_bad: -1,
   font_good: -1,
   font_bad: -1,
   object_good: -1,
   object_bad: -1,
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/svg/crashtests/1282985-1.svg
@@ -0,0 +1,24 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+<script>
+<![CDATA[
+
+function boom() {
+    var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
+    g.setAttribute("id", "g");
+    var iframe = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
+    g.appendChild(iframe);
+    document.documentElement.appendChild(g);
+    var use = document.createElementNS("http://www.w3.org/2000/svg", "use");
+    use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#g");
+    document.documentElement.appendChild(use);
+    setTimeout(function() {
+        setTimeout(function() {
+            g.appendChild(document.createElementNS("http://www.w3.org/1999/xhtml", "video"));
+        }, 3);
+    }, 3);
+}
+window.addEventListener("load", boom, false);
+
+]]>
+</script>
+</svg>
--- a/dom/svg/crashtests/crashtests.list
+++ b/dom/svg/crashtests/crashtests.list
@@ -71,11 +71,12 @@ load 880544-2.svg
 load 880544-3.svg
 load 880544-4.svg
 load 880544-5.svg
 load 898915-1.svg
 load 1035248-1.svg
 load 1035248-2.svg
 load 1244898-1.xhtml
 load 1267272-1.svg
+load 1282985-1.svg
 # Disabled for now due to it taking a very long time to run - bug 1259356
 #load long-clipPath-reference-chain.svg
 load zero-size-image.svg
--- a/dom/webidl/MediaKeySystemAccess.webidl
+++ b/dom/webidl/MediaKeySystemAccess.webidl
@@ -17,22 +17,16 @@ dictionary MediaKeySystemMediaCapability
 
 dictionary MediaKeySystemConfiguration {
   DOMString                               label = "";
   sequence<DOMString>                     initDataTypes;
   sequence<MediaKeySystemMediaCapability> audioCapabilities;
   sequence<MediaKeySystemMediaCapability> videoCapabilities;
 
    // TODO: distinctiveIdentifier, persistentState, sessionTypes  
-  
-  // For backwards compatibility with implementations using old
-  // MediaKeySystemOptions paradigm...
-  DOMString            initDataType = "";
-  DOMString            audioType = "";
-  DOMString            videoType = "";
 };
 
 [Pref="media.eme.apiVisible"]
 interface MediaKeySystemAccess {
   readonly    attribute DOMString keySystem;
   [NewObject]
   MediaKeySystemConfiguration getConfiguration();
   [NewObject]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -167,17 +167,16 @@ WEBIDL_FILES = [
     'FlyWebWebSocketEvent.webidl',
     'FocusEvent.webidl',
     'FontFace.webidl',
     'FontFaceSet.webidl',
     'FontFaceSource.webidl',
     'FormData.webidl',
     'Function.webidl',
     'GainNode.webidl',
-    'GamepadServiceTest.webidl',
     'Geolocation.webidl',
     'GeometryUtils.webidl',
     'GetUserMediaRequest.webidl',
     'HDMIInputPort.webidl',
     'Headers.webidl',
     'HeapSnapshot.webidl',
     'History.webidl',
     'HTMLAllCollection.webidl',
@@ -655,16 +654,17 @@ if CONFIG['MOZ_WEBSPEECH']:
         'SpeechSynthesisEvent.webidl',
         'SpeechSynthesisUtterance.webidl',
         'SpeechSynthesisVoice.webidl',
     ]
 
 if CONFIG['MOZ_GAMEPAD']:
     WEBIDL_FILES += [
         'Gamepad.webidl',
+        'GamepadServiceTest.webidl'
     ]
 
 WEBIDL_FILES += [
     'CloseEvent.webidl',
     'CustomEvent.webidl',
     'DeviceOrientationEvent.webidl',
     'DeviceStorageChangeEvent.webidl',
     'DOMTransactionEvent.webidl',
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -972,48 +972,16 @@ public:
 
     microTaskQueue->push(aRunnable);
   }
 
 private:
   WorkerPrivate* mWorkerPrivate;
 };
 
-class WorkerBackgroundChildCallback final :
-  public nsIIPCBackgroundChildCreateCallback
-{
-  bool* mDone;
-
-public:
-  explicit WorkerBackgroundChildCallback(bool* aDone)
-  : mDone(aDone)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-    MOZ_ASSERT(mDone);
-  }
-
-  NS_DECL_ISUPPORTS
-
-private:
-  ~WorkerBackgroundChildCallback()
-  { }
-
-  virtual void
-  ActorCreated(PBackgroundChild* aActor) override
-  {
-    *mDone = true;
-  }
-
-  virtual void
-  ActorFailed() override
-  {
-    *mDone = true;
-  }
-};
-
 class WorkerThreadPrimaryRunnable final : public Runnable
 {
   WorkerPrivate* mWorkerPrivate;
   RefPtr<WorkerThread> mThread;
   JSRuntime* mParentRuntime;
 
   class FinishedRunnable final : public Runnable
   {
@@ -1046,19 +1014,16 @@ public:
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
 private:
   ~WorkerThreadPrimaryRunnable()
   { }
 
-  nsresult
-  SynchronouslyCreatePBackground();
-
   NS_DECL_NSIRUNNABLE
 };
 
 class WorkerTaskRunnable final : public WorkerRunnable
 {
   RefPtr<WorkerTask> mTask;
 
 public:
@@ -2517,18 +2482,16 @@ LogViolationDetailsRunnable::MainThreadR
                                mFileName, scriptSample, mLineNum,
                                EmptyString(), EmptyString());
     }
   }
 
   return true;
 }
 
-NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
-
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, Runnable)
 
 NS_IMETHODIMP
 WorkerThreadPrimaryRunnable::Run()
 {
   using mozilla::ipc::BackgroundChild;
 
 #ifdef MOZ_NUWA_PROCESS
@@ -2544,23 +2507,22 @@ WorkerThreadPrimaryRunnable::Run()
 
   nsAutoCString threadName;
   threadName.AssignLiteral("DOM Worker '");
   threadName.Append(NS_LossyConvertUTF16toASCII(mWorkerPrivate->ScriptURL()));
   threadName.Append('\'');
 
   profiler_register_thread(threadName.get(), &stackBaseGuess);
 
-  // Note: SynchronouslyCreatePBackground() must be called prior to
+  // Note: SynchronouslyCreateForCurrentThread() must be called prior to
   //       mWorkerPrivate->SetThread() in order to avoid accidentally consuming
   //       worker messages here.
-  nsresult rv = SynchronouslyCreatePBackground();
-  if (NS_WARN_IF(NS_FAILED(rv))) {
+  if (NS_WARN_IF(!BackgroundChild::SynchronouslyCreateForCurrentThread())) {
     // XXX need to fire an error at parent.
-    return rv;
+    return NS_ERROR_UNEXPECTED;
   }
 
   mWorkerPrivate->SetThread(mThread);
 
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   {
     nsCycleCollector_startup();
@@ -2643,44 +2605,16 @@ WorkerThreadPrimaryRunnable::Run()
     new FinishedRunnable(mThread.forget());
   MOZ_ALWAYS_SUCCEEDS(mainThread->Dispatch(finishedRunnable,
                                            NS_DISPATCH_NORMAL));
 
   profiler_unregister_thread();
   return NS_OK;
 }
 
-nsresult
-WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground()
-{
-  using mozilla::ipc::BackgroundChild;
-
-  MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
-
-  bool done = false;
-  nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
-    new WorkerBackgroundChildCallback(&done);
-
-  if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
-    return NS_ERROR_FAILURE;
-  }
-
-  while (!done) {
-    if (NS_WARN_IF(!NS_ProcessNextEvent(mThread, true /* aMayWait */))) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
 NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable,
                              Runnable)
 
 NS_IMETHODIMP
 WorkerThreadPrimaryRunnable::FinishedRunnable::Run()
 {
   AssertIsOnMainThread();
 
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScriptLoader.h"
 
 #include "nsIChannel.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIDocShell.h"
+#include "nsIDOMDocument.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIInputStreamPump.h"
 #include "nsIIOService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamLoader.h"
@@ -47,16 +48,18 @@
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/dom/CacheBinding.h"
 #include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/Cache.h"
 #include "mozilla/dom/cache/CacheStorage.h"
 #include "mozilla/dom/ChannelInfo.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/InternalResponse.h"
+#include "mozilla/dom/nsCSPService.h"
+#include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/UniquePtr.h"
 #include "Principal.h"
 #include "WorkerHolder.h"
 #include "WorkerPrivate.h"
@@ -1037,24 +1040,34 @@ private:
     // but then give it a different origin.
     aLoadInfo.mMutedErrorFlag.emplace(IsMainWorkerScript()
                                         ? false 
                                         : !principal->Subsumes(channelPrincipal));
 
     // Make sure we're not seeing the result of a 404 or something by checking
     // the 'requestSucceeded' attribute on the http channel.
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
+    nsAutoCString tCspHeaderValue, tCspROHeaderValue;
+
     if (httpChannel) {
       bool requestSucceeded;
       rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (!requestSucceeded) {
         return NS_ERROR_NOT_AVAILABLE;
       }
+
+      httpChannel->GetResponseHeader(
+        NS_LITERAL_CSTRING("content-security-policy"),
+        tCspHeaderValue);
+
+      httpChannel->GetResponseHeader(
+        NS_LITERAL_CSTRING("content-security-policy-report-only"),
+        tCspROHeaderValue);
     }
 
     // May be null.
     nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
 
     // Use the regular nsScriptLoader for this grunt work! Should be just fine
     // because we're running on the main thread.
     // Unlike <script> tags, Worker scripts are always decoded as UTF-8,
@@ -1150,19 +1163,58 @@ private:
         }
       }
 
       // The principal can change, but it should still match the original
       // load group's appId and browser element flag.
       MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
 
       mWorkerPrivate->SetPrincipal(channelPrincipal, channelLoadGroup);
+
+      // We did inherit CSP in bug 1223647. If we do not already have a CSP, we
+      // should get it from the HTTP headers on the worker script.
+      if (!mWorkerPrivate->GetCSP() && CSPService::sCSPEnabled) {
+        NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
+        NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
+
+        nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
+        MOZ_ASSERT(principal, "Should not be null");
+
+        nsCOMPtr<nsIContentSecurityPolicy> csp;
+        rv = principal->EnsureCSP(nullptr, getter_AddRefs(csp));
+
+        if (csp) {
+          // If there's a CSP header, apply it.
+          if (!cspHeaderValue.IsEmpty()) {
+            rv = CSP_AppendCSPFromHeader(csp, cspHeaderValue, false);
+            NS_ENSURE_SUCCESS(rv, rv);
+          }
+          // If there's a report-only CSP header, apply it.
+          if (!cspROHeaderValue.IsEmpty()) {
+            rv = CSP_AppendCSPFromHeader(csp, cspROHeaderValue, true);
+            NS_ENSURE_SUCCESS(rv, rv);
+          }
+
+          // Set evalAllowed, default value is set in GetAllowsEval
+          bool evalAllowed = false;
+          bool reportEvalViolations = false;
+          rv = csp->GetAllowsEval(&reportEvalViolations, &evalAllowed);
+          NS_ENSURE_SUCCESS(rv, rv);
+
+          mWorkerPrivate->SetCSP(csp);
+          mWorkerPrivate->SetEvalAllowed(evalAllowed);
+          mWorkerPrivate->SetReportCSPViolations(reportEvalViolations);
+        }
+      }
+      if (parent) {
+        // XHR Params Allowed
+        mWorkerPrivate->SetXHRParamsAllowed(parent->XHRParamsAllowed());
+      }
     }
 
-    DataReceived();
     return NS_OK;
   }
 
   void
   DataReceivedFromCache(uint32_t aIndex, const uint8_t* aString,
                         uint32_t aStringLen,
                         const mozilla::dom::ChannelInfo& aChannelInfo,
                         UniquePtr<PrincipalInfo> aPrincipalInfo)
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -664,16 +664,22 @@ public:
   }
 
   bool
   GetReportCSPViolations() const
   {
     return mLoadInfo.mReportCSPViolations;
   }
 
+  void
+  SetReportCSPViolations(bool aReport)
+  {
+    mLoadInfo.mReportCSPViolations = aReport;
+  }
+
   bool
   XHRParamsAllowed() const
   {
     return mLoadInfo.mXHRParamsAllowed;
   }
 
   void
   SetXHRParamsAllowed(bool aAllowed)
--- a/dom/workers/WorkerThread.cpp
+++ b/dom/workers/WorkerThread.cpp
@@ -322,18 +322,19 @@ WorkerThread::Observer::OnDispatchedEven
 
 NS_IMETHODIMP
 WorkerThread::Observer::OnProcessNextEvent(nsIThreadInternal* /* aThread */,
                                            bool aMayWait)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   // If the PBackground child is not created yet, then we must permit
-  // blocking event processing to support SynchronouslyCreatePBackground().
-  // If this occurs then we are spinning on the event queue at the start of
+  // blocking event processing to support
+  // BackgroundChild::SynchronouslyCreateForCurrentThread(). If this occurs
+  // then we are spinning on the event queue at the start of
   // PrimaryWorkerRunnable::Run() and don't want to process the event in
   // mWorkerPrivate yet.
   if (aMayWait) {
     MOZ_ASSERT(CycleCollectedJSRuntime::Get()->RecursionDepth() == 2);
     MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
     return NS_OK;
   }
 
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/csp_worker.js^headers^
@@ -0,0 +1,1 @@
+Content-Security-Policy: default-src 'self' blob: ; script-src 'unsafe-eval'
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -13,16 +13,17 @@ support-files =
   clearTimeouts_worker.js
   closeOnGC_server.sjs
   closeOnGC_worker.js
   close_worker.js
   content_worker.js
   console_worker.js
   consoleReplaceable_worker.js
   csp_worker.js
+  csp_worker.js^headers^
   404_server.sjs
   errorPropagation_iframe.html
   errorPropagation_worker.js
   errorwarning_worker.js
   eventDispatch_worker.js
   fibonacci_worker.js
   file_bug1010784_worker.js
   foreign.js
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -2723,17 +2723,17 @@ XMLHttpRequestMainThread::Send(nsIVarian
   if (!IsSystemXHR()) {
     nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
     loadInfo->SetCorsPreflightInfo(mCORSUnsafeHeaders,
                                    mState & XML_HTTP_REQUEST_HAD_UPLOAD_LISTENERS_ON_SEND);
   }
 
   mIsMappedArrayBuffer = false;
   if (mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
-      Preferences::GetBool("dom.mapped_arraybuffer.enabled", false)) {
+      Preferences::GetBool("dom.mapped_arraybuffer.enabled", true)) {
     nsCOMPtr<nsIURI> uri;
     nsAutoCString scheme;
 
     rv = mChannel->GetURI(getter_AddRefs(uri));
     if (NS_SUCCEEDED(rv)) {
       uri->GetScheme(scheme);
       if (scheme.LowerCaseEqualsLiteral("app") ||
           scheme.LowerCaseEqualsLiteral("jar")) {
@@ -3752,21 +3752,16 @@ ArrayBufferBuilder::getArrayBuffer(JSCon
   mDataPtr = nullptr;
   return obj;
 }
 
 nsresult
 ArrayBufferBuilder::mapToFileInPackage(const nsCString& aFile,
                                        nsIFile* aJarFile)
 {
-#ifdef XP_WIN
-  // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
-  MOZ_CRASH("Not implemented");
-  return NS_ERROR_NOT_IMPLEMENTED;
-#else
   nsresult rv;
 
   // Open Jar file to get related attributes of target file.
   RefPtr<nsZipArchive> zip = new nsZipArchive();
   rv = zip->OpenArchive(aJarFile);
   if (NS_FAILED(rv)) {
     return rv;
   }
@@ -3788,17 +3783,16 @@ ArrayBufferBuilder::mapToFileInPackage(c
     mMapPtr = JS_CreateMappedArrayBufferContents(PR_FileDesc2NativeHandle(pr_fd),
                                                  offset, size);
     if (mMapPtr) {
       mLength = size;
       return NS_OK;
     }
   }
   return NS_ERROR_FAILURE;
-#endif
 }
 
 /* static */ bool
 ArrayBufferBuilder::areOverlappingRegions(const uint8_t* aStart1,
                                           uint32_t aLength1,
                                           const uint8_t* aStart2,
                                           uint32_t aLength2)
 {
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1460,16 +1460,18 @@ ContainerLayer::DefaultComputeEffectiveT
             useIntermediateSurface = true;
             break;
           }
         }
       }
     }
   }
 
+  NS_ASSERTION(!Extend3DContext() || !useIntermediateSurface, "Can't have an intermediate surface with preserve-3d!");
+
   if (useIntermediateSurface) {
     mEffectiveTransform = SnapTransformTranslation(idealTransform, &residual);
   } else {
     mEffectiveTransform = idealTransform;
   }
 
   // For layers extending 3d context, its ideal transform should be
   // applied on children.
--- a/image/ClippedImage.cpp
+++ b/image/ClippedImage.cpp
@@ -1,13 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; 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 "ClippedImage.h"
+
 #include <new>      // Workaround for bug in VS10; see bug 981264.
 #include <cmath>
 #include <utility>
 
 #include "gfxDrawable.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
@@ -15,18 +17,16 @@
 #include "mozilla/RefPtr.h"
 #include "mozilla/Pair.h"
 #include "mozilla/Tuple.h"
 
 #include "ImageRegion.h"
 #include "Orientation.h"
 #include "SVGImageContext.h"
 
-#include "ClippedImage.h"
-
 namespace mozilla {
 
 using namespace gfx;
 using layers::LayerManager;
 using layers::ImageContainer;
 using std::make_pair;
 using std::modf;
 using std::pair;
--- a/image/DecoderFactory.cpp
+++ b/image/DecoderFactory.cpp
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DecoderFactory.h"
 
 #include "nsMimeTypes.h"
 #include "mozilla/RefPtr.h"
-#include "nsString.h"
 
 #include "Decoder.h"
 #include "IDecodingTask.h"
 #include "nsPNGDecoder.h"
 #include "nsGIFDecoder2.h"
 #include "nsJPEGDecoder.h"
 #include "nsBMPDecoder.h"
 #include "nsICODecoder.h"
--- a/image/DecoderFactory.h
+++ b/image/DecoderFactory.h
@@ -10,18 +10,16 @@
 #include "DecoderFlags.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/NotNull.h"
 #include "mozilla/gfx/2D.h"
 #include "nsCOMPtr.h"
 #include "SurfaceFlags.h"
 
-class nsACString;
-
 namespace mozilla {
 namespace image {
 
 class Decoder;
 class IDecodingTask;
 class RasterImage;
 class SourceBuffer;
 
--- a/image/Downscaler.cpp
+++ b/image/Downscaler.cpp
@@ -5,25 +5,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Downscaler.h"
 
 #include <algorithm>
 #include <ctime>
 #include "gfxPrefs.h"
 #include "image_operations.h"
+#include "mozilla/gfx/2D.h"
 #include "mozilla/SSE.h"
 #include "mozilla/mips.h"
 #include "convolver.h"
 #include "skia/include/core/SkTypes.h"
 
 using std::max;
 using std::swap;
 
 namespace mozilla {
+
+using gfx::IntRect;
+
 namespace image {
 
 Downscaler::Downscaler(const nsIntSize& aTargetSize)
   : mTargetSize(aTargetSize)
   , mOutputBuffer(nullptr)
   , mXFilter(MakeUnique<skia::ConvolutionFilter1D>())
   , mYFilter(MakeUnique<skia::ConvolutionFilter1D>())
   , mWindowCapacity(0)
--- a/image/Downscaler.h
+++ b/image/Downscaler.h
@@ -9,16 +9,17 @@
  * scaling implementation.
  */
 
 #ifndef mozilla_image_Downscaler_h
 #define mozilla_image_Downscaler_h
 
 #include "mozilla/Maybe.h"
 #include "mozilla/UniquePtr.h"
+#include "gfxPoint.h"
 #include "nsRect.h"
 
 namespace skia {
   class ConvolutionFilter1D;
 } // namespace skia
 
 namespace mozilla {
 namespace image {
--- a/image/DownscalingFilter.h
+++ b/image/DownscalingFilter.h
@@ -14,17 +14,16 @@
  */
 
 #ifndef mozilla_image_DownscalingFilter_h
 #define mozilla_image_DownscalingFilter_h
 
 #include <algorithm>
 #include <ctime>
 #include <stdint.h>
-#include <string.h>
 
 #include "mozilla/Maybe.h"
 #include "mozilla/SSE.h"
 #include "mozilla/mips.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/gfx/2D.h"
 #include "gfxPrefs.h"
 
--- a/image/FrozenImage.cpp
+++ b/image/FrozenImage.cpp
@@ -3,16 +3,18 @@
  * 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 "FrozenImage.h"
 
 namespace mozilla {
 
 using namespace gfx;
+using layers::ImageContainer;
+using layers::LayerManager;
 
 namespace image {
 
 NS_IMPL_ISUPPORTS_INHERITED0(FrozenImage, ImageWrapper)
 
 void
 FrozenImage::IncrementAnimationConsumers()
 {
--- a/image/ImageCacheKey.h
+++ b/image/ImageCacheKey.h
@@ -6,16 +6,17 @@
 /**
  * ImageCacheKey is the key type for the image cache (see imgLoader.h).
  */
 
 #ifndef mozilla_image_src_ImageCacheKey_h
 #define mozilla_image_src_ImageCacheKey_h
 
 #include "mozilla/Maybe.h"
+#include "mozilla/RefPtr.h"
 
 class nsIDocument;
 class nsIURI;
 
 namespace mozilla {
 namespace image {
 
 class ImageURL;
--- a/image/ImageFactory.cpp
+++ b/image/ImageFactory.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; 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 "ImageFactory.h"
+
 #include <algorithm>
 
 #include "mozilla/Likely.h"
 
 #include "nsIHttpChannel.h"
 #include "nsIFileChannel.h"
 #include "nsIFile.h"
 #include "nsMimeTypes.h"
@@ -17,17 +19,16 @@
 #include "MultipartImage.h"
 #include "RasterImage.h"
 #include "VectorImage.h"
 #include "Image.h"
 #include "nsMediaFragmentURIParser.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 
-#include "ImageFactory.h"
 #include "gfxPrefs.h"
 
 namespace mozilla {
 namespace image {
 
 /*static*/ void
 ImageFactory::Initialize()
 { }
--- a/image/ImageLogging.h
+++ b/image/ImageLogging.h
@@ -4,17 +4,16 @@
  * 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_image_ImageLogging_h
 #define mozilla_image_ImageLogging_h
 
 #include "mozilla/Logging.h"
 #include "prinrval.h"
-#include "nsString.h"
 
 static mozilla::LazyLogModule gImgLog("imgRequest");
 
 #define GIVE_ME_MS_NOW() PR_IntervalToMilliseconds(PR_IntervalNow())
 
 using mozilla::LogLevel;
 
 class LogScope {
--- a/image/ImageWrapper.cpp
+++ b/image/ImageWrapper.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/RefPtr.h"
 #include "Orientation.h"
 
 #include "mozilla/MemoryReporting.h"
 
 namespace mozilla {
 
 using gfx::DataSourceSurface;
+using gfx::IntSize;
 using gfx::SamplingFilter;
 using gfx::SourceSurface;
 using layers::LayerManager;
 using layers::ImageContainer;
 
 namespace image {
 
 // Inherited methods from Image.
--- a/image/MultipartImage.cpp
+++ b/image/MultipartImage.cpp
@@ -3,16 +3,20 @@
  * 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 "MultipartImage.h"
 
 #include "imgINotificationObserver.h"
 
 namespace mozilla {
+
+using gfx::IntSize;
+using gfx::SourceSurface;
+
 namespace image {
 
 ///////////////////////////////////////////////////////////////////////////////
 // Helpers
 ///////////////////////////////////////////////////////////////////////////////
 
 class NextPartObserver : public IProgressObserver
 {
--- a/image/OrientedImage.cpp
+++ b/image/OrientedImage.cpp
@@ -1,24 +1,24 @@
 /* -*- Mode: C++; tab-width: 2; 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 "OrientedImage.h"
+
 #include <algorithm>
 
 #include "gfx2DGlue.h"
 #include "gfxDrawable.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "ImageRegion.h"
 #include "SVGImageContext.h"
 
-#include "OrientedImage.h"
-
 using std::swap;
 
 namespace mozilla {
 
 using namespace gfx;
 using layers::LayerManager;
 using layers::ImageContainer;
 
--- a/image/SurfacePipe.h
+++ b/image/SurfacePipe.h
@@ -19,16 +19,18 @@
  * underlying surface.
  */
 
 #ifndef mozilla_image_SurfacePipe_h
 #define mozilla_image_SurfacePipe_h
 
 #include <stdint.h>
 
+#include "nsDebug.h"
+
 #include "mozilla/Likely.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Move.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/Variant.h"
 #include "mozilla/gfx/2D.h"
 
--- a/image/decoders/icon/gtk/nsIconChannel.cpp
+++ b/image/decoders/icon/gtk/nsIconChannel.cpp
@@ -1,43 +1,41 @@
 /* vim:set ts=2 sw=2 sts=2 cin et: */
 /* 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 "nsIconChannel.h"
+
 #include <stdlib.h>
 #include <unistd.h>
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EndianUtils.h"
 #include <algorithm>
 
 #ifdef MOZ_ENABLE_GIO
 #include <gio/gio.h>
 #endif
 
 #include <gtk/gtk.h>
 
 #include "nsMimeTypes.h"
 #include "nsIMIMEService.h"
 
-#include "nsIStringBundle.h"
-#include "nsIStringStream.h"
 #include "nsServiceManagerUtils.h"
 
 #include "nsNetUtil.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIStringStream.h"
 #include "nsServiceManagerUtils.h"
 #include "nsNullPrincipal.h"
 #include "nsIURL.h"
 #include "prlink.h"
 
-#include "nsIconChannel.h"
-
 NS_IMPL_ISUPPORTS(nsIconChannel,
                   nsIRequest,
                   nsIChannel)
 
 static nsresult
 moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI* aURI,
                           nsIChannel** aChannel)
 {
--- a/image/decoders/icon/nsIconProtocolHandler.cpp
+++ b/image/decoders/icon/nsIconProtocolHandler.cpp
@@ -1,17 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  *
  * 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 "nsIconProtocolHandler.h"
+
 #include "nsIconChannel.h"
 #include "nsIconURI.h"
-#include "nsIconProtocolHandler.h"
 #include "nsIURL.h"
 #include "nsCRT.h"
 #include "nsCOMPtr.h"
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsNetCID.h"
 
 ///////////////////////////////////////////////////////////////////////////////
--- a/image/decoders/icon/nsIconURI.cpp
+++ b/image/decoders/icon/nsIconURI.cpp
@@ -1,20 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set sw=2 sts=2 ts=2 et 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 "nsIconURI.h"
+
 #include "mozilla/ArrayUtils.h"
-
 #include "mozilla/ipc/URIUtils.h"
 
-#include "nsIconURI.h"
 #include "nsIIOService.h"
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "prprf.h"
 #include "plstr.h"
 #include <stdlib.h>
 
 using namespace mozilla;
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -77,23 +77,24 @@
 //   omitted fields are treated as zero. The first 40 bytes of these fields are
 //   nearly identical to the WinBMPv3 info header; the remaining 24 bytes are
 //   different.
 // - Also adds compression types "Huffman 1D" and "RLE24", which we don't
 //   support.
 // - We treat OS2-BMPv2 files as if they are WinBMPv3 (i.e. ignore the extra 24
 //   bytes in the info header), which in practice is good enough.
 
+#include "ImageLogging.h"
+#include "nsBMPDecoder.h"
+
 #include <stdlib.h>
 
-#include "ImageLogging.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Likely.h"
-#include "nsBMPDecoder.h"
 
 #include "nsIInputStream.h"
 #include "RasterImage.h"
 #include <algorithm>
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -33,21 +33,22 @@ For further information, please contact 
     U. S. A.
 
 CompuServe Incorporated maintains a mailing list with all those individuals and
 organizations who wish to receive copies of this document when it is corrected
 or revised. This service is offered free of charge; please provide us with your
 mailing address.
 */
 
+#include "nsGIFDecoder2.h"
+
 #include <stddef.h>
 
 #include "imgFrame.h"
 #include "mozilla/EndianUtils.h"
-#include "nsGIFDecoder2.h"
 #include "nsIInputStream.h"
 #include "RasterImage.h"
 #include "SurfacePipeFactory.h"
 
 #include "gfxColor.h"
 #include "gfxPlatform.h"
 #include "qcms.h"
 #include <algorithm>
@@ -411,16 +412,17 @@ ConvertColormap(uint32_t* aColormap, uin
 {
   // Apply CMS transformation if enabled and available
   if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
     qcms_transform* transform = gfxPlatform::GetCMSRGBTransform();
     if (transform) {
       qcms_transform_data(transform, aColormap, aColormap, aColors);
     }
   }
+
   // Convert from the GIF's RGB format to the Cairo format.
   // Work from end to begin, because of the in-place expansion
   uint8_t* from = ((uint8_t*)aColormap) + 3 * aColors;
   uint32_t* to = aColormap + aColors;
 
   // Convert color entries to Cairo format
 
   // set up for loops below
@@ -885,17 +887,20 @@ nsGIFDecoder2::ReadImageDescriptor(const
           static_cast<uint32_t*>(moz_xmalloc(mColormapSize));
       }
       mColormap = mGIFStruct.local_colormap;
     }
 
     const size_t size = 3 << depth;
     if (mColormapSize > size) {
       // Clear the part of the colormap which will be unused with this palette.
-      memset(reinterpret_cast<uint8_t*>(mColormap) + size, 0,
+      // If a GIF references an invalid palette entry, ensure the entry is opaque white.
+      // This is needed for Skia as if it isn't, RGBX surfaces will cause blending issues
+      // with Skia.
+      memset(reinterpret_cast<uint8_t*>(mColormap) + size, 0xFF,
              mColormapSize - size);
     }
 
     MOZ_ASSERT(mColorTablePos == 0);
 
     // We read the local color table in unbuffered mode since it can be quite
     // large and it'd be preferable to avoid unnecessary copies.
     return Transition::ToUnbuffered(State::FINISHED_LOCAL_COLOR_TABLE,
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -1,21 +1,22 @@
 /* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=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/. */
 
 /* This is a Cross-Platform ICO Decoder, which should work everywhere, including
  * Big-Endian machines like the PowerPC. */
 
+#include "nsICODecoder.h"
+
 #include <stdlib.h>
 
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Move.h"
-#include "nsICODecoder.h"
 
 #include "RasterImage.h"
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace image {
 
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -8,16 +8,17 @@
 #define mozilla_image_decoders_nsICODecoder_h
 
 #include "StreamingLexer.h"
 #include "Decoder.h"
 #include "imgFrame.h"
 #include "nsBMPDecoder.h"
 #include "nsPNGDecoder.h"
 #include "ICOFileHeaders.h"
+#include "mozilla/gfx/2D.h"
 
 namespace mozilla {
 namespace image {
 
 class RasterImage;
 
 enum class ICOState
 {
@@ -109,18 +110,18 @@ private:
   LexerTransition<ICOState> FinishMask();
   LexerTransition<ICOState> FinishResource();
 
   StreamingLexer<ICOState, 32> mLexer; // The lexer.
   RefPtr<Decoder> mContainedDecoder; // Either a BMP or PNG decoder.
   UniquePtr<uint8_t[]> mMaskBuffer;    // A temporary buffer for the alpha mask.
   char mBIHraw[bmp::InfoHeaderLength::WIN_ICO]; // The bitmap information header.
   IconDirEntry mDirEntry;              // The dir entry for the selected resource.
-  IntSize mBiggestResourceSize;        // Used to select the intrinsic size.
-  IntSize mBiggestResourceHotSpot;     // Used to select the intrinsic size.
+  gfx::IntSize mBiggestResourceSize;   // Used to select the intrinsic size.
+  gfx::IntSize mBiggestResourceHotSpot; // Used to select the intrinsic size.
   uint16_t mBiggestResourceColorDepth; // Used to select the intrinsic size.
   int32_t mBestResourceDelta;          // Used to select the best resource.
   uint16_t mBestResourceColorDepth;    // Used to select the best resource.
   uint16_t mNumIcons; // Stores the number of icons in the ICO file.
   uint16_t mCurrIcon; // Stores the current dir entry index we are processing.
   uint16_t mBPP;      // The BPP of the resource we're decoding.
   uint32_t mMaskRowSize;  // The size in bytes of each row in the BMP alpha mask.
   uint32_t mCurrMaskLine; // The line of the BMP alpha mask we're processing.
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -1,17 +1,18 @@
 /* -*- Mode: C++; tab-width: 2; 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 "ImageLogging.h"
+#include "nsJPEGDecoder.h"
+
 #include "imgFrame.h"
-#include "nsJPEGDecoder.h"
 #include "Orientation.h"
 #include "EXIF.h"
 
 #include "nsIInputStream.h"
 
 #include "nspr.h"
 #include "nsCRT.h"
 #include "gfxColor.h"
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -1,26 +1,26 @@
 /* -*- Mode: C++; tab-width: 2; 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 "ImageLogging.h" // Must appear first
+#include "nsPNGDecoder.h"
 
 #include <algorithm>
 #include <cstdint>
 
 #include "gfxColor.h"
 #include "gfxPlatform.h"
 #include "imgFrame.h"
 #include "nsColor.h"
 #include "nsIInputStream.h"
 #include "nsMemory.h"
-#include "nsPNGDecoder.h"
 #include "nsRect.h"
 #include "nspr.h"
 #include "png.h"
 #include "RasterImage.h"
 #include "SurfacePipeFactory.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Telemetry.h"
 
--- a/image/imgFrame.cpp
+++ b/image/imgFrame.cpp
@@ -7,16 +7,17 @@
 #include "imgFrame.h"
 #include "ImageRegion.h"
 #include "ShutdownTracker.h"
 
 #include "prenv.h"
 
 #include "gfx2DGlue.h"
 #include "gfxPlatform.h"
+#include "gfxPrefs.h"
 #include "gfxUtils.h"
 #include "gfxAlphaRecovery.h"
 
 #include "GeckoProfiler.h"
 #include "MainThreadUtils.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/gfx/Tools.h"
 #include "mozilla/Likely.h"
@@ -49,17 +50,17 @@ static already_AddRefed<DataSourceSurfac
 CreateLockedSurface(VolatileBuffer* vbuf,
                     const IntSize& size,
                     SurfaceFormat format)
 {
   VolatileBufferPtr<unsigned char>* vbufptr =
     new VolatileBufferPtr<unsigned char>(vbuf);
   MOZ_ASSERT(!vbufptr->WasBufferPurged(), "Expected image data!");
 
-  int32_t stride = VolatileSurfaceStride(size, format);
+  const int32_t stride = VolatileSurfaceStride(size, format);
 
   // The VolatileBufferPtr is held by this DataSourceSurface.
   RefPtr<DataSourceSurface> surf =
     Factory::CreateWrappingDataSourceSurface(*vbufptr, stride, size, format,
                                              &VolatileBufferRelease,
                                              static_cast<void*>(vbufptr));
   if (!surf) {
     delete vbufptr;
@@ -77,16 +78,42 @@ AllocateBufferForImage(const IntSize& si
   if (buf->Init(stride * size.height,
                 size_t(1) << gfxAlphaRecovery::GoodAlignmentLog2())) {
     return buf.forget();
   }
 
   return nullptr;
 }
 
+static bool
+ClearSurface(VolatileBuffer* aVBuf, const IntSize& aSize, SurfaceFormat aFormat)
+{
+  VolatileBufferPtr<unsigned char> vbufptr(aVBuf);
+  if (vbufptr.WasBufferPurged()) {
+    NS_WARNING("VolatileBuffer was purged");
+    return false;
+  }
+
+  int32_t stride = VolatileSurfaceStride(aSize, aFormat);
+  if (aFormat == SurfaceFormat::B8G8R8X8) {
+    // Skia doesn't support RGBX surfaces, so ensure the alpha value is set
+    // to opaque white. While it would be nice to only do this for Skia,
+    // imgFrame can run off main thread and past shutdown where
+    // we might not have gfxPlatform, so just memset everytime instead.
+    memset(vbufptr, 0xFF, stride * aSize.height);
+  } else if (aVBuf->OnHeap()) {
+    // We only need to memset it if the buffer was allocated on the heap.
+    // Otherwise, it's allocated via mmap and refers to a zeroed page and will
+    // be COW once it's written to.
+    memset(vbufptr, 0, stride * aSize.height);
+  }
+
+  return true;
+}
+
 // Returns true if an image of aWidth x aHeight is allowed and legal.
 static bool
 AllowedImageSize(int32_t aWidth, int32_t aHeight)
 {
   // reject over-wide or over-tall images
   const int32_t k64KLimit = 0x0000FFFF;
   if (MOZ_UNLIKELY(aWidth > k64KLimit || aHeight > k64KLimit )) {
     NS_WARNING("image too big");
@@ -204,25 +231,27 @@ imgFrame::InitForDecoder(const nsIntSize
   } else {
     MOZ_ASSERT(!mImageSurface, "Called imgFrame::InitForDecoder() twice?");
 
     mVBuf = AllocateBufferForImage(mFrameRect.Size(), mFormat);
     if (!mVBuf) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    if (mVBuf->OnHeap()) {
-      int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
-      VolatileBufferPtr<uint8_t> ptr(mVBuf);
-      memset(ptr, 0, stride * mFrameRect.height);
-    }
+
     mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
 
     if (!mImageSurface) {
-      NS_WARNING("Failed to create VolatileDataSourceSurface");
+      NS_WARNING("Failed to create ImageSurface");
+      mAborted = true;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    if (!ClearSurface(mVBuf, mFrameRect.Size(), mFormat)) {
+      NS_WARNING("Could not clear allocated buffer");
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   return NS_OK;
 }
 
@@ -264,20 +293,30 @@ imgFrame::InitWithDrawable(gfxDrawable* 
     }
 
     int32_t stride = VolatileSurfaceStride(mFrameRect.Size(), mFormat);
     VolatileBufferPtr<uint8_t> ptr(mVBuf);
     if (!ptr) {
       mAborted = true;
       return NS_ERROR_OUT_OF_MEMORY;
     }
-    if (mVBuf->OnHeap()) {
-      memset(ptr, 0, stride * mFrameRect.height);
+
+    mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
+
+    if (!mImageSurface) {
+      NS_WARNING("Failed to create ImageSurface");
+      mAborted = true;
+      return NS_ERROR_OUT_OF_MEMORY;
     }
-    mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
+
+    if (!ClearSurface(mVBuf, mFrameRect.Size(), mFormat)) {
+      NS_WARNING("Could not clear allocated buffer");
+      mAborted = true;
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
 
     target = gfxPlatform::GetPlatform()->
       CreateDrawTargetForData(ptr, mFrameRect.Size(), stride, mFormat);
   } else {
     // We can't use data surfaces for content, so we'll create an offscreen
     // surface instead.  This means if someone later calls RawAccessRef(), we
     // may have to do an expensive readback, but we warned callers about that in
     // the documentation for this method.
@@ -318,16 +357,33 @@ imgFrame::InitWithDrawable(gfxDrawable* 
 #ifdef DEBUG
   MonitorAutoLock lock(mMonitor);
   MOZ_ASSERT(AreAllPixelsWritten());
 #endif
 
   return NS_OK;
 }
 
+bool
+imgFrame::CanOptimizeOpaqueImage()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!ShutdownTracker::ShutdownHasStarted());
+  mMonitor.AssertCurrentThreadOwns();
+
+  // If we're using a surface format with alpha but the image has no alpha,
+  // change the format. This doesn't change the underlying data at all, but
+  // allows DrawTargets to avoid blending when drawing known opaque images.
+  // This optimization is free and safe, so we always do it when we can except
+  // if we have a Skia backend. Skia doesn't support RGBX so ensure we don't
+  // optimize to a RGBX surface.
+  return mHasNoAlpha && mFormat == SurfaceFormat::B8G8R8A8 && mImageSurface &&
+         (gfxPlatform::GetPlatform()->GetDefaultContentBackend() != BackendType::SKIA);
+}
+
 nsresult
 imgFrame::Optimize()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mMonitor.AssertCurrentThreadOwns();
   MOZ_ASSERT(mLockCount == 1,
              "Should only optimize when holding the lock exclusively");
 
@@ -341,16 +397,22 @@ imgFrame::Optimize()
     hasCheckedOptimize = true;
   }
 
   // Don't optimize during shutdown because gfxPlatform may not be available.
   if (ShutdownTracker::ShutdownHasStarted()) {
     return NS_OK;
   }
 
+  // This optimization is basically free, so we perform it even if optimization is disabled.
+  if (CanOptimizeOpaqueImage()) {
+    mFormat = SurfaceFormat::B8G8R8X8;
+    mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
+  }
+
   if (!mOptimizable || gDisableOptimize) {
     return NS_OK;
   }
 
   if (mPalettedImageData || mOptSurface || mSinglePixel) {
     return NS_OK;
   }
 
@@ -832,24 +894,16 @@ imgFrame::UnlockImageData()
   if (mLockCount == 1 && !mPalettedImageData) {
     // We can't safely optimize off-main-thread, so create a runnable to do it.
     if (!NS_IsMainThread()) {
       nsCOMPtr<nsIRunnable> runnable = new UnlockImageDataRunnable(this);
       NS_DispatchToMainThread(runnable);
       return NS_OK;
     }
 
-    // If we're using a surface format with alpha but the image has no alpha,
-    // change the format. This doesn't change the underlying data at all, but
-    // allows DrawTargets to avoid blending when drawing known opaque images.
-    if (mHasNoAlpha && mFormat == SurfaceFormat::B8G8R8A8 && mImageSurface) {
-      mFormat = SurfaceFormat::B8G8R8X8;
-      mImageSurface = CreateLockedSurface(mVBuf, mFrameRect.Size(), mFormat);
-    }
-
     // Convert the data surface to a GPU surface or a single color if possible.
     // This will also release mImageSurface if possible.
     Optimize();
 
     // Allow the OS to release our data surface.
     mVBufPtr = nullptr;
   }
 
--- a/image/imgFrame.h
+++ b/image/imgFrame.h
@@ -248,16 +248,17 @@ public:
                               size_t& aNonHeapSizeOut) const;
 
 private: // methods
 
   ~imgFrame();
 
   nsresult LockImageData();
   nsresult UnlockImageData();
+  bool     CanOptimizeOpaqueImage();
   nsresult Optimize();
 
   void AssertImageDataLocked() const;
 
   bool AreAllPixelsWritten() const;
   nsresult ImageUpdatedInternal(const nsIntRect& aUpdateRect);
   void GetImageDataInternal(uint8_t** aData, uint32_t* length) const;
   uint32_t GetImageBytesPerRow() const;
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -1,24 +1,24 @@
 /* -*- 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 "ImageLogging.h"
+#include "imgLoader.h"
+
 #include "mozilla/Attributes.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/Move.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ChaosMode.h"
 
-#include "ImageLogging.h"
 #include "nsImageModule.h"
-#include "nsPrintfCString.h"
-#include "imgLoader.h"
 #include "imgRequestProxy.h"
 
 #include "nsCOMPtr.h"
 
 #include "nsContentPolicyUtils.h"
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
--- a/ipc/glue/BackgroundChild.h
+++ b/ipc/glue/BackgroundChild.h
@@ -35,17 +35,18 @@ class PBackgroundChild;
 // across threads. Each PBackgroundChild is unique and valid as long as its
 // designated thread lives.
 //
 // Creation of PBackground is asynchronous. GetForCurrentThread() will return
 // null until the sequence is complete. GetOrCreateForCurrentThread() will start
 // the creation sequence and will call back via the
 // nsIIPCBackgroundChildCreateCallback interface when completed. Thereafter
 // (assuming success) GetForCurrentThread() will return the same actor every
-// time.
+// time. SynchronouslyCreateForCurrentThread() will spin the event loop until
+// the BackgroundChild until the creation sequence is complete.
 //
 // CloseForCurrentThread() will close the current PBackground actor.  Subsequent
 // calls to GetForCurrentThread will return null.  CloseForCurrentThread() may
 // only be called exactly once for each thread-specific actor.  Currently it is
 // illegal to call this before the PBackground actor has been created.
 //
 // The PBackgroundChild actor and all its sub-protocol actors will be
 // automatically destroyed when its designated thread completes.
@@ -61,16 +62,20 @@ public:
   // See above.
   static PBackgroundChild*
   GetForCurrentThread();
 
   // See above.
   static bool
   GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
 
+  // See above.
+  static PBackgroundChild*
+  SynchronouslyCreateForCurrentThread();
+
   static mozilla::dom::PBlobChild*
   GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor,
                           nsIDOMBlob* aBlob);
 
   static mozilla::dom::PBlobChild*
   GetOrCreateActorForBlobImpl(PBackgroundChild* aBackgroundActor,
                               mozilla::dom::BlobImpl* aBlobImpl);
 
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -19,18 +19,20 @@
 #include "mozilla/dom/PFileSystemRequestChild.h"
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
 #include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/quota/PQuotaChild.h"
+#ifdef MOZ_GAMEPAD
 #include "mozilla/dom/GamepadEventChannelChild.h"
 #include "mozilla/dom/GamepadTestChannelChild.h"
+#endif
 #include "mozilla/dom/MessagePortChild.h"
 #include "mozilla/dom/NuwaChild.h"
 #include "mozilla/ipc/PBackgroundTestChild.h"
 #include "mozilla/ipc/PSendStreamChild.h"
 #include "mozilla/layout/VsyncChild.h"
 #include "mozilla/net/PUDPSocketChild.h"
 #include "mozilla/dom/network/UDPSocketChild.h"
 #include "nsID.h"
@@ -491,33 +493,39 @@ BackgroundChildImpl::AllocPGamepadEventC
 {
   MOZ_CRASH("PGamepadEventChannelChild actor should be manually constructed!");
   return nullptr;
 }
 
 bool
 BackgroundChildImpl::DeallocPGamepadEventChannelChild(PGamepadEventChannelChild* aActor)
 {
+#ifdef MOZ_GAMEPAD
   MOZ_ASSERT(aActor);
   delete static_cast<dom::GamepadEventChannelChild*>(aActor);
+#endif
   return true;
 }
 
 dom::PGamepadTestChannelChild*
 BackgroundChildImpl::AllocPGamepadTestChannelChild()
 {
+#ifdef MOZ_GAMEPAD
   MOZ_CRASH("PGamepadTestChannelChild actor should be manually constructed!");
+#endif
   return nullptr;
 }
 
 bool
 BackgroundChildImpl::DeallocPGamepadTestChannelChild(PGamepadTestChannelChild* aActor)
 {
+#ifdef MOZ_GAMEPAD
   MOZ_ASSERT(aActor);
   delete static_cast<dom::GamepadTestChannelChild*>(aActor);
+#endif
   return true;
 }
 
 } // namespace ipc
 } // namespace mozilla
 
 bool
 TestChild::Recv__delete__(const nsCString& aTestArg)
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -406,16 +406,20 @@ private:
   static PBackgroundChild*
   GetForCurrentThread();
 
   // Forwarded from BackgroundChild.
   static bool
   GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
 
   // Forwarded from BackgroundChild.
+  static PBackgroundChild*
+  SynchronouslyCreateForCurrentThread();
+
+  // Forwarded from BackgroundChild.
   static void
   CloseForCurrentThread();
 
   // Forwarded from BackgroundChildImpl.
   static BackgroundChildImpl::ThreadLocal*
   GetThreadLocalForCurrentThread();
 
   static void
@@ -883,16 +887,23 @@ BackgroundChild::GetForCurrentThread()
 bool
 BackgroundChild::GetOrCreateForCurrentThread(
                                  nsIIPCBackgroundChildCreateCallback* aCallback)
 {
   return ChildImpl::GetOrCreateForCurrentThread(aCallback);
 }
 
 // static
+PBackgroundChild*
+BackgroundChild::SynchronouslyCreateForCurrentThread()
+{
+  return ChildImpl::SynchronouslyCreateForCurrentThread();
+}
+
+// static
 PBlobChild*
 BackgroundChild::GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor,
                                          nsIDOMBlob* aBlob)
 {
   MOZ_ASSERT(aBlob);
 
   RefPtr<BlobImpl> blobImpl = static_cast<Blob*>(aBlob)->Impl();
   MOZ_ASSERT(blobImpl);
@@ -1700,16 +1711,77 @@ ChildImpl::GetOrCreateForCurrentThread(
   if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
     CRASH_IN_CHILD_PROCESS("Failed to dispatch to main thread!");
     return false;
   }
 
   return true;
 }
 
+namespace {
+
+class Callback final : public nsIIPCBackgroundChildCreateCallback
+{
+  bool* mDone;
+
+public:
+  explicit Callback(bool* aDone)
+    : mDone(aDone)
+  {
+    MOZ_ASSERT(mDone);
+  }
+
+  NS_DECL_ISUPPORTS
+
+private:
+  ~Callback()
+  { }
+
+  virtual void
+  ActorCreated(PBackgroundChild* aActor) override
+  {
+    *mDone = true;
+  }
+
+  virtual void
+  ActorFailed() override
+  {
+    *mDone = true;
+  }
+};
+
+NS_IMPL_ISUPPORTS(Callback, nsIIPCBackgroundChildCreateCallback)
+
+} // anonymous namespace
+
+/* static */
+PBackgroundChild*
+ChildImpl::SynchronouslyCreateForCurrentThread()
+{
+  MOZ_ASSERT(!GetForCurrentThread());
+
+  bool done = false;
+  nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback = new Callback(&done);
+
+  if (NS_WARN_IF(!GetOrCreateForCurrentThread(callback))) {
+    return nullptr;
+  }
+
+  nsIThread* currentThread = NS_GetCurrentThread();
+  MOZ_ASSERT(currentThread);
+
+  while (!done) {
+    if (NS_WARN_IF(!NS_ProcessNextEvent(currentThread, true /* aMayWait */))) {
+      return nullptr;
+    }
+  }
+
+  return GetForCurrentThread();
+}
+
 // static
 void
 ChildImpl::CloseForCurrentThread()
 {
   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
              "BackgroundChild::Startup() was never called!");
   auto threadLocalInfo =
     static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -13,18 +13,20 @@
 #endif
 #include "mozilla/media/MediaParent.h"
 #include "mozilla/AppProcessChecker.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/dom/FileSystemBase.h"
 #include "mozilla/dom/FileSystemRequestParent.h"
+#ifdef MOZ_GAMEPAD
 #include "mozilla/dom/GamepadEventChannelParent.h"
 #include "mozilla/dom/GamepadTestChannelParent.h"
+#endif
 #include "mozilla/dom/NuwaParent.h"
 #include "mozilla/dom/PBlobParent.h"
 #include "mozilla/dom/PGamepadEventChannelParent.h"
 #include "mozilla/dom/PGamepadTestChannelParent.h"
 #include "mozilla/dom/MessagePortParent.h"
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/ActorUtils.h"
@@ -919,46 +921,58 @@ BackgroundParentImpl::DeallocPFileSystem
     dont_AddRef(static_cast<FileSystemRequestParent*>(aDoomed));
   return true;
 }
 
 // Gamepad API Background IPC
 dom::PGamepadEventChannelParent*
 BackgroundParentImpl::AllocPGamepadEventChannelParent()
 {
+#ifdef MOZ_GAMEPAD
   RefPtr<dom::GamepadEventChannelParent> parent =
     new dom::GamepadEventChannelParent();
 
   return parent.forget().take();
+#else
+  return nullptr;
+#endif
 }
 
 bool
 BackgroundParentImpl::DeallocPGamepadEventChannelParent(dom::PGamepadEventChannelParent *aActor)
 {
+#ifdef MOZ_GAMEPAD
   MOZ_ASSERT(aActor);
   RefPtr<dom::GamepadEventChannelParent> parent =
     dont_AddRef(static_cast<dom::GamepadEventChannelParent*>(aActor));
+#endif
   return true;
 }
 
 dom::PGamepadTestChannelParent*
 BackgroundParentImpl::AllocPGamepadTestChannelParent()
 {
+#ifdef MOZ_GAMEPAD
   RefPtr<dom::GamepadTestChannelParent> parent =
     new dom::GamepadTestChannelParent();
 
   return parent.forget().take();
+#else
+  return nullptr;
+#endif
 }
 
 bool
 BackgroundParentImpl::DeallocPGamepadTestChannelParent(dom::PGamepadTestChannelParent *aActor)
 {
+#ifdef MOZ_GAMEPAD
   MOZ_ASSERT(aActor);
   RefPtr<dom::GamepadTestChannelParent> parent =
     dont_AddRef(static_cast<dom::GamepadTestChannelParent*>(aActor));
+#endif
   return true;
 }
 
 } // namespace ipc
 } // namespace mozilla
 
 void
 TestParent::ActorDestroy(ActorDestroyReason aWhy)
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -80,17 +80,17 @@ ModuleGenerator::~ModuleGenerator()
 
                 uint32_t numFailed = HelperThreadState().harvestFailedWasmJobs();
                 MOZ_ASSERT(outstanding_ >= numFailed);
                 outstanding_ -= numFailed;
 
                 if (!outstanding_)
                     break;
 
-                HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
+                HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
             }
         }
 
         MOZ_ASSERT(HelperThreadState().wasmCompilationInProgress);
         HelperThreadState().wasmCompilationInProgress = false;
     } else {
         MOZ_ASSERT(!outstanding_);
     }
@@ -177,17 +177,17 @@ ModuleGenerator::finishOutstandingTask()
                 return false;
 
             if (!HelperThreadState().wasmFinishedList().empty()) {
                 outstanding_--;
                 task = HelperThreadState().wasmFinishedList().popCopy();
                 break;
             }
 
-            HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
+            HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
         }
     }
 
     return finishTask(task);
 }
 
 static const uint32_t BadCodeRange = UINT32_MAX;
 
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -50,19 +50,19 @@ struct LinkData : LinkDataCacheablePod
     LinkDataCacheablePod& pod() { return *this; }
     const LinkDataCacheablePod& pod() const { return *this; }
 
     struct InternalLink {
         enum Kind {
             RawPointer,
             CodeLabel,
             InstructionImmediate
-        };
-        uint32_t patchAtOffset;
-        uint32_t targetOffset;
+        };	
+        MOZ_INIT_OUTSIDE_CTOR uint32_t patchAtOffset;
+        MOZ_INIT_OUTSIDE_CTOR uint32_t targetOffset;
 
         InternalLink() = default;
         explicit InternalLink(Kind kind);
         bool isRawPointerPatch();
     };
     typedef Vector<InternalLink, 0, SystemAllocPolicy> InternalLinkVector;
 
     struct SymbolicLinkArray : EnumeratedArray<SymbolicAddress, SymbolicAddress::Limit, Uint32Vector> {
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -619,46 +619,37 @@ wasm::GenerateJitExit(MacroAssembler& ma
         Register reg2 = AsmJSIonExitRegE2;
         Register reg3 = AsmJSIonExitRegE3;
 
         // The following is inlined:
         //   JSContext* cx = activation->cx();
         //   Activation* act = cx->runtime()->activation();
         //   act.active_ = true;
         //   act.prevJitTop_ = cx->runtime()->jitTop;
-        //   act.prevJitJSContext_ = cx->runtime()->jitJSContext;
-        //   cx->runtime()->jitJSContext = cx;
         //   act.prevJitActivation_ = cx->runtime()->jitActivation;
         //   cx->runtime()->jitActivation = act;
         //   act.prevProfilingActivation_ = cx->runtime()->profilingActivation;
         //   cx->runtime()->profilingActivation_ = act;
         // On the ARM store8() uses the secondScratchReg (lr) as a temp.
         size_t offsetOfActivation = JSRuntime::offsetOfActivation();
         size_t offsetOfJitTop = offsetof(JSRuntime, jitTop);
-        size_t offsetOfJitJSContext = offsetof(JSRuntime, jitJSContext);
         size_t offsetOfJitActivation = offsetof(JSRuntime, jitActivation);
         size_t offsetOfProfilingActivation = JSRuntime::offsetOfProfilingActivation();
         masm.loadWasmActivation(reg0);
         masm.loadPtr(Address(reg0, WasmActivation::offsetOfContext()), reg3);
         masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
         masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
 
         //   act.active_ = true;
         masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8()));
 
         //   act.prevJitTop_ = cx->runtime()->jitTop;
         masm.loadPtr(Address(reg0, offsetOfJitTop), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop()));
 
-        //   act.prevJitJSContext_ = cx->runtime()->jitJSContext;
-        masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2);
-        masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext()));
-        //   cx->runtime()->jitJSContext = cx;
-        masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext));
-
         //   act.prevJitActivation_ = cx->runtime()->jitActivation;
         masm.loadPtr(Address(reg0, offsetOfJitActivation), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitActivation()));
         //   cx->runtime()->jitActivation = act;
         masm.storePtr(reg1, Address(reg0, offsetOfJitActivation));
 
         //   act.prevProfilingActivation_ = cx->runtime()->profilingActivation;
         masm.loadPtr(Address(reg0, offsetOfProfilingActivation), reg2);
@@ -681,22 +672,20 @@ wasm::GenerateJitExit(MacroAssembler& ma
         Register reg0 = AsmJSIonExitRegD0;
         Register reg1 = AsmJSIonExitRegD1;
         Register reg2 = AsmJSIonExitRegD2;
 
         // The following is inlined:
         //   rt->profilingActivation = prevProfilingActivation_;
         //   rt->activation()->active_ = false;
         //   rt->jitTop = prevJitTop_;
-        //   rt->jitJSContext = prevJitJSContext_;
         //   rt->jitActivation = prevJitActivation_;
         // On the ARM store8() uses the secondScratchReg (lr) as a temp.
         size_t offsetOfActivation = JSRuntime::offsetOfActivation();
         size_t offsetOfJitTop = offsetof(JSRuntime, jitTop);
-        size_t offsetOfJitJSContext = offsetof(JSRuntime, jitJSContext);
         size_t offsetOfJitActivation = offsetof(JSRuntime, jitActivation);
         size_t offsetOfProfilingActivation = JSRuntime::offsetOfProfilingActivation();
 
         masm.movePtr(SymbolicAddress::Runtime, reg0);
         masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
 
         //   rt->jitTop = prevJitTop_;
         masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitTop()), reg2);
@@ -704,20 +693,16 @@ wasm::GenerateJitExit(MacroAssembler& ma
 
         //   rt->profilingActivation = rt->activation()->prevProfiling_;
         masm.loadPtr(Address(reg1, Activation::offsetOfPrevProfiling()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfProfilingActivation));
 
         //   rt->activation()->active_ = false;
         masm.store8(Imm32(0), Address(reg1, JitActivation::offsetOfActiveUint8()));
 
-        //   rt->jitJSContext = prevJitJSContext_;
-        masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitJSContext()), reg2);
-        masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext));
-
         //   rt->jitActivation = prevJitActivation_;
         masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitActivation()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfJitActivation));
     }
 
     // Reload the global register since JIT code can clobber any register.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
--- a/js/src/gc/Allocator.cpp
+++ b/js/src/gc/Allocator.cpp
@@ -289,17 +289,17 @@ void
 GCRuntime::startBackgroundAllocTaskIfIdle()
 {
     AutoLockHelperThreadState helperLock;
     if (allocTask.isRunning())
         return;
 
     // Join the previous invocation of the task. This will return immediately
     // if the thread has never been started.
-    allocTask.joinWithLockHeld();
+    allocTask.joinWithLockHeld(helperLock);
     allocTask.startWithLockHeld();
 }
 
 /* static */ TenuredCell*
 GCRuntime::refillFreeListFromAnyThread(ExclusiveContext* cx, AllocKind thingKind, size_t thingSize)
 {
     cx->arenas()->checkEmptyFreeList(thingKind);
 
@@ -330,17 +330,17 @@ GCRuntime::refillFreeListOffMainThread(E
 
     AutoMaybeStartBackgroundAllocation maybeStartBGAlloc;
 
     // If we're off the main thread, we try to allocate once and return
     // whatever value we get. We need to first ensure the main thread is not in
     // a GC session.
     AutoLockHelperThreadState lock;
     while (rt->isHeapBusy())
-        HelperThreadState().wait(GlobalHelperThreadState::PRODUCER);
+        HelperThreadState().wait(lock, GlobalHelperThreadState::PRODUCER);
 
     return arenas->allocateFromArena(zone, thingKind, maybeStartBGAlloc);
 }
 
 /* static */ TenuredCell*
 GCRuntime::refillFreeListInGC(Zone* zone, AllocKind thingKind)
 {
     /*
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -18,16 +18,17 @@
 #include "gc/Statistics.h"
 #include "gc/StoreBuffer.h"
 #include "gc/Tracer.h"
 #include "js/GCAnnotations.h"
 
 namespace js {
 
 class AutoLockGC;
+class AutoLockHelperThreadState;
 class VerifyPreTracer;
 
 namespace gc {
 
 typedef Vector<JS::Zone*, 4, SystemAllocPolicy> ZoneVector;
 
 class AutoMaybeStartBackgroundAllocation;
 class MarkingValidator;
@@ -1193,18 +1194,18 @@ class GCRuntime
     unsigned finalizePhase;
     JS::Zone* sweepZone;
     AllocKind sweepKind;
     bool abortSweepAfterCurrentGroup;
 
     /*
      * Concurrent sweep infrastructure.
      */
-    void startTask(GCParallelTask& task, gcstats::Phase phase);
-    void joinTask(GCParallelTask& task, gcstats::Phase phase);
+    void startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked);
+    void joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked);
 
     /*
      * List head of arenas allocated during the sweep phase.
      */
     Arena* arenasAllocatedDuringSweep;
 
     /*
      * Incremental compacting state.
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -275,16 +275,71 @@ size_t
 GetPageFaultCount()
 {
     PROCESS_MEMORY_COUNTERS pmc;
     if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
         return 0;
     return pmc.PageFaultCount;
 }
 
+// On Windows the minimum size for a mapping is the allocation granularity
+// (64KiB in practice), so mapping very small buffers is potentially wasteful.
+void*
+AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
+{
+    // The allocation granularity must be a whole multiple of the alignment and
+    // the caller must request an aligned offset to satisfy Windows' and the
+    // caller's alignment requirements.
+    if (allocGranularity % alignment != 0 || offset % alignment != 0)
+        return nullptr;
+
+    // Make sure file exists and do sanity check for offset and size.
+    HANDLE hFile = reinterpret_cast<HANDLE>(intptr_t(fd));
+    MOZ_ASSERT(hFile != INVALID_HANDLE_VALUE);
+
+    uint32_t fSizeHgh;
+    uint32_t fSizeLow = GetFileSize(hFile, LPDWORD(&fSizeHgh));
+    if (fSizeLow == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
+        return nullptr;
+
+    uint64_t fSize = (uint64_t(fSizeHgh) << 32) + fSizeLow;
+    if (offset >= size_t(fSize) || length == 0 || length > fSize - offset)
+        return nullptr;
+
+    uint64_t mapSize = length + offset;
+    HANDLE hMap = CreateFileMapping(hFile, nullptr, PAGE_READONLY, mapSize >> 32, mapSize, nullptr);
+    if (!hMap)
+        return nullptr;
+
+    // MapViewOfFile requires the offset to be a whole multiple of the
+    // allocation granularity.
+    size_t alignOffset = offset - (offset % allocGranularity);
+    size_t alignLength = length + (offset % allocGranularity);
+    void* map = MapViewOfFile(hMap, FILE_MAP_COPY, 0, alignOffset, alignLength);
+    CloseHandle(hMap);
+    if (!map)
+        return nullptr;
+
+    return reinterpret_cast<void*>(uintptr_t(map) + (offset - alignOffset));
+}
+
+void
+DeallocateMappedContent(void* p, size_t /*length*/)
+{
+    if (!p)
+        return;
+
+    // Calculate the address originally returned by MapViewOfFile.
+    // This is required because AllocateMappedContent returns a pointer that
+    // might be offset into the view, necessitated by the requirement that the
+    // beginning of a view must be aligned with the allocation granularity.
+    uintptr_t map = uintptr_t(p) - (uintptr_t(p) % allocGranularity);
+    MOZ_ALWAYS_TRUE(UnmapViewOfFile(reinterpret_cast<void*>(map)));
+}
+
 #  else // Various APIs are unavailable.
 
 void*
 MapAlignedPages(size_t size, size_t alignment)
 {
     MOZ_ASSERT(size >= alignment);
     MOZ_ASSERT(size % alignment == 0);
     MOZ_ASSERT(size % pageSize == 0);
@@ -323,32 +378,32 @@ MarkPagesInUse(void* p, size_t size)
 
 size_t
 GetPageFaultCount()
 {
     // GetProcessMemoryInfo is unavailable.
     return 0;
 }
 
-#  endif
-
 void*
 AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
 {
-    // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
+    // Not implemented.
     return nullptr;
 }
 
 // Deallocate mapped memory for object.
 void
 DeallocateMappedContent(void* p, size_t length)
 {
-    // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
+    // Not implemented.
 }
 
+#  endif
+
 #elif defined(SOLARIS)
 
 #ifndef MAP_NOSYNC
 # define MAP_NOSYNC 0
 #endif
 
 void
 InitMemorySubsystem()
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -608,17 +608,17 @@ void
 js::Nursery::freeMallocedBuffers()
 {
     if (mallocedBuffers.empty())
         return;
 
     bool started;
     {
         AutoLockHelperThreadState lock;
-        freeMallocedBuffersTask->joinWithLockHeld();
+        freeMallocedBuffersTask->joinWithLockHeld(lock);
         freeMallocedBuffersTask->transferBuffersToFree(mallocedBuffers);
         started = freeMallocedBuffersTask->startWithLockHeld();
     }
 
     if (!started)
         freeMallocedBuffersTask->runFromMainThread(runtime());
 
     MOZ_ASSERT(mallocedBuffers.empty());
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -333,25 +333,24 @@ Statistics::formatCompactSliceMessage() 
 
     const size_t index = slices.length() - 1;
     const SliceData& slice = slices[index];
 
     char budgetDescription[200];
     slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
 
     const char* format =
-        "GC Slice %u - Pause: %.3fms of %s budget (@ %.3fms); Reason: %s; Reset: %s%s; Cycles: %u "
-        "Times: ";
+        "GC Slice %u - Pause: %.3fms of %s budget (@ %.3fms); Reason: %s; Reset: %s%s; Times: ";
     char buffer[1024];
     memset(buffer, 0, sizeof(buffer));
     JS_snprintf(buffer, sizeof(buffer), format, index,
                 t(slice.duration()), budgetDescription, t(slice.start - slices[0].start),
                 ExplainReason(slice.reason),
-                slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "",
-                slice.cycleCount);
+                slice.resetReason ? "yes - " : "no",
+                slice.resetReason ? slice.resetReason : "");
 
     FragmentVector fragments;
     if (!fragments.append(DuplicateString(buffer)) ||
         !fragments.append(formatCompactSlicePhaseTimes(slices[index].phaseTimes)))
     {
         return UniqueChars(nullptr);
     }
     return Join(fragments);
@@ -519,27 +518,25 @@ Statistics::formatDetailedSliceDescripti
     const char* format =
 "\
   ---- Slice %u ----\n\
     Reason: %s\n\
     Reset: %s%s\n\
     State: %s -> %s\n\
     Page Faults: %ld\n\
     Pause: %.3fms of %s budget (@ %.3fms)\n\
-    Cycles: %u\n\
 ";
     char buffer[1024];
     memset(buffer, 0, sizeof(buffer));
     JS_snprintf(buffer, sizeof(buffer), format, i,
                 ExplainReason(slice.reason),
                 slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "",
                 gc::StateName(slice.initialState), gc::StateName(slice.finalState),
                 uint64_t(slice.endFaults - slice.startFaults),
-                t(slice.duration()), budgetDescription, t(slice.start - slices[0].start),
-                slice.cycleCount);
+                t(slice.duration()), budgetDescription, t(slice.start - slices[0].start));
     return DuplicateString(buffer);
 }
 
 UniqueChars
 Statistics::formatDetailedPhaseTimes(const PhaseTimeTable phaseTimes)
 {
     static const char* LevelToIndent[] = { "", "  ", "    ", "      " };
     static const int64_t MaxUnaccountedChildTimeUS = 50;
@@ -692,32 +689,30 @@ Statistics::formatJsonSliceDescription(u
         "\"pause\":%llu.%03llu,"
         "\"when\":%llu.%03llu,"
         "\"reason\":\"%s\","
         "\"initial_state\":\"%s\","
         "\"final_state\":\"%s\","
         "\"budget\":\"%s\","
         "\"page_faults\":%llu,"
         "\"start_timestamp\":%llu,"
-        "\"end_timestamp\":%llu,"
-        "\"cycle_count\":%u,";
+        "\"end_timestamp\":%llu,";
     char buffer[1024];
     memset(buffer, 0, sizeof(buffer));
     JS_snprintf(buffer, sizeof(buffer), format,
                 i,
                 duration / 1000, duration % 1000,
                 when / 1000, when % 1000,
                 ExplainReason(slice.reason),
                 gc::StateName(slice.initialState),
                 gc::StateName(slice.finalState),
                 budgetDescription,
                 pageFaults,
                 slice.start,
-                slice.end,
-                slice.cycleCount);
+                slice.end);
     return DuplicateString(buffer);
 }
 
 UniqueChars
 FilterJsonKey(const char*const buffer)
 {
     char* mut = strdup(buffer);
     char* c = mut;
@@ -1049,23 +1044,16 @@ Statistics::endSlice()
     /* Do this after the slice callback since it uses these values. */
     if (last)
         PodArrayZero(counts);
 
     gcDepth--;
     MOZ_ASSERT(gcDepth >= 0);
 }
 
-void
-Statistics::setSliceCycleCount(unsigned cycleCount)
-{
-    if (!aborted)
-        slices.back().cycleCount = cycleCount;
-}
-
 bool
 Statistics::startTimingMutator()
 {
     if (phaseNestingDepth != 0) {
         // Should only be called from outside of GC.
         MOZ_ASSERT(phaseNestingDepth == 1);
         MOZ_ASSERT(phaseNesting[0] == PHASE_MUTATOR);
         return false;
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -185,17 +185,16 @@ struct Statistics
     void suspendPhases(Phase suspension = PHASE_EXPLICIT_SUSPENSION);
 
     // Resume a suspended stack of phases.
     void resumePhases();
 
     void beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
                     SliceBudget budget, JS::gcreason::Reason reason);
     void endSlice();
-    void setSliceCycleCount(unsigned cycleCount);
 
     MOZ_MUST_USE bool startTimingMutator();
     MOZ_MUST_USE bool stopTimingMutator(double& mutator_ms, double& gc_ms);
 
     void reset(const char* reason) {
         if (!aborted)
             slices.back().resetReason = reason;
     }
@@ -255,32 +254,30 @@ struct Statistics
     struct SliceData {
         SliceData(SliceBudget budget, JS::gcreason::Reason reason, int64_t start,
                   double startTimestamp, size_t startFaults, gc::State initialState)
           : budget(budget), reason(reason),
             initialState(initialState),
             finalState(gc::NO_INCREMENTAL),
             resetReason(nullptr),
             start(start), startTimestamp(startTimestamp),
-            startFaults(startFaults),
-            cycleCount(0)
+            startFaults(startFaults)
         {
             for (auto i : mozilla::MakeRange(NumTimingArrays))
                 mozilla::PodArrayZero(phaseTimes[i]);
         }
 
         SliceBudget budget;
         JS::gcreason::Reason reason;
         gc::State initialState, finalState;
         const char* resetReason;
         int64_t start, end;
         double startTimestamp, endTimestamp;
         size_t startFaults, endFaults;
         PhaseTimeTable phaseTimes;
-        unsigned cycleCount;
 
         int64_t duration() const { return end - start; }
     };
 
     typedef Vector<SliceData, 8, SystemAllocPolicy> SliceDataVector;
     typedef SliceDataVector::ConstRange SliceRange;
 
     SliceRange sliceRange() const { return slices.all(); }
@@ -385,20 +382,16 @@ struct MOZ_RAII AutoGCSlice
     AutoGCSlice(Statistics& stats, const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
                 SliceBudget budget, JS::gcreason::Reason reason)
       : stats(stats)
     {
         stats.beginSlice(zoneStats, gckind, budget, reason);
     }
     ~AutoGCSlice() { stats.endSlice(); }
 
-    void setCycleCount(unsigned cycleCount) {
-        stats.setSliceCycleCount(cycleCount);
-    }
-
     Statistics& stats;
 };
 
 struct MOZ_RAII AutoPhase
 {
     AutoPhase(Statistics& stats, Phase phase)
       : stats(stats), task(nullptr), phase(phase), enabled(true)
     {
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -24,17 +24,17 @@
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsInRange;
 
 uint32_t
 jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
 {
-    JSContext* cx = GetJSContextFromJitCode();
+    JSContext* cx = GetJSContextFromMainThread();
     MOZ_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
     cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
@@ -100,17 +100,17 @@ jit::Bailout(BailoutStack* sp, BaselineB
 }
 
 uint32_t
 jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
                          BaselineBailoutInfo** bailoutInfo)
 {
     sp->checkInvariants();
 
-    JSContext* cx = GetJSContextFromJitCode();
+    JSContext* cx = GetJSContextFromMainThread();
 
     // We don't have an exit frame.
     cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->runtime());
     BailoutFrameInfo bailoutData(jitActivations, sp);
     JitFrameIterator iter(jitActivations);
     CommonFrameLayout* currentFramePtr = iter.current();
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1739,17 +1739,17 @@ CopyFromRematerializedFrame(JSContext* c
     return true;
 }
 
 uint32_t
 jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
 {
     // The caller pushes R0 and R1 on the stack without rooting them.
     // Since GC here is very unlikely just suppress it.
-    JSContext* cx = GetJSContextFromJitCode();
+    JSContext* cx = GetJSContextFromMainThread();
     js::gc::AutoSuppressGC suppressGC(cx);
 
     JitSpew(JitSpew_BaselineBailouts, "  Done restoring frames");
 
     // The current native code pc may not have a corresponding ICEntry, so we
     // store the bytecode pc in the frame for frame iterators. This pc is
     // cleared at the end of this function. If we return false, we don't clear
     // it: the exception handler also needs it and will clear it for us.
--- a/js/src/jit/BaselineFrame.cpp
+++ b/js/src/jit/BaselineFrame.cpp
@@ -158,17 +158,17 @@ BaselineFrame::initForOsr(InterpreterFra
         numStackValues * sizeof(Value);
 
     MOZ_ASSERT(numValueSlots() == numStackValues);
 
     for (uint32_t i = 0; i < numStackValues; i++)
         *valueSlot(i) = fp->slots()[i];
 
     if (fp->isDebuggee()) {
-        JSContext* cx = GetJSContextFromJitCode();
+        JSContext* cx = GetJSContextFromMainThread();
 
         // For debuggee frames, update any Debugger.Frame objects for the
         // InterpreterFrame to point to the BaselineFrame.
 
         // The caller pushed a fake return address. ScriptFrameIter, used by the
         // debugger, wants a valid return address, but it's okay to just pick one.
         // In debug mode there's always at least 1 ICEntry (since there are always
         // debug prologue/epilogue calls).
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -220,22 +220,23 @@ class CompileInfo
         nimplicit_ = StartArgSlot(script)                   /* scope chain and argument obj */
                    + (fun ? 1 : 0);                         /* this */
         nargs_ = fun ? fun->nargs() : 0;
         nbodyfixed_ = script->nbodyfixed();
         nlocals_ = script->nfixed();
         fixedLexicalBegin_ = script->fixedLexicalBegin();
         nstack_ = Max<unsigned>(script->nslots() - script->nfixed(), MinJITStackSize);
         nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_;
+        needsCallObject_ = fun ? fun->needsCallObject() : false;
     }
 
     explicit CompileInfo(unsigned nlocals)
       : script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr),
-        constructing_(false), analysisMode_(Analysis_None), scriptNeedsArgsObj_(false),
-        mayReadFrameArgsDirectly_(false), inlineScriptTree_(nullptr)
+        constructing_(false), needsCallObject_(false), analysisMode_(Analysis_None),
+        scriptNeedsArgsObj_(false), mayReadFrameArgsDirectly_(false), inlineScriptTree_(nullptr)
     {
         nimplicit_ = 0;
         nargs_ = 0;
         nbodyfixed_ = 0;
         nlocals_ = nlocals;
         nstack_ = 1;  /* For FunctionCompiler::pushPhiInput/popPhiOutput */
         nslots_ = nlocals_ + nstack_;
         fixedLexicalBegin_ = nlocals;
@@ -324,16 +325,20 @@ class CompileInfo
     // maybe argumentsobject and this value.
     unsigned nimplicit() const {
         return nimplicit_;
     }
     // Number of arguments (without counting this value).
     unsigned nargs() const {
         return nargs_;
     }
+    bool needsCallObject() const {
+        MOZ_ASSERT(funMaybeLazy());
+        return needsCallObject_;
+    }
     // Number of slots needed for fixed body-level bindings.  Note that this
     // is only non-zero for function code.
     unsigned nbodyfixed() const {
         return nbodyfixed_;
     }
     // Number of slots needed for all local variables.  This includes "fixed
     // vars" (see above) and also block-scoped locals.
     unsigned nlocals() const {
@@ -494,17 +499,17 @@ class CompileInfo
     bool isObservableFrameSlot(uint32_t slot) const {
         if (!funMaybeLazy())
             return false;
 
         // The |this| value must always be observable.
         if (slot == thisSlot())
             return true;
 
-        if (funMaybeLazy()->needsCallObject() && slot == scopeChainSlot())
+        if (needsCallObject() && slot == scopeChainSlot())
             return true;
 
         // If the function may need an arguments object, then make sure to
         // preserve the scope chain, because it may be needed to construct the
         // arguments object during bailout. If we've already created an
         // arguments object (or got one via OSR), preserve that as well.
         if (hasArguments() && (slot == scopeChainSlot() || slot == argsObjSlot()))
             return true;
@@ -567,16 +572,17 @@ class CompileInfo
     unsigned nstack_;
     unsigned nslots_;
     unsigned fixedLexicalBegin_;
     JSScript* script_;
     JSFunction* fun_;
     jsbytecode* osrPc_;
     NestedStaticScope* osrStaticScope_;
     bool constructing_;
+    bool needsCallObject_;
     AnalysisMode analysisMode_;
 
     // Whether a script needs an arguments object is unstable over compilation
     // since the arguments optimization could be marked as failed on the main
     // thread, so cache a value here and use it throughout for consistency.
     bool scriptNeedsArgsObj_;
 
     // Record the state of previous bailouts in order to prevent compiling the
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -64,22 +64,16 @@ CompileRuntime::addressOfJitStackLimit()
 const void*
 CompileRuntime::addressOfIonBailAfter()
 {
     return runtime()->addressOfIonBailAfter();
 }
 #endif
 
 const void*
-CompileRuntime::addressOfJSContext()
-{
-    return &runtime()->jitJSContext;
-}
-
-const void*
 CompileRuntime::addressOfActivation()
 {
     return runtime()->addressOfActivation();
 }
 
 const void*
 CompileRuntime::addressOfLastCachedNativeIterator()
 {
@@ -95,16 +89,22 @@ CompileRuntime::addressOfGCZealModeBits(
 #endif
 
 const void*
 CompileRuntime::addressOfInterruptUint32()
 {
     return runtime()->addressOfInterruptUint32();
 }
 
+const void*
+CompileRuntime::getJSContext()
+{
+    return runtime()->unsafeContextFromAnyThread();
+}
+
 const JitRuntime*
 CompileRuntime::jitRuntime()
 {
     return runtime()->jitRuntime();
 }
 
 SPSProfiler&
 CompileRuntime::spsProfiler()
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -43,31 +43,32 @@ class CompileRuntime
     // rt->runtime()->jitStackLimit;
     const void* addressOfJitStackLimit();
 
 #ifdef DEBUG
     // rt->runtime()->addressOfIonBailAfter;
     const void* addressOfIonBailAfter();
 #endif
 
-    // &runtime()->jitJSContext
-    const void* addressOfJSContext();
-
     // &runtime()->activation_
     const void* addressOfActivation();
 
     // &GetJitContext()->runtime->nativeIterCache.last
     const void* addressOfLastCachedNativeIterator();
 
 #ifdef JS_GC_ZEAL
     const void* addressOfGCZealModeBits();
 #endif
 
     const void* addressOfInterruptUint32();
 
+    // We have to bake JSContext* into JIT code, but this pointer shouldn't be
+    // used/dereferenced on the background thread so we return it as void*.
+    const void* getJSContext();
+
     const JitRuntime* jitRuntime();
 
     // Compilation does not occur off thread when the SPS profiler is enabled.
     SPSProfiler& spsProfiler();
 
     bool canUseSignalHandlers();
     bool jitSupportsFloatingPoint();
     bool hadOutOfMemory();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6220,19 +6220,19 @@ MInstruction*
 IonBuilder::createCallObject(MDefinition* callee, MDefinition* scope)
 {
     // Get a template CallObject that we'll use to generate inline object
     // creation.
     CallObject* templateObj = inspector->templateCallObject();
 
     // Allocate the object. Run-once scripts need a singleton type, so always do
     // a VM call in such cases.
-    MNullaryInstruction* callObj;
-    if (script()->treatAsRunOnce())
-        callObj = MNewRunOnceCallObject::New(alloc(), templateObj);
+    MNewCallObjectBase* callObj;
+    if (script()->treatAsRunOnce() || templateObj->isSingleton())
+        callObj = MNewSingletonCallObject::New(alloc(), templateObj);
     else
         callObj = MNewCallObject::New(alloc(), templateObj);
     current->add(callObj);
 
     // Initialize the object's reserved slots. No post barrier is needed here,
     // for the same reason as in createDeclEnvObject.
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::enclosingScopeSlot(), scope));
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee));
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -741,17 +741,17 @@ struct AutoResetLastProfilerFrameOnRetur
         MOZ_CRASH("Invalid ResumeFromException type!");
         return nullptr;
     }
 };
 
 void
 HandleException(ResumeFromException* rfe)
 {
-    JSContext* cx = GetJSContextFromJitCode();
+    JSContext* cx = GetJSContextFromMainThread();
     TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime());
 
     AutoResetLastProfilerFrameOnReturnFromException profFrameReset(cx, rfe);
 
     rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
 
     JitSpew(JitSpew_IonInvalidate, "handling exception");
 
@@ -2481,17 +2481,17 @@ MachineState::FromBailout(RegisterDump::
     return machine;
 }
 
 bool
 InlineFrameIterator::isConstructing() const
 {
     // Skip the current frame and look at the caller's.
     if (more()) {
-        InlineFrameIterator parent(GetJSContextFromJitCode(), this);
+        InlineFrameIterator parent(GetJSContextFromMainThread(), this);
         ++parent;
 
         // Inlined Getters and Setters are never constructing.
         if (IsGetPropPC(parent.pc()) || IsSetPropPC(parent.pc()))
             return false;
 
         // In the case of a JS frame, look up the pc from the snapshot.
         MOZ_ASSERT(IsCallPC(parent.pc()));
@@ -2554,17 +2554,17 @@ JitFrameIterator::dumpBaseline() const
 #endif
     } else {
         fprintf(stderr, "  global frame, no callee\n");
     }
 
     fprintf(stderr, "  file %s line %" PRIuSIZE "\n",
             script()->filename(), script()->lineno());
 
-    JSContext* cx = GetJSContextFromJitCode();
+    JSContext* cx = GetJSContextFromMainThread();
     RootedScript script(cx);
     jsbytecode* pc;
     baselineScriptAndPc(script.address(), &pc);
 
     fprintf(stderr, "  script = %p, pc = %p (offset %u)\n", (void*)script, pc, uint32_t(script->pcToOffset(pc)));
     fprintf(stderr, "  current op: %s\n", CodeName[*pc]);
 
     fprintf(stderr, "  actual args: %d\n", numActualArgs());
@@ -2623,17 +2623,17 @@ InlineFrameIterator::dump() const
                 fprintf(stderr, "  scope chain: ");
             else if (i == 1)
                 fprintf(stderr, "  this: ");
             else if (i - 2 < calleeTemplate()->nargs())
                 fprintf(stderr, "  formal (arg %d): ", i - 2);
             else {
                 if (i - 2 == calleeTemplate()->nargs() && numActualArgs() > calleeTemplate()->nargs()) {
                     DumpOp d(calleeTemplate()->nargs());
-                    unaliasedForEachActual(GetJSContextFromJitCode(), d, ReadFrame_Overflown, fallback);
+                    unaliasedForEachActual(GetJSContextFromMainThread(), d, ReadFrame_Overflown, fallback);
                 }
 
                 fprintf(stderr, "  slot %d: ", int(i - 2 - calleeTemplate()->nargs()));
             }
         } else
             fprintf(stderr, "  slot %u: ", i);
 #ifdef DEBUG
         DumpValue(si.maybeRead(fallback));
@@ -2658,17 +2658,17 @@ JitFrameIterator::dump() const
         break;
       case JitFrame_BaselineStub:
         fprintf(stderr, " Baseline stub frame\n");
         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
         break;
       case JitFrame_Bailout:
       case JitFrame_IonJS:
       {
-        InlineFrameIterator frames(GetJSContextFromJitCode(), this);
+        InlineFrameIterator frames(GetJSContextFromMainThread(), this);
         for (;;) {
             frames.dump();
             if (!frames.more())
                 break;
             ++frames;
         }
         break;
       }
@@ -2735,17 +2735,17 @@ JitFrameIterator::verifyReturnAddressUsi
     for (size_t i = 0; i < location.length(); i++) {
         JitSpew(JitSpew_Profiling, "   %s:%" PRIuSIZE " - %" PRIuSIZE,
                 location[i].script->filename(), location[i].script->lineno(),
                 size_t(location[i].pc - location[i].script->code()));
     }
 
     if (type_ == JitFrame_IonJS) {
         // Create an InlineFrameIterator here and verify the mapped info against the iterator info.
-        InlineFrameIterator inlineFrames(GetJSContextFromJitCode(), this);
+        InlineFrameIterator inlineFrames(GetJSContextFromMainThread(), this);
         for (size_t idx = 0; idx < location.length(); idx++) {
             MOZ_ASSERT(idx < location.length());
             MOZ_ASSERT_IF(idx < location.length() - 1, inlineFrames.more());
 
             JitSpew(JitSpew_Profiling,
                     "Match %d: ION %s:%" PRIuSIZE "(%" PRIuSIZE ") vs N2B %s:%" PRIuSIZE "(%" PRIuSIZE ")",
                     (int)idx,
                     inlineFrames.script()->filename(),
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -260,32 +260,23 @@ LIRGenerator::visitNewDeclEnvObject(MNew
     LNewDeclEnvObject* lir = new(alloc()) LNewDeclEnvObject(temp());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitNewCallObject(MNewCallObject* ins)
 {
-    LInstruction* lir;
-    if (ins->templateObject()->isSingleton()) {
-        LNewSingletonCallObject* singletonLir = new(alloc()) LNewSingletonCallObject(temp());
-        define(singletonLir, ins);
-        lir = singletonLir;
-    } else {
-        LNewCallObject* normalLir = new(alloc()) LNewCallObject(temp());
-        define(normalLir, ins);
-        lir = normalLir;
-    }
-
+    LNewCallObject* lir = new(alloc()) LNewCallObject(temp());
+    define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
-LIRGenerator::visitNewRunOnceCallObject(MNewRunOnceCallObject* ins)
+LIRGenerator::visitNewSingletonCallObject(MNewSingletonCallObject* ins)
 {
     LNewSingletonCallObject* lir = new(alloc()) LNewSingletonCallObject(temp());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitNewDerivedTypedObject(MNewDerivedTypedObject* ins)
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -73,17 +73,17 @@ class LIRGenerator : public LIRGenerator
     void visitTableSwitch(MTableSwitch* tableswitch);
     void visitNewArray(MNewArray* ins);
     void visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins);
     void visitNewArrayDynamicLength(MNewArrayDynamicLength* ins);
     void visitNewObject(MNewObject* ins);
     void visitNewTypedObject(MNewTypedObject* ins);
     void visitNewDeclEnvObject(MNewDeclEnvObject* ins);
     void visitNewCallObject(MNewCallObject* ins);
-    void visitNewRunOnceCallObject(MNewRunOnceCallObject* ins);
+    void visitNewSingletonCallObject(MNewSingletonCallObject* ins);
     void visitNewStringObject(MNewStringObject* ins);
     void visitNewDerivedTypedObject(MNewDerivedTypedObject* ins);
     void visitInitElem(MInitElem* ins);
     void visitInitElemGetterSetter(MInitElemGetterSetter* ins);
     void visitMutateProto(MMutateProto* ins);
     void visitInitProp(MInitProp* ins);
     void visitInitPropGetterSetter(MInitPropGetterSetter* ins);
     void visitCheckOverRecursed(MCheckOverRecursed* ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -12266,38 +12266,40 @@ class MNewCallObjectBase : public MNulla
 
 class MNewCallObject : public MNewCallObjectBase
 {
   public:
     INSTRUCTION_HEADER(NewCallObject)
 
     explicit MNewCallObject(CallObject* templateObj)
       : MNewCallObjectBase(templateObj)
-    {}
+    {
+        MOZ_ASSERT(!templateObj->isSingleton());
+    }
 
     static MNewCallObject*
     New(TempAllocator& alloc, CallObject* templateObj)
     {
         return new(alloc) MNewCallObject(templateObj);
     }
 };
 
-class MNewRunOnceCallObject : public MNewCallObjectBase
-{
-  public:
-    INSTRUCTION_HEADER(NewRunOnceCallObject)
-
-    explicit MNewRunOnceCallObject(CallObject* templateObj)
+class MNewSingletonCallObject : public MNewCallObjectBase
+{
+  public:
+    INSTRUCTION_HEADER(NewSingletonCallObject)
+
+    explicit MNewSingletonCallObject(CallObject* templateObj)
       : MNewCallObjectBase(templateObj)
     {}
 
-    static MNewRunOnceCallObject*
+    static MNewSingletonCallObject*
     New(TempAllocator& alloc, CallObject* templateObj)
     {
-        return new(alloc) MNewRunOnceCallObject(templateObj);
+        return new(alloc) MNewSingletonCallObject(templateObj);
     }
 };
 
 class MNewStringObject :
   public MUnaryInstruction,
   public ConvertToStringPolicy<0>::Data
 {
     CompilerObject templateObj_;
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -128,17 +128,17 @@ namespace jit {
     _(ToObjectOrNull)                                                       \
     _(NewArray)                                                             \
     _(NewArrayCopyOnWrite)                                                  \
     _(NewArrayDynamicLength)                                                \
     _(NewObject)                                                            \
     _(NewTypedObject)                                                       \
     _(NewDeclEnvObject)                                                     \
     _(NewCallObject)                                                        \
-    _(NewRunOnceCallObject)                                                 \
+    _(NewSingletonCallObject)                                               \
     _(NewStringObject)                                                      \
     _(ObjectState)                                                          \
     _(ArrayState)                                                           \
     _(InitElem)                                                             \
     _(InitElemGetterSetter)                                                 \
     _(MutateProto)                                                          \
     _(InitProp)                                                             \
     _(InitPropGetterSetter)                                                 \
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1256,17 +1256,17 @@ class MacroAssembler : public MacroAssem
     void loadStringLength(Register str, Register dest) {
         load32(Address(str, JSString::offsetOfLength()), dest);
     }
 
     void loadStringChars(Register str, Register dest);
     void loadStringChar(Register str, Register index, Register output);
 
     void loadJSContext(Register dest) {
-        loadPtr(AbsoluteAddress(GetJitContext()->runtime->addressOfJSContext()), dest);
+        movePtr(ImmPtr(GetJitContext()->runtime->getJSContext()), dest);
     }
     void loadJitActivation(Register dest) {
         loadPtr(AbsoluteAddress(GetJitContext()->runtime->addressOfActivation()), dest);
     }
 
     template<typename T>
     void loadTypedOrValue(const T& src, TypedOrValueRegister dest) {
         if (dest.hasValue())
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -34,16 +34,17 @@
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/SizePrintfMacros.h"
 
 #include "asmjs/WasmSignalHandlers.h"
 #include "jit/arm/Assembler-arm.h"
 #include "jit/arm/disasm/Constants-arm.h"
 #include "jit/AtomicOperations.h"
+#include "threading/LockGuard.h"
 #include "vm/Runtime.h"
 #include "vm/SharedMem.h"
 
 extern "C" {
 
 int64_t
 __aeabi_idivmod(int x, int y)
 {
@@ -353,33 +354,36 @@ class CachePage
   private:
     char data_[kPageSize];   // The cached data.
     static const int kValidityMapSize = kPageSize >> kLineShift;
     char validity_map_[kValidityMapSize];  // One byte per line.
 };
 
 // Protects the icache() and redirection() properties of the
 // Simulator.
-class AutoLockSimulatorCache
+class AutoLockSimulatorCache : public LockGuard<Mutex>
 {
+    using Base = LockGuard<Mutex>;
+
   public:
-    explicit AutoLockSimulatorCache(Simulator* sim) : sim_(sim) {
-        PR_Lock(sim_->cacheLock_);
+    explicit AutoLockSimulatorCache(Simulator* sim)
+      : Base(sim->cacheLock_)
+      , sim_(sim)
+    {
         MOZ_ASSERT(!sim_->cacheLockHolder_);
 #ifdef DEBUG
         sim_->cacheLockHolder_ = PR_GetCurrentThread();
 #endif
     }
 
     ~AutoLockSimulatorCache() {
         MOZ_ASSERT(sim_->cacheLockHolder_);
 #ifdef DEBUG
         sim_->cacheLockHolder_ = nullptr;
 #endif
-        PR_Unlock(sim_->cacheLock_);
     }
 
   private:
     Simulator* const sim_;
 };
 
 bool Simulator::ICacheCheckingEnabled = false;
 
@@ -1119,32 +1123,27 @@ Simulator::Simulator()
 
     // The lr and pc are initialized to a known bad value that will cause an
     // access violation if the simulator ever tries to execute it.
     registers_[pc] = bad_lr;
     registers_[lr] = bad_lr;
 
     lastDebuggerInput_ = nullptr;
 
-    cacheLock_ = nullptr;
 #ifdef DEBUG
     cacheLockHolder_ = nullptr;
 #endif
     redirection_ = nullptr;
     exclusiveMonitorHeld_ = false;
     exclusiveMonitor_ = 0;
 }
 
 bool
 Simulator::init()
 {
-    cacheLock_ = PR_NewLock();
-    if (!cacheLock_)
-        return false;
-
     if (!icache_.init())
         return false;
 
     // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
     static const size_t stackSize = 2 * 1024*1024;
     stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
     if (!stack_)
         return false;
@@ -1221,17 +1220,16 @@ class Redirection
     uint32_t swiInstruction_;
     ABIFunctionType type_;
     Redirection* next_;
 };
 
 Simulator::~Simulator()
 {
     js_free(stack_);
-    PR_DestroyLock(cacheLock_);
     Redirection* r = redirection_;
     while (r) {
         Redirection* next = r->next_;
         js_delete(r);
         r = next;
     }
 }
 
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -31,16 +31,17 @@
 
 #ifdef JS_SIMULATOR_ARM
 
 #include "jslock.h"
 
 #include "jit/arm/Architecture-arm.h"
 #include "jit/arm/disasm/Disasm-arm.h"
 #include "jit/IonTypes.h"
+#include "threading/Mutex.h"
 
 namespace js {
 namespace jit {
 
 class Simulator;
 class Redirection;
 class CachePage;
 class AutoLockSimulator;
@@ -413,17 +414,17 @@ class Simulator
 
   public:
     typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap;
 
   private:
     // This lock creates a critical section around 'redirection_' and
     // 'icache_', which are referenced both by the execution engine
     // and by the off-thread compiler (see Redirection::Get in the cpp file).
-    PRLock* cacheLock_;
+    Mutex cacheLock_;
 #ifdef DEBUG
     PRThread* cacheLockHolder_;
 #endif
 
     Redirection* redirection_;
     ICacheMap icache_;
 
   public:
--- a/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
+++ b/js/src/jit/arm64/vixl/MozSimulator-vixl.cpp
@@ -24,33 +24,33 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "mozilla/DebugOnly.h"
 
 #include "jit/arm64/vixl/Debugger-vixl.h"
 #include "jit/arm64/vixl/Simulator-vixl.h"
 #include "jit/IonTypes.h"
+#include "threading/LockGuard.h"
 #include "vm/Runtime.h"
 
 namespace vixl {
 
 
 using mozilla::DebugOnly;
 using js::jit::ABIFunctionType;
 
 Simulator::Simulator(Decoder* decoder, FILE* stream)
   : stream_(nullptr)
   , print_disasm_(nullptr)
   , instrumentation_(nullptr)
   , stack_(nullptr)
   , stack_limit_(nullptr)
   , decoder_(nullptr)
   , oom_(false)
-  , lock_(nullptr)
 {
     this->init(decoder, stream);
 }
 
 
 Simulator::~Simulator() {
   js_free(stack_);
   stack_ = nullptr;
@@ -139,21 +139,16 @@ void Simulator::init(Decoder* decoder, F
     return;
   }
 
   // Print a warning about exclusive-access instructions, but only the first
   // time they are encountered. This warning can be silenced using
   // SilenceExclusiveAccessWarning().
   print_exclusive_access_warning_ = true;
 
-  lock_ = PR_NewLock();
-  if (!lock_) {
-    oom_ = true;
-    return;
-  }
 #ifdef DEBUG
   lockOwner_ = nullptr;
 #endif
   redirection_ = nullptr;
 }
 
 
 Simulator* Simulator::Current() {
@@ -290,35 +285,37 @@ int64_t Simulator::call(uint8_t* entry, 
   int64_t result = xreg(0);
   if (getenv("USE_DEBUGGER"))
       printf("LEAVE\n");
   return result;
 }
 
 
 // Protects the icache and redirection properties of the simulator.
-class AutoLockSimulatorCache
+class AutoLockSimulatorCache : public js::LockGuard<js::Mutex>
 {
   friend class Simulator;
+  using Base = js::LockGuard<js::Mutex>;
 
  public:
-  explicit AutoLockSimulatorCache(Simulator* sim) : sim_(sim) {
-    PR_Lock(sim_->lock_);
+  explicit AutoLockSimulatorCache(Simulator* sim)
+    : Base(sim->lock_)
+    , sim_(sim)
+  {
     VIXL_ASSERT(!sim_->lockOwner_);
 #ifdef DEBUG
     sim_->lockOwner_ = PR_GetCurrentThread();
 #endif
   }
 
   ~AutoLockSimulatorCache() {
 #ifdef DEBUG
     VIXL_ASSERT(sim_->lockOwner_ == PR_GetCurrentThread());
     sim_->lockOwner_ = nullptr;
 #endif
-    PR_Unlock(sim_->lock_);
   }
 
  private:
    Simulator* const sim_;
 };
 
 
 // When the generated code calls a VM function (masm.callWithABI) we need to
@@ -722,9 +719,8 @@ vixl::Simulator* js::PerThreadData::simu
 vixl::Simulator* JSRuntime::simulator() const {
   return simulator_;
 }
 
 
 uintptr_t* JSRuntime::addressOfSimulatorStackLimit() {
   return simulator_->addressOfStackLimit();
 }
-
--- a/js/src/jit/arm64/vixl/Simulator-vixl.h
+++ b/js/src/jit/arm64/vixl/Simulator-vixl.h
@@ -36,18 +36,18 @@
 #include "jsalloc.h"
 
 #include "jit/arm64/vixl/Assembler-vixl.h"
 #include "jit/arm64/vixl/Disasm-vixl.h"
 #include "jit/arm64/vixl/Globals-vixl.h"
 #include "jit/arm64/vixl/Instructions-vixl.h"
 #include "jit/arm64/vixl/Instrument-vixl.h"
 #include "jit/arm64/vixl/Utils-vixl.h"
-
 #include "jit/IonTypes.h"
+#include "threading/Mutex.h"
 #include "vm/PosixNSPR.h"
 
 #define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror)             \
     JS_BEGIN_MACRO                                                              \
         if (cx->mainThread().simulator()->overRecursedWithExtra(extra)) {       \
             js::ReportOverRecursed(cx);                                         \
             onerror;                                                            \
         }                                                                       \
@@ -2773,17 +2773,17 @@ class Simulator : public DecoderVisitor 
   bool oom_;
 
  public:
   // True if the simulator ran out of memory during or after construction.
   bool oom() const { return oom_; }
 
  protected:
   // Moz: Synchronizes access between main thread and compilation threads.
-  PRLock* lock_;
+  js::Mutex lock_;
 #ifdef DEBUG
   PRThread* lockOwner_;
 #endif
   Redirection* redirection_;
   mozilla::Vector<int64_t, 0, js::SystemAllocPolicy> spStack_;
 };
 }  // namespace vixl
 
--- a/js/src/jit/mips32/Simulator-mips32.cpp
+++ b/js/src/jit/mips32/Simulator-mips32.cpp
@@ -482,33 +482,36 @@ class CachePage {
   private:
     char data_[kPageSize];   // The cached data.
     static const int kValidityMapSize = kPageSize >> kLineShift;
     char validity_map_[kValidityMapSize];  // One byte per line.
 };
 
 // Protects the icache() and redirection() properties of the
 // Simulator.
-class AutoLockSimulatorCache
+class AutoLockSimulatorCache : public LockGuard<Mutex>
 {
+    using Base = LockGuard<Mutex>;
+
   public:
-    explicit AutoLockSimulatorCache(Simulator* sim) : sim_(sim) {
-        PR_Lock(sim_->cacheLock_);
+    explicit AutoLockSimulatorCache(Simulator* sim)
+      : Base(sim->cacheLock_)
+      , sim_(sim)
+    {
         MOZ_ASSERT(!sim_->cacheLockHolder_);
 #ifdef DEBUG
         sim_->cacheLockHolder_ = PR_GetCurrentThread();
 #endif
     }
 
     ~AutoLockSimulatorCache() {
         MOZ_ASSERT(sim_->cacheLockHolder_);
 #ifdef DEBUG
         sim_->cacheLockHolder_ = nullptr;
 #endif
-        PR_Unlock(sim_->cacheLock_);
     }
 
   private:
     Simulator* const sim_;
 };
 
 bool Simulator::ICacheCheckingEnabled = false;
 
@@ -1269,30 +1272,25 @@ Simulator::Simulator()
     registers_[pc] = bad_ra;
     registers_[ra] = bad_ra;
 
     for (int i = 0; i < kNumExceptions; i++)
         exceptions[i] = 0;
 
     lastDebuggerInput_ = nullptr;
 
-    cacheLock_ = nullptr;
 #ifdef DEBUG
     cacheLockHolder_ = nullptr;
 #endif
     redirection_ = nullptr;
 }
 
 bool
 Simulator::init()
 {
-    cacheLock_ = PR_NewLock();
-    if (!cacheLock_)
-        return false;
-
     if (!icache_.init())
         return false;
 
     // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
     static const size_t stackSize = 2 * 1024 * 1024;
     stack_ = static_cast<char*>(js_malloc(stackSize));
     if (!stack_)
         return false;
@@ -1372,17 +1370,16 @@ class Redirection
     uint32_t swiInstruction_;
     ABIFunctionType type_;
     Redirection* next_;
 };
 
 Simulator::~Simulator()
 {
     js_free(stack_);
-    PR_DestroyLock(cacheLock_);
     Redirection* r = redirection_;
     while (r) {
         Redirection* next = r->next_;
         js_delete(r);
         r = next;
     }
 }
 
@@ -3500,9 +3497,8 @@ js::PerThreadData::simulator() const
     return runtime_->simulator();
 }
 
 uintptr_t*
 JSRuntime::addressOfSimulatorStackLimit()
 {
     return simulator_->addressOfStackLimit();
 }
-
--- a/js/src/jit/mips32/Simulator-mips32.h
+++ b/js/src/jit/mips32/Simulator-mips32.h
@@ -29,16 +29,17 @@
 #ifndef jit_mips32_Simulator_mips32_h
 #define jit_mips32_Simulator_mips32_h
 
 #ifdef JS_SIMULATOR_MIPS32
 
 #include "jslock.h"
 
 #include "jit/IonTypes.h"
+#include "threading/Mutex.h"
 
 namespace js {
 namespace jit {
 
 class Simulator;
 class Redirection;
 class CachePage;
 class AutoLockSimulator;
@@ -375,17 +376,17 @@ class Simulator {
 
   public:
     typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap;
 
   private:
     // This lock creates a critical section around 'redirection_' and
     // 'icache_', which are referenced both by the execution engine
     // and by the off-thread compiler (see Redirection::Get in the cpp file).
-    PRLock* cacheLock_;
+    Mutex cacheLock_;
 #ifdef DEBUG
     PRThread* cacheLockHolder_;
 #endif
 
     Redirection* redirection_;
     ICacheMap icache_;
 
   public:
--- a/js/src/jit/mips64/Simulator-mips64.cpp
+++ b/js/src/jit/mips64/Simulator-mips64.cpp
@@ -32,16 +32,17 @@
 #include "mozilla/Casting.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include <float.h>
 
 #include "jit/mips64/Assembler-mips64.h"
+#include "threading/LockGuard.h"
 #include "vm/Runtime.h"
 
 #define I8(v)   static_cast<int8_t>(v)
 #define I16(v)  static_cast<int16_t>(v)
 #define U16(v)  static_cast<uint16_t>(v)
 #define I32(v)  static_cast<int32_t>(v)
 #define U32(v)  static_cast<uint32_t>(v)
 #define I64(v)  static_cast<int64_t>(v)
@@ -519,33 +520,36 @@ class CachePage {
   private:
     char data_[kPageSize];   // The cached data.
     static const int kValidityMapSize = kPageSize >> kLineShift;
     char validity_map_[kValidityMapSize];  // One byte per line.
 };
 
 // Protects the icache() and redirection() properties of the
 // Simulator.
-class AutoLockSimulatorCache
+class AutoLockSimulatorCache : public LockGuard<Mutex>
 {
+    using Base = LockGuard<Mutex>;
+
   public:
-    explicit AutoLockSimulatorCache(Simulator* sim) : sim_(sim) {
-        PR_Lock(sim_->cacheLock_);
+    explicit AutoLockSimulatorCache(Simulator* sim)
+      : Base(sim->cacheLock_)
+      , sim_(sim)
+    {
         MOZ_ASSERT(!sim_->cacheLockHolder_);
 #ifdef DEBUG
         sim_->cacheLockHolder_ = PR_GetCurrentThread();
 #endif
     }
 
     ~AutoLockSimulatorCache() {
         MOZ_ASSERT(sim_->cacheLockHolder_);
 #ifdef DEBUG
         sim_->cacheLockHolder_ = nullptr;
 #endif
-        PR_Unlock(sim_->cacheLock_);
     }
 
   private:
     Simulator* const sim_;
 };
 
 bool Simulator::ICacheCheckingEnabled = false;
 
@@ -1282,30 +1286,25 @@ Simulator::Simulator()
     registers_[pc] = bad_ra;
     registers_[ra] = bad_ra;
 
     for (int i = 0; i < kNumExceptions; i++)
         exceptions[i] = 0;
 
     lastDebuggerInput_ = nullptr;
 
-    cacheLock_ = nullptr;
 #ifdef DEBUG
     cacheLockHolder_ = nullptr;
 #endif
     redirection_ = nullptr;
 }
 
 bool
 Simulator::init()
 {
-    cacheLock_ = PR_NewLock();
-    if (!cacheLock_)
-        return false;
-
     if (!icache_.init())
         return false;
 
     // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
     static const size_t stackSize = 2 * 1024 * 1024;
     stack_ = static_cast<char*>(js_malloc(stackSize));
     if (!stack_)
         return false;
@@ -1385,17 +1384,16 @@ class Redirection
     uint32_t swiInstruction_;
     ABIFunctionType type_;
     Redirection* next_;
 };
 
 Simulator::~Simulator()
 {
     js_free(stack_);
-    PR_DestroyLock(cacheLock_);
     Redirection* r = redirection_;
     while (r) {
         Redirection* next = r->next_;
         js_delete(r);
         r = next;
     }
 }
 
--- a/js/src/jit/mips64/Simulator-mips64.h
+++ b/js/src/jit/mips64/Simulator-mips64.h
@@ -30,16 +30,17 @@
 #ifndef jit_mips64_Simulator_mips64_h
 #define jit_mips64_Simulator_mips64_h
 
 #ifdef JS_SIMULATOR_MIPS64
 
 #include "jslock.h"
 
 #include "jit/IonTypes.h"
+#include "threading/Mutex.h"
 
 namespace js {
 namespace jit {
 
 class Simulator;
 class Redirection;
 class CachePage;
 class AutoLockSimulator;
@@ -391,17 +392,17 @@ class Simulator {
 
   public:
     typedef HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy> ICacheMap;
 
   private:
     // This lock creates a critical section around 'redirection_' and
     // 'icache_', which are referenced both by the execution engine
     // and by the off-thread compiler (see Redirection::Get in the cpp file).
-    PRLock* cacheLock_;
+    Mutex cacheLock_;
 #ifdef DEBUG
     PRThread* cacheLockHolder_;
 #endif
 
     Redirection* redirection_;
     ICacheMap icache_;
 
   public:
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1146,39 +1146,32 @@ class LNewCallObject : public LInstructi
     }
 
 
     MNewCallObject* mir() const {
         return mir_->toNewCallObject();
     }
 };
 
-// Allocates a new CallObject with singleton type.
-//
-// This instruction generates two possible instruction sets:
-//   (1) If the call object is extensible, this is a callVM to create the
-//       call object.
-//   (2) Otherwise, an inline allocation of the call object is attempted.
-//
+// Performs a callVM to allocate a new CallObject with singleton type.
 class LNewSingletonCallObject : public LInstructionHelper<1, 0, 1>
 {
   public:
     LIR_HEADER(NewSingletonCallObject)
 
     explicit LNewSingletonCallObject(const LDefinition& temp) {
         setTemp(0, temp);
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 
-    MNewCallObjectBase* mir() const {
-        MOZ_ASSERT(mir_->isNewCallObject() || mir_->isNewRunOnceCallObject());
-        return static_cast<MNewCallObjectBase*>(mir_);
+    MNewSingletonCallObject* mir() const {
+        return mir_->toNewSingletonCallObject();
     }
 };
 
 class LNewDerivedTypedObject : public LCallInstructionHelper<1, 3, 0>
 {
   public:
     LIR_HEADER(NewDerivedTypedObject);
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -865,17 +865,17 @@ ExclusiveContext::recoverFromOutOfMemory
     }
     // Keep in sync with addPendingOutOfMemory.
     if (ParseTask* task = helperThread()->parseTask())
         task->outOfMemory = false;
 }
 
 JSContext::JSContext(JSRuntime* parentRuntime)
   : ExclusiveContext(this, &this->JSRuntime::mainThread, Context_JS),
-    JSRuntime(this, parentRuntime),
+    JSRuntime(parentRuntime),
     throwing(false),
     unwrappedException_(this),
     overRecursed_(false),
     propagatingForcedReturn_(false),
     liveVolatileJitFrameIterators_(nullptr),
     reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
     resolvingList(nullptr),
     generatingError(false),
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -759,9 +759,22 @@ class MOZ_RAII AutoLockForExclusiveAcces
 };
 
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
+inline JSContext*
+JSRuntime::unsafeContextFromAnyThread()
+{
+    return static_cast<JSContext*>(this);
+}
+
+inline JSContext*
+JSRuntime::contextFromMainThread()
+{
+    MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
+    return unsafeContextFromAnyThread();
+}
+
 #endif /* jscntxt_h */
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2437,28 +2437,28 @@ GCRuntime::updateCellPointers(MovingTrac
 
     {
         AutoLockHelperThreadState lock;
 
         fgTask.emplace(rt, &fgArenas, lock);
 
         for (size_t i = 0; i < bgTaskCount && !bgArenas.done(); i++) {
             bgTasks[i].emplace(rt, &bgArenas, lock);
-            startTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
+            startTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS, lock);
             tasksStarted = i;
         }
     }
 
     fgTask->runFromMainThread(rt);
 
     {
         AutoLockHelperThreadState lock;
 
         for (size_t i = 0; i < tasksStarted; i++)
-            joinTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
+            joinTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS, lock);
     }
 }
 
 // Pointer updates run in three phases because of depdendencies between the
 // different types of GC thing. The most important consideration is the
 // dependency:
 //
 //    object ---> shape ---> base shape
@@ -4797,19 +4797,19 @@ GCRuntime::endMarkingZoneGroup()
         zone->setGCState(Zone::Mark);
     }
     MOZ_ASSERT(marker.isDrained());
     marker.setMarkColorBlack();
 }
 
 class GCSweepTask : public GCParallelTask
 {
-    virtual void runFromHelperThread() override {
+    virtual void runFromHelperThread(AutoLockHelperThreadState& locked) override {
         AutoSetThreadIsSweeping threadIsSweeping;
-        GCParallelTask::runFromHelperThread();
+        GCParallelTask::runFromHelperThread(locked);
     }
     GCSweepTask(const GCSweepTask&) = delete;
 
   protected:
     JSRuntime* runtime;
 
   public:
     explicit GCSweepTask(JSRuntime* rt) : runtime(rt) {}
@@ -4893,31 +4893,31 @@ SweepMiscTask::run()
     for (GCCompartmentGroupIter c(runtime); !c.done(); c.next()) {
         c->sweepSavedStacks();
         c->sweepSelfHostingScriptSource();
         c->sweepNativeIterators();
     }
 }
 
 void
-GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase)
+GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     if (!task.startWithLockHeld()) {
-        AutoUnlockHelperThreadState unlock;
+        AutoUnlockHelperThreadState unlock(locked);
         gcstats::AutoPhase ap(stats, phase);
         task.runFromMainThread(rt);
     }
 }
 
 void
-GCRuntime::joinTask(GCParallelTask& task, gcstats::Phase phase)
+GCRuntime::joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked)
 {
     gcstats::AutoPhase ap(stats, task, phase);
-    task.joinWithLockHeld();
+    task.joinWithLockHeld(locked);
 }
 
 using WeakCacheTaskVector = mozilla::Vector<SweepWeakCacheTask, 0, SystemAllocPolicy>;
 
 static void
 SweepWeakCachesFromMainThread(JSRuntime* rt)
 {
     for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
@@ -5010,32 +5010,32 @@ GCRuntime::beginSweepingZoneGroup(AutoLo
                 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
                     callWeakPointerCompartmentCallbacks(comp);
             }
         }
     }
 
     if (sweepingAtoms) {
         AutoLockHelperThreadState helperLock;
-        startTask(sweepAtomsTask, gcstats::PHASE_SWEEP_ATOMS);
+        startTask(sweepAtomsTask, gcstats::PHASE_SWEEP_ATOMS, helperLock);
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_COMPARTMENTS);
         gcstats::AutoSCC scc(stats, zoneGroupIndex);
 
         {
             AutoLockHelperThreadState helperLock;
-            startTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS);
-            startTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER);
-            startTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT);
-            startTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP);
-            startTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC);
+            startTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS, helperLock);
+            startTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER, helperLock);
+            startTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT, helperLock);
+            startTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP, helperLock);
+            startTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC, helperLock);
             for (auto& task : sweepCacheTasks)
-                startTask(task, gcstats::PHASE_SWEEP_MISC);
+                startTask(task, gcstats::PHASE_SWEEP_MISC, helperLock);
         }
 
         // The remainder of the of the tasks run in parallel on the main
         // thread until we join, below.
         {
             gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_MISC);
 
             for (GCCompartmentGroupIter c(rt); !c.done(); c.next()) {
@@ -5091,31 +5091,31 @@ GCRuntime::beginSweepingZoneGroup(AutoLo
     if (sweepingAtoms) {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_SYMBOL_REGISTRY);
         rt->symbolRegistry(lock).sweep();
     }
 
     // Rejoin our off-main-thread tasks.
     if (sweepingAtoms) {
         AutoLockHelperThreadState helperLock;
-        joinTask(sweepAtomsTask, gcstats::PHASE_SWEEP_ATOMS);
+        joinTask(sweepAtomsTask, gcstats::PHASE_SWEEP_ATOMS, helperLock);
     }
 
     {
         gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_COMPARTMENTS);
         gcstats::AutoSCC scc(stats, zoneGroupIndex);
 
         AutoLockHelperThreadState helperLock;
-        joinTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS);
-        joinTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER);
-        joinTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT);
-        joinTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP);
-        joinTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC);
+        joinTask(sweepInnerViewsTask, gcstats::PHASE_SWEEP_INNER_VIEWS, helperLock);
+        joinTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER, helperLock);
+        joinTask(sweepObjectGroupsTask, gcstats::PHASE_SWEEP_TYPE_OBJECT, helperLock);
+        joinTask(sweepRegExpsTask, gcstats::PHASE_SWEEP_REGEXP, helperLock);
+        joinTask(sweepMiscTask, gcstats::PHASE_SWEEP_MISC, helperLock);
         for (auto& task : sweepCacheTasks)
-            joinTask(task, gcstats::PHASE_SWEEP_MISC);
+            joinTask(task, gcstats::PHASE_SWEEP_MISC, helperLock);
     }
 
     /*
      * Queue all GC things in all zones for sweeping, either in the
      * foreground or on the background thread.
      *
      * Note that order is important here for the background case.
      *
@@ -6109,18 +6109,21 @@ class AutoScheduleZonesForGC
  * use during the marking implementation.
  *
  * Returns true if we "reset" an existing incremental GC, which would force us
  * to run another cycle.
  */
 MOZ_NEVER_INLINE bool
 GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::Reason reason)
 {
+    // Note that the following is allowed to re-enter GC in the finalizer.
     AutoNotifyGCActivity notify(*this);
 
+    gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), invocationKind, budget, reason);
+
     evictNursery(reason);
 
     AutoTraceSession session(rt, JS::HeapState::MajorCollecting);
 
     majorGCTriggerReason = JS::gcreason::NO_REASON;
     interFrameGC = true;
 
     number++;
@@ -6272,22 +6275,19 @@ GCRuntime::collect(bool nonincrementalBy
     // Check if we are allowed to GC at this time before proceeding.
     if (!checkIfGCAllowedInCurrentState(reason))
         return;
 
     AutoTraceLog logGC(TraceLoggerForMainThread(rt), TraceLogger_GC);
     AutoStopVerifyingBarriers av(rt, IsShutdownGC(reason));
     AutoEnqueuePendingParseTasksAfterGC aept(*this);
     AutoScheduleZonesForGC asz(rt);
-    gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), invocationKind, budget, reason);
 
     bool repeat = false;
-    unsigned cycleCount = 0;
     do {
-        cycleCount++;
         poked = false;
         bool wasReset = gcCycle(nonincrementalByAPI, budget, reason);
 
         /* Need to re-schedule all zones for GC. */
         if (poked && cleanUpEverything)
             JS::PrepareForFullGC(rt);
 
         /*
@@ -6311,18 +6311,16 @@ GCRuntime::collect(bool nonincrementalBy
          * If we reset an existing GC, we need to start a new one. Also, we
          * repeat GCs that happen during shutdown (the gcShouldCleanUpEverything
          * case) until we can be sure that no additional garbage is created
          * (which typically happens if roots are dropped during finalizers).
          */
         repeat = (poked && cleanUpEverything) || wasReset || repeatForDeadZone;
     } while (repeat);
 
-    agc.setCycleCount(cycleCount);
-
 #ifdef JS_GC_ZEAL
     if (shouldCompact() && rt->hasZealMode(ZealMode::CheckHeapOnMovingGC)) {
         gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_TRACE_HEAP);
         CheckHeapAfterMovingGC(rt);
     }
 #endif
 }
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -19,16 +19,17 @@
 #include "js/GCAPI.h"
 #include "js/SliceBudget.h"
 #include "js/Vector.h"
 #include "threading/ConditionVariable.h"
 #include "vm/NativeObject.h"
 
 namespace js {
 
+class AutoLockHelperThreadState;
 unsigned GetCPUCount();
 
 enum ThreadType
 {
     MainThread,
     BackgroundThread
 };
 
@@ -951,17 +952,17 @@ class GCParallelTask
 
     // The simple interface to a parallel task works exactly like pthreads.
     bool start();
     void join();
 
     // If multiple tasks are to be started or joined at once, it is more
     // efficient to take the helper thread lock once and use these methods.
     bool startWithLockHeld();
-    void joinWithLockHeld();
+    void joinWithLockHeld(AutoLockHelperThreadState& locked);
 
     // Instead of dispatching to a helper, run the task on the main thread.
     void runFromMainThread(JSRuntime* rt);
 
     // Dispatch a cancelation request.
     enum CancelMode { CancelNoWait, CancelAndWait};
     void cancel(CancelMode mode = CancelNoWait) {
         cancel_ = true;
@@ -970,17 +971,17 @@ class GCParallelTask
     }
 
     // Check if a task is actively running.
     bool isRunning() const;
 
     // This should be friended to HelperThread, but cannot be because it
     // would introduce several circular dependencies.
   public:
-    virtual void runFromHelperThread();
+    virtual void runFromHelperThread(AutoLockHelperThreadState& locked);
 };
 
 typedef void (*IterateChunkCallback)(JSRuntime* rt, void* data, gc::Chunk* chunk);
 typedef void (*IterateZoneCallback)(JSRuntime* rt, void* data, JS::Zone* zone);
 typedef void (*IterateArenaCallback)(JSRuntime* rt, void* data, gc::Arena* arena,
                                      JS::TraceKind traceKind, size_t thingSize);
 typedef void (*IterateCellCallback)(JSRuntime* rt, void* data, void* thing,
                                     JS::TraceKind traceKind, size_t thingSize);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2993,28 +2993,27 @@ WorkerMain(void* arg)
     KillWatchdog(rt);
 
     JS_DestroyRuntime(rt);
 
     js_delete(input);
 }
 
 // Workers can spawn other workers, so we need a lock to access workerThreads.
-static PRLock* workerThreadsLock = nullptr;
+static Mutex* workerThreadsLock = nullptr;
 static Vector<PRThread*, 0, SystemAllocPolicy> workerThreads;
 
-class MOZ_RAII AutoLockWorkerThreads
-{
+class MOZ_RAII AutoLockWorkerThreads : public LockGuard<Mutex>
+{
+    using Base = LockGuard<Mutex>;
   public:
-    AutoLockWorkerThreads() {
+    AutoLockWorkerThreads()
+      : Base(*workerThreadsLock)
+    {
         MOZ_ASSERT(workerThreadsLock);
-        PR_Lock(workerThreadsLock);
-    }
-    ~AutoLockWorkerThreads() {
-        PR_Unlock(workerThreadsLock);
     }
 };
 
 static bool
 EvalInWorker(JSContext* cx, unsigned argc, Value* vp)
 {
     if (!CanUseExtraThreads()) {
         JS_ReportError(cx, "Can't create worker threads with --no-threads");
@@ -3026,17 +3025,17 @@ EvalInWorker(JSContext* cx, unsigned arg
         JS_ReportError(cx, "Invalid arguments to evalInWorker");
         return false;
     }
 
     if (!args[0].toString()->ensureLinear(cx))
         return false;
 
     if (!workerThreadsLock) {
-        workerThreadsLock = PR_NewLock();
+        workerThreadsLock = js_new<Mutex>();
         if (!workerThreadsLock) {
             ReportOutOfMemory(cx);
             return false;
         }
     }
 
     JSLinearString* str = &args[0].toString()->asLinear();
 
@@ -3228,17 +3227,17 @@ KillWorkerThreads()
             AutoLockWorkerThreads alwt;
             if (workerThreads.empty())
                 break;
             thread = workerThreads.popCopy();
         }
         PR_JoinThread(thread);
     }
 
-    PR_DestroyLock(workerThreadsLock);
+    js_delete(workerThreadsLock);
     workerThreadsLock = nullptr;
 }
 
 static void
 CancelExecution(JSRuntime* rt)
 {
     ShellRuntime* sr = GetShellRuntime(rt);
     sr->serviceInterrupt = true;
@@ -4618,56 +4617,56 @@ IsLatin1(JSContext* cx, unsigned argc, V
 //
 // The lock guards the mailbox variable and prevents a race where two
 // workers try to set the mailbox at the same time to replace a SARB
 // that is only referenced from the mailbox: the workers will both
 // decrement the reference count on the old SARB, and one of those
 // decrements will be on a garbage object.  We could implement this
 // with atomics and a CAS loop but it's not worth the bother.
 
-static PRLock* sharedArrayBufferMailboxLock;
+static Mutex* sharedArrayBufferMailboxLock;
 static SharedArrayRawBuffer* sharedArrayBufferMailbox;
 
 static bool
 InitSharedArrayBufferMailbox()
 {
-    sharedArrayBufferMailboxLock = PR_NewLock();
+    sharedArrayBufferMailboxLock = js_new<Mutex>();
     return sharedArrayBufferMailboxLock != nullptr;
 }
 
 static void
 DestructSharedArrayBufferMailbox()
 {
     // All workers need to have terminated at this point.
     if (sharedArrayBufferMailbox)
         sharedArrayBufferMailbox->dropReference();
-    PR_DestroyLock(sharedArrayBufferMailboxLock);
+    js_delete(sharedArrayBufferMailboxLock);
 }
 
 static bool
 GetSharedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JSObject* newObj = nullptr;
     bool rval = true;
 
-    PR_Lock(sharedArrayBufferMailboxLock);
+    sharedArrayBufferMailboxLock->lock();
     SharedArrayRawBuffer* buf = sharedArrayBufferMailbox;
     if (buf) {
         buf->addReference();
         // Shared memory is enabled globally in the shell: there can't be a worker
         // that does not enable it if the main thread has it.
         MOZ_ASSERT(cx->compartment()->creationOptions().getSharedMemoryAndAtomicsEnabled());
         newObj = SharedArrayBufferObject::New(cx, buf);
         if (!newObj) {
             buf->dropReference();
             rval = false;
         }
     }
-    PR_Unlock(sharedArrayBufferMailboxLock);
+    sharedArrayBufferMailboxLock->unlock();
 
     args.rval().setObjectOrNull(newObj);
     return rval;
 }
 
 static bool
 SetSharedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -4680,22 +4679,22 @@ SetSharedArrayBuffer(JSContext* cx, unsi
     else if (args.get(0).isObject() && args[0].toObject().is<SharedArrayBufferObject>()) {
         newBuffer = args[0].toObject().as<SharedArrayBufferObject>().rawBufferObject();
         newBuffer->addReference();
     } else {
         JS_ReportError(cx, "Only a SharedArrayBuffer can be installed in the global mailbox");
         return false;
     }
 
-    PR_Lock(sharedArrayBufferMailboxLock);
+    sharedArrayBufferMailboxLock->lock();
     SharedArrayRawBuffer* oldBuffer = sharedArrayBufferMailbox;
     if (oldBuffer)
         oldBuffer->dropReference();
     sharedArrayBufferMailbox = newBuffer;
-    PR_Unlock(sharedArrayBufferMailboxLock);
+    sharedArrayBufferMailboxLock->unlock();
 
     args.rval().setUndefined();
     return true;
 }
 
 class SprintOptimizationTypeInfoOp : public JS::ForEachTrackedOptimizationTypeInfoOp
 {
     Sprinter* sp;
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/newTargetDefaults.js
@@ -0,0 +1,25 @@
+// Check that new.target works properly in defaults.
+
+function check(expected, actual = new.target) { assertEq(actual, expected); }
+new check(check);
+check(undefined);
+
+let evaldCheck = eval("(" + check.toString() + ")");
+new evaldCheck(evaldCheck);
+evaldCheck(undefined);
+
+function testInFunction() {
+    function checkInFunction(expected, actual = new.target) { assertEq(actual, expected); }
+    new checkInFunction(checkInFunction);
+    checkInFunction(undefined);
+
+    let evaldCheckInFunction = eval("(" + checkInFunction.toString() + ")");
+    new evaldCheckInFunction(evaldCheckInFunction);
+    evaldCheckInFunction(undefined);
+}
+
+testInFunction();
+new testInFunction();
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
--- a/js/src/threading/Thread.h
+++ b/js/src/threading/Thread.h
@@ -145,19 +145,19 @@ private:
   MOZ_MUST_USE bool create(THREAD_RETURN_TYPE (THREAD_CALL_API *aMain)(void*), void* aArg);
 };
 
 namespace ThisThread {
 
 // Return the thread id of the calling thread.
 Thread::Id GetId();
 
-// Set the current thread name. Returns true if successful. Note that setting
-// the thread name may not be available on all platforms; on these platforms
-// setName() will simply do nothing.
+// Set the current thread name. Note that setting the thread name may not be
+// available on all platforms; on these platforms setName() will simply do
+// nothing.
 void SetName(const char* name);
 
 } // namespace ThisThread
 
 namespace detail {
 
 // Platform thread APIs allow passing a single void* argument to the target
 // thread. This class is responsible for safely ferrying the arg pack and
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -158,17 +158,17 @@ js::CancelOffThreadIonCompile(JSCompartm
         while (helper.ionBuilder() &&
                CompiledScriptMatches(compartment, script, helper.ionBuilder()->script()))
         {
             helper.ionBuilder()->cancel();
             if (helper.pause) {
                 helper.pause = false;
                 HelperThreadState().notifyAll(GlobalHelperThreadState::PAUSE);
             }
-            HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
+            HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
         }
     }
 
     /* Cancel code generation for any completed entries. */
     GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList();
     for (size_t i = 0; i < finished.length(); i++) {
         jit::IonBuilder* builder = finished[i];
         if (CompiledScriptMatches(compartment, script, builder->script())) {
@@ -323,28 +323,28 @@ js::CancelOffThreadParses(JSRuntime* rt)
             for (size_t i = 0; i < HelperThreadState().threadCount; i++) {
                 ParseTask* task = HelperThreadState().threads[i].parseTask();
                 if (task && task->runtimeMatches(rt))
                     inProgress = true;
             }
             if (!inProgress)
                 break;
         }
-        HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
+        HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
     }
 
     // Clean up any parse tasks which haven't been finished by the main thread.
     GlobalHelperThreadState::ParseTaskVector& finished = HelperThreadState().parseFinishedList();
     while (true) {
         bool found = false;
         for (size_t i = 0; i < finished.length(); i++) {
             ParseTask* task = finished[i];
             if (task->runtimeMatches(rt)) {
                 found = true;
-                AutoUnlockHelperThreadState unlock;
+                AutoUnlockHelperThreadState unlock(lock);
                 HelperThreadState().finishParseTask(/* maybecx = */ nullptr, rt, task->kind,
                                                     task);
             }
         }
         if (!found)
             break;
     }
 }
@@ -627,42 +627,28 @@ GlobalHelperThreadState::ensureInitializ
     return true;
 }
 
 GlobalHelperThreadState::GlobalHelperThreadState()
  : cpuCount(0),
    threadCount(0),
    threads(nullptr),
    wasmCompilationInProgress(false),
-   numWasmFailedJobs(0),
-   helperLock(nullptr),
-   consumerWakeup(nullptr),
-   producerWakeup(nullptr),
-   pauseWakeup(nullptr)
+   numWasmFailedJobs(0)
 {
     cpuCount = GetCPUCount();
     threadCount = ThreadCountForCPUCount(cpuCount);
 
     MOZ_ASSERT(cpuCount > 0, "GetCPUCount() seems broken");
-
-    helperLock = PR_NewLock();
-    consumerWakeup = PR_NewCondVar(helperLock);
-    producerWakeup = PR_NewCondVar(helperLock);
-    pauseWakeup = PR_NewCondVar(helperLock);
 }
 
 void
 GlobalHelperThreadState::finish()
 {
     finishThreads();
-
-    PR_DestroyCondVar(consumerWakeup);
-    PR_DestroyCondVar(producerWakeup);
-    PR_DestroyCondVar(pauseWakeup);
-    PR_DestroyLock(helperLock);
 }
 
 void
 GlobalHelperThreadState::finishThreads()
 {
     if (!threads)
         return;
 
@@ -673,66 +659,66 @@ GlobalHelperThreadState::finishThreads()
     threads = nullptr;
 }
 
 void
 GlobalHelperThreadState::lock()
 {
     MOZ_ASSERT(!isLocked());
     AssertCurrentThreadCanLock(HelperThreadStateLock);
-    PR_Lock(helperLock);
+    helperLock.lock();
 #ifdef DEBUG
     lockOwner = PR_GetCurrentThread();
 #endif
 }
 
 void
 GlobalHelperThreadState::unlock()
 {
     MOZ_ASSERT(isLocked());
 #ifdef DEBUG
     lockOwner = nullptr;
 #endif
-    PR_Unlock(helperLock);
+    helperLock.unlock();
 }
 
 #ifdef DEBUG
 bool
 GlobalHelperThreadState::isLocked()
 {
     return lockOwner == PR_GetCurrentThread();
 }
 #endif
 
 void
-GlobalHelperThreadState::wait(CondVar which, TimeDuration timeout /* = TimeDuration::Forever() */)
+GlobalHelperThreadState::wait(AutoLockHelperThreadState& locked, CondVar which,
+                              TimeDuration timeout /* = TimeDuration::Forever() */)
 {
     MOZ_ASSERT(isLocked());
 #ifdef DEBUG
     lockOwner = nullptr;
 #endif
-    DebugOnly<PRStatus> status = PR_WaitCondVar(whichWakeup(which), DurationToPRInterval(timeout));
-    MOZ_ASSERT(status == PR_SUCCESS);
+    whichWakeup(which).wait_for(locked, timeout);
 #ifdef DEBUG
     lockOwner = PR_GetCurrentThread();
 #endif
 }
 
 void
 GlobalHelperThreadState::notifyAll(CondVar which)
 {
     MOZ_ASSERT(isLocked());
-    PR_NotifyAllCondVar(whichWakeup(which));
+    whichWakeup(which).notify_all();
 }
 
 void
 GlobalHelperThreadState::notifyOne(CondVar which)
 {
     MOZ_ASSERT(isLocked());
-    PR_NotifyCondVar(whichWakeup(which));
+    whichWakeup(which).notify_one();
 }
 
 bool
 GlobalHelperThreadState::hasActiveThreads()
 {
     MOZ_ASSERT(isLocked());
     if (!threads)
         return false;
@@ -747,17 +733,17 @@ GlobalHelperThreadState::hasActiveThread
 
 void
 GlobalHelperThreadState::waitForAllThreads()
 {
     CancelOffThreadIonCompile(nullptr, nullptr, /* discardLazyLinkList = */ false);
 
     AutoLockHelperThreadState lock;
     while (hasActiveThreads())
-        wait(CONSUMER);
+        wait(lock, CONSUMER);
 }
 
 template <typename T>
 bool
 GlobalHelperThreadState::checkTaskThreadLimit(size_t maxThreads) const
 {
     if (maxThreads >= threadCount)
         return true;
@@ -1044,53 +1030,53 @@ js::GCParallelTask::startWithLockHeld()
 bool
 js::GCParallelTask::start()
 {
     AutoLockHelperThreadState helperLock;
     return startWithLockHeld();
 }
 
 void
-js::GCParallelTask::joinWithLockHeld()
+js::GCParallelTask::joinWithLockHeld(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
 
     if (state == NotStarted)
         return;
 
     while (state != Finished)
-        HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
+        HelperThreadState().wait(locked, GlobalHelperThreadState::CONSUMER);
     state = NotStarted;
     cancel_ = false;
 }
 
 void
 js::GCParallelTask::join()
 {
     AutoLockHelperThreadState helperLock;
-    joinWithLockHeld();
+    joinWithLockHeld(helperLock);
 }
 
 void
 js::GCParallelTask::runFromMainThread(JSRuntime* rt)
 {
     MOZ_ASSERT(state == NotStarted);
     MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(rt));
     uint64_t timeStart = PRMJ_Now();
     run();
     duration_ = PRMJ_Now() - timeStart;
 }
 
 void
-js::GCParallelTask::runFromHelperThread()
+js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
 
     {
-        AutoUnlockHelperThreadState parallelSection;
+        AutoUnlockHelperThreadState parallelSection(locked);
         uint64_t timeStart = PRMJ_Now();
         run();
         duration_ = PRMJ_Now() - timeStart;
     }
 
     state = Finished;
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
 }
@@ -1098,27 +1084,27 @@ js::GCParallelTask::runFromHelperThread(
 bool
 js::GCParallelTask::isRunning() const
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     return state == Dispatched;
 }
 
 void
-HelperThread::handleGCParallelWorkload()
+HelperThread::handleGCParallelWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     MOZ_ASSERT(HelperThreadState().canStartGCParallelTask());
     MOZ_ASSERT(idle());
 
     TraceLoggerThread* logger = TraceLoggerForCurrentThread();
     AutoTraceLog logCompile(logger, TraceLogger_GC);
 
     currentTask.emplace(HelperThreadState().gcParallelWorklist().popCopy());
-    gcParallelTask()->runFromHelperThread();
+    gcParallelTask()->runFromHelperThread(locked);
     currentTask.reset();
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
 }
 
 static void
 LeaveParseTaskZone(JSRuntime* rt, ParseTask* task)
 {
     // Mark the zone as no longer in use by an ExclusiveContext, and available
@@ -1343,28 +1329,28 @@ HelperThread::ThreadMain(void* arg)
     //computations on this thread may use incorrect precision rules during
     //Ion compilation.
     FIX_FPU();
 
     static_cast<HelperThread*>(arg)->threadLoop();
 }
 
 void
-HelperThread::handleWasmWorkload()
+HelperThread::handleWasmWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     MOZ_ASSERT(HelperThreadState().canStartWasmCompile());
     MOZ_ASSERT(idle());
 
     currentTask.emplace(HelperThreadState().wasmWorklist().popCopy());
     bool success = false;
 
     wasm::IonCompileTask* task = wasmTask();
     {
-        AutoUnlockHelperThreadState unlock;
+        AutoUnlockHelperThreadState unlock(locked);
 
         TraceLoggerThread* logger = TraceLoggerForCurrentThread();
         AutoTraceLog logCompile(logger, TraceLogger_WasmCompilation);
 
         PerThreadData::AutoEnterRuntime enter(threadData.ptr(), task->runtime());
         success = wasm::CompileFunction(task);
     }
 
@@ -1377,17 +1363,17 @@ HelperThread::handleWasmWorkload()
         HelperThreadState().noteWasmFailure();
 
     // Notify the main thread in case it's waiting.
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
     currentTask.reset();
 }
 
 void
-HelperThread::handleIonWorkload()
+HelperThread::handleIonWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     MOZ_ASSERT(HelperThreadState().canStartIonCompile());
     MOZ_ASSERT(idle());
 
     // Find the IonBuilder in the worklist with the highest priority, and
     // remove it from the worklist.
     jit::IonBuilder* builder =
@@ -1404,17 +1390,17 @@ HelperThread::handleIonWorkload()
     }
 
     currentTask.emplace(builder);
     builder->setPauseFlag(&pause);
 
     JSRuntime* rt = builder->script()->compartment()->runtimeFromAnyThread();
 
     {
-        AutoUnlockHelperThreadState unlock;
+        AutoUnlockHelperThreadState unlock(locked);
 
         TraceLoggerThread* logger = TraceLoggerForCurrentThread();
         TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, builder->script());
         AutoTraceLog logScript(logger, event);
         AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
 
         PerThreadData::AutoEnterRuntime enter(threadData.ptr(),
                                               builder->script()->runtimeFromAnyThread());
@@ -1480,17 +1466,17 @@ js::PauseCurrentHelperThread()
 {
     TraceLoggerThread* logger = TraceLoggerForCurrentThread();
     AutoTraceLog logPaused(logger, TraceLogger_IonCompilationPaused);
 
     HelperThread* thread = CurrentHelperThread();
 
     AutoLockHelperThreadState lock;
     while (thread->pause)
-        HelperThreadState().wait(GlobalHelperThreadState::PAUSE);
+        HelperThreadState().wait(lock, GlobalHelperThreadState::PAUSE);
 }
 
 void
 ExclusiveContext::setHelperThread(HelperThread* thread)
 {
     helperThread_ = thread;
     perThreadData = thread->threadData.ptr();
 }
@@ -1518,28 +1504,28 @@ void
 ExclusiveContext::addPendingOutOfMemory()
 {
     // Keep in sync with recoverFromOutOfMemory.
     if (helperThread()->parseTask())
         helperThread()->parseTask()->outOfMemory = true;
 }
 
 void
-HelperThread::handleParseWorkload()
+HelperThread::handleParseWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     MOZ_ASSERT(HelperThreadState().canStartParseTask());
     MOZ_ASSERT(idle());
 
     currentTask.emplace(HelperThreadState().parseWorklist().popCopy());
     ParseTask* task = parseTask();
     task->cx->setHelperThread(this);
 
     {
-        AutoUnlockHelperThreadState unlock;
+        AutoUnlockHelperThreadState unlock(locked);
         PerThreadData::AutoEnterRuntime enter(threadData.ptr(),
                                               task->exclusiveContextGlobal->runtimeFromAnyThread());
         task->parse();
     }
 
     // The callback is invoked while we are still off the main thread.
     task->callback(task, task->callbackData);
 
@@ -1553,28 +1539,28 @@ HelperThread::handleParseWorkload()
 
     currentTask.reset();
 
     // Notify the main thread in case it is waiting for the parse/emit to finish.
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
 }
 
 void
-HelperThread::handleCompressionWorkload()
+HelperThread::handleCompressionWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     MOZ_ASSERT(HelperThreadState().canStartCompressionTask());
     MOZ_ASSERT(idle());
 
     currentTask.emplace(HelperThreadState().compressionWorklist().popCopy());
     SourceCompressionTask* task = compressionTask();
     task->helperThread = this;
 
     {
-        AutoUnlockHelperThreadState unlock;
+        AutoUnlockHelperThreadState unlock(locked);
 
         TraceLoggerThread* logger = TraceLoggerForCurrentThread();
         AutoTraceLog logCompile(logger, TraceLogger_CompressSource);
 
         task->result = task->work();
     }
 
     task->helperThread = nullptr;
@@ -1618,17 +1604,17 @@ bool
 SourceCompressionTask::complete()
 {
     if (!active())
         return true;
 
     {
         AutoLockHelperThreadState lock;
         while (HelperThreadState().compressionInProgress(this))
-            HelperThreadState().wait(GlobalHelperThreadState::CONSUMER);
+            HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
     }
 
     if (result == Success) {
         MOZ_ASSERT(resultString);
         ss->setCompressedSource(mozilla::Move(*resultString), ss->length());
     } else {
         if (result == OOM)
             ReportOutOfMemory(cx);
@@ -1653,27 +1639,27 @@ GlobalHelperThreadState::compressionTask
         SourceCompressionTask* task = threads[i].compressionTask();
         if (task && task->source() == ss)
             return task;
     }
     return nullptr;
 }
 
 void
-HelperThread::handleGCHelperWorkload()
+HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().isLocked());
     MOZ_ASSERT(HelperThreadState().canStartGCHelperTask());
     MOZ_ASSERT(idle());
 
     currentTask.emplace(HelperThreadState().gcHelperWorklist().popCopy());
     GCHelperState* task = gcHelperTask();
 
     {
-        AutoUnlockHelperThreadState unlock;
+        AutoUnlockHelperThreadState unlock(locked);
         task->work();
     }
 
     currentTask.reset();
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER);
 }
 
 void
@@ -1710,35 +1696,35 @@ HelperThread::threadLoop()
                 (ionCompile = HelperThreadState().pendingIonCompileHasSufficientPriority()) ||
                 HelperThreadState().canStartParseTask() ||
                 HelperThreadState().canStartCompressionTask() ||
                 HelperThreadState().canStartGCHelperTask() ||
                 HelperThreadState().canStartGCParallelTask())
             {
                 break;
             }
-            HelperThreadState().wait(GlobalHelperThreadState::PRODUCER);
+            HelperThreadState().wait(lock, GlobalHelperThreadState::PRODUCER);
         }
 
         // Dispatch tasks, prioritizing wasm work.
         if (HelperThreadState().canStartWasmCompile()) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_ASMJS);
-            handleWasmWorkload();
+            handleWasmWorkload(lock);
         } else if (ionCompile) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_ION);
-            handleIonWorkload();
+            handleIonWorkload(lock);
         } else if (HelperThreadState().canStartParseTask()) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_PARSE);
-            handleParseWorkload();
+            handleParseWorkload(lock);
         } else if (HelperThreadState().canStartCompressionTask()) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_COMPRESS);
-            handleCompressionWorkload();
+            handleCompressionWorkload(lock);
         } else if (HelperThreadState().canStartGCHelperTask()) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_GCHELPER);
-            handleGCHelperWorkload();
+            handleGCHelperWorkload(lock);
         } else if (HelperThreadState().canStartGCParallelTask()) {
             js::oom::SetThreadType(js::oom::THREAD_TYPE_GCPARALLEL);
-            handleGCParallelWorkload();
+            handleGCParallelWorkload(lock);
         } else {
             MOZ_CRASH("No task to perform");
         }
     }
 }
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -18,19 +18,23 @@
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Variant.h"
 
 #include "jscntxt.h"
 #include "jslock.h"
 
 #include "frontend/TokenStream.h"
 #include "jit/Ion.h"
+#include "threading/ConditionVariable.h"
+#include "threading/Mutex.h"
 
 namespace js {
 
+class AutoLockHelperThreadState;
+class AutoUnlockHelperThreadState;
 struct HelperThread;
 struct ParseTask;
 namespace jit {
   class IonBuilder;
 } // namespace jit
 namespace wasm {
   class FuncIR;
   class FunctionCompileResults;
@@ -42,16 +46,19 @@ enum class ParseTaskKind
 {
     Script,
     Module
 };
 
 // Per-process state for off thread work items.
 class GlobalHelperThreadState
 {
+    friend class AutoLockHelperThreadState;
+    friend class AutoUnlockHelperThreadState;
+
   public:
     // Number of CPUs to treat this machine as having when creating threads.
     // May be accessed without locking.
     size_t cpuCount;
 
     // Number of threads to create. May be accessed without locking.
     size_t threadCount;
 
@@ -123,17 +130,18 @@ class GlobalHelperThreadState
         // For notifying threads doing work that they may be able to make progress.
         PRODUCER,
 
         // For notifying threads doing work which are paused that they may be
         // able to resume making progress.
         PAUSE
     };
 
-    void wait(CondVar which, mozilla::TimeDuration timeout = mozilla::TimeDuration::Forever());
+    void wait(AutoLockHelperThreadState& locked, CondVar which,
+              mozilla::TimeDuration timeout = mozilla::TimeDuration::Forever());
     void notifyAll(CondVar which);
     void notifyOne(CondVar which);
 
     // Helper method for removing items from the vectors below while iterating over them.
     template <typename T>
     void remove(T& vector, size_t* index)
     {
         vector[(*index)--] = vector.back();
@@ -242,32 +250,32 @@ class GlobalHelperThreadState
     bool checkTaskThreadLimit(size_t maxThreads) const;
 
   private:
 
     /*
      * Lock protecting all mutable shared state accessed by helper threads, and
      * used by all condition variables.
      */
-    PRLock* helperLock;
+    js::Mutex helperLock;
 #ifdef DEBUG
     mozilla::Atomic<PRThread*> lockOwner;
 #endif
 
     /* Condvars for threads waiting/notifying each other. */
-    PRCondVar* consumerWakeup;
-    PRCondVar* producerWakeup;
-    PRCondVar* pauseWakeup;
+    js::ConditionVariable consumerWakeup;
+    js::ConditionVariable producerWakeup;
+    js::ConditionVariable pauseWakeup;
 
-    PRCondVar* whichWakeup(CondVar which) {
+    js::ConditionVariable& whichWakeup(CondVar which) {
         switch (which) {
           case CONSUMER: return consumerWakeup;
           case PRODUCER: return producerWakeup;
           case PAUSE: return pauseWakeup;
-          default: MOZ_CRASH();
+          default: MOZ_CRASH("Invalid CondVar in |whichWakeup|");
         }
     }
 };
 
 static inline GlobalHelperThreadState&
 HelperThreadState()
 {
     extern GlobalHelperThreadState* gHelperThreadState;
@@ -346,22 +354,22 @@ struct HelperThread
     template <typename T>
     T maybeCurrentTaskAs() {
         if (currentTask.isSome() && currentTask->is<T>())
             return currentTask->as<T>();
 
         return nullptr;
     }
 
-    void handleWasmWorkload();
-    void handleIonWorkload();
-    void handleParseWorkload();
-    void handleCompressionWorkload();
-    void handleGCHelperWorkload();
-    void handleGCParallelWorkload();
+    void handleWasmWorkload(AutoLockHelperThreadState& locked);
+    void handleIonWorkload(AutoLockHelperThreadState& locked);
+    void handleParseWorkload(AutoLockHelperThreadState& locked);
+    void handleCompressionWorkload(AutoLockHelperThreadState& locked);
+    void handleGCHelperWorkload(AutoLockHelperThreadState& locked);
+    void handleGCParallelWorkload(AutoLockHelperThreadState& locked);
 };
 
 /* Methods for interacting with helper threads. */
 
 // Create data structures used by helper threads.
 bool
 CreateHelperThreadsState();
 
@@ -431,47 +439,68 @@ struct AutoEnqueuePendingParseTasksAfter
     explicit AutoEnqueuePendingParseTasksAfterGC(const gc::GCRuntime& gc) : gc_(gc) {}
     ~AutoEnqueuePendingParseTasksAfterGC();
 };
 
 /* Start a compression job for the specified token. */
 bool
 StartOffThreadCompression(ExclusiveContext* cx, SourceCompressionTask* task);
 
-class MOZ_RAII AutoLockHelperThreadState
+class MOZ_RAII AutoLockHelperThreadState : public LockGuard<Mutex>
 {
+    using Base = LockGuard<Mutex>;
+
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
   public:
     explicit AutoLockHelperThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+      : Base(HelperThreadState().helperLock)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        HelperThreadState().lock();
+
+#ifdef DEBUG
+        HelperThreadState().lockOwner = PR_GetCurrentThread();
+#endif
     }
 
     ~AutoLockHelperThreadState() {
-        HelperThreadState().unlock();
+#ifdef DEBUG
+        HelperThreadState().lockOwner = nullptr;
+#endif
     }
 };
 
 class MOZ_RAII AutoUnlockHelperThreadState
 {
+    // This is only in a Maybe so that we can update the DEBUG-only lockOwner
+    // thread in the proper order.
+    mozilla::Maybe<UnlockGuard<Mutex>> unlocked;
+
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
   public:
 
-    explicit AutoUnlockHelperThreadState(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+    explicit AutoUnlockHelperThreadState(AutoLockHelperThreadState& locked
+                                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        HelperThreadState().unlock();
+
+#ifdef DEBUG
+        HelperThreadState().lockOwner = nullptr;
+#endif
+
+        unlocked.emplace(locked);
     }
 
-    ~AutoUnlockHelperThreadState()
-    {
-        HelperThreadState().lock();
+    ~AutoUnlockHelperThreadState() {
+        unlocked.reset();
+
+#ifdef DEBUG
+        HelperThreadState().lockOwner = PR_GetCurrentThread();
+#endif
     }
 };
 
 struct ParseTask
 {
     ParseTaskKind kind;
     ExclusiveContext* cx;
     OwningCompileOptions options;
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -123,20 +123,19 @@ static const JSWrapObjectCallbacks Defau
 };
 
 static size_t
 ReturnZeroSize(const void* p)
 {
     return 0;
 }
 
-JSRuntime::JSRuntime(JSContext* cx, JSRuntime* parentRuntime)
+JSRuntime::JSRuntime(JSRuntime* parentRuntime)
   : mainThread(this),
     jitTop(nullptr),
-    jitJSContext(nullptr),
     jitActivation(nullptr),
     jitStackLimit_(0xbad),
     jitStackLimitNoInterrupt_(0xbad),
 #ifdef DEBUG
     ionBailAfter_(0),
 #endif
     activation_(nullptr),
     profilingActivation_(nullptr),
@@ -168,17 +167,16 @@ JSRuntime::JSRuntime(JSContext* cx, JSRu
     numExclusiveThreads(0),
     numCompartments(0),
     localeCallbacks(nullptr),
     defaultLocale(nullptr),
     defaultVersion_(JSVERSION_DEFAULT),
     ownerThread_(nullptr),
     ownerThreadNative_(0),
     tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
-    context_(cx),
     jitRuntime_(nullptr),
     selfHostingGlobal_(nullptr),
     nativeStackBase(GetNativeStackBase()),
     destroyCompartmentCallback(nullptr),
     sizeOfIncludingThisCompartmentCallback(nullptr),
     destroyZoneCallback(nullptr),
     sweepZoneCallback(nullptr),
     compartmentNameCallback(nullptr),
@@ -513,27 +511,27 @@ void
 JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
 {
     // Several tables in the runtime enumerated below can be used off thread.
     AutoLockForExclusiveAccess lock(this);
 
     // For now, measure the size of the derived class (JSContext).
     // TODO (bug 1281529): make memory reporting reflect the new
     // JSContext/JSRuntime world better.
-    rtSizes->object += mallocSizeOf(context_);
+    rtSizes->object += mallocSizeOf(unsafeContextFromAnyThread());
 
     rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
 
     if (!parentRuntime) {
         rtSizes->atomsTable += mallocSizeOf(staticStrings);
         rtSizes->atomsTable += mallocSizeOf(commonNames);
         rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
     }
 
-    rtSizes->contexts += context_->sizeOfExcludingThis(mallocSizeOf);
+    rtSizes->contexts += unsafeContextFromAnyThread()->sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
 
     if (sharedImmutableStrings_) {
@@ -978,8 +976,13 @@ void
 JSRuntime::ionLazyLinkListAdd(jit::IonBuilder* builder)
 {
     MOZ_ASSERT(TlsPerThreadData.get()->runtimeFromMainThread(),
             "Should only be mutated by the main thread.");
     ionLazyLinkList().insertFront(builder);
     ionLazyLinkListSize_++;
 }
 
+JSContext*
+PerThreadData::contextFromMainThread()
+{
+    return runtime_->contextFromMainThread();
+}
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -577,16 +577,18 @@ class PerThreadData : public PerThreadDa
     ~PerThreadData();
 
     bool init();
 
     bool associatedWith(const JSRuntime* rt) { return runtime_ == rt; }
     inline JSRuntime* runtimeFromMainThread();
     inline JSRuntime* runtimeIfOnOwnerThread();
 
+    JSContext* contextFromMainThread();
+
     inline bool exclusiveThreadsPresent();
     inline void addActiveCompilation(AutoLockForExclusiveAccess& lock);
     inline void removeActiveCompilation(AutoLockForExclusiveAccess& lock);
 
     // For threads which may be associated with different runtimes, depending
     // on the work they are doing.
     class MOZ_STACK_CLASS AutoEnterRuntime
     {
@@ -632,23 +634,16 @@ struct JSRuntime : public JS::shadow::Ru
     js::PerThreadData mainThread;
 
     /*
      * If Baseline or Ion code is on the stack, and has called into C++, this
      * will be aligned to an exit frame.
      */
     uint8_t*            jitTop;
 
-    /*
-     * The current JSContext when entering JIT code. This field may only be used
-     * from JIT code and C++ directly called by JIT code (otherwise it may refer
-     * to the wrong JSContext).
-     */
-    JSContext*          jitJSContext;
-
      /*
      * Points to the most recent JitActivation pushed on the thread.
      * See JitActivation constructor in vm/Stack.cpp
      */
     js::jit::JitActivation* jitActivation;
 
     /* See comment for JSRuntime::interrupt_. */
   private:
@@ -1013,18 +1008,16 @@ struct JSRuntime : public JS::shadow::Ru
         return ownerThreadNative_;
     }
 
     /* Temporary arena pool used while compiling and decompiling. */
     static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
     js::LifoAlloc tempLifoAlloc;
 
   private:
-    JSContext* context_;
-
     js::jit::JitRuntime* jitRuntime_;
 
     /*
      * Self-hosting state cloned on demand into other compartments. Shared with the parent
      * runtime if there is one.
      */
     js::NativeObject* selfHostingGlobal_;
 
@@ -1049,20 +1042,18 @@ struct JSRuntime : public JS::shadow::Ru
     }
     bool hasJitRuntime() const {
         return !!jitRuntime_;
     }
     js::InterpreterStack& interpreterStack() {
         return interpreterStack_;
     }
 
-    JSContext* contextFromMainThread() {
-        MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
-        return context_;
-    }
+    inline JSContext* unsafeContextFromAnyThread();
+    inline JSContext* contextFromMainThread();
 
     bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise);
     void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
     void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
 
     //-------------------------------------------------------------------------
     // Self-hosting support
     //-------------------------------------------------------------------------
@@ -1476,17 +1467,17 @@ struct JSRuntime : public JS::shadow::Ru
     static mozilla::Atomic<size_t> liveRuntimesCount;
 
   public:
     static bool hasLiveRuntimes() {
         return liveRuntimesCount > 0;
     }
 
   protected:
-    JSRuntime(JSContext* cx, JSRuntime* parentRuntime);
+    explicit JSRuntime(JSRuntime* parentRuntime);
 
     // destroyRuntime is used instead of a destructor, to ensure the downcast
     // to JSContext remains valid. The final GC triggered here depends on this.
     void destroyRuntime();
 
     bool init(uint32_t maxbytes, uint32_t maxNurseryBytes);
 
     JSRuntime* thisFromCtor() { return this; }
@@ -1641,27 +1632,20 @@ struct JSRuntime : public JS::shadow::Ru
     }
 
     void ionLazyLinkListRemove(js::jit::IonBuilder* builder);
     void ionLazyLinkListAdd(js::jit::IonBuilder* builder);
 };
 
 namespace js {
 
-// When entering JIT code, the calling JSContext* is stored into the thread's
-// PerThreadData. This function retrieves the JSContext with the pre-condition
-// that the caller is JIT code or C++ called directly from JIT code. This
-// function should not be called from arbitrary locations since the JSContext
-// may be the wrong one.
 static inline JSContext*
-GetJSContextFromJitCode()
+GetJSContextFromMainThread()
 {
-    JSContext* cx = js::TlsPerThreadData.get()->runtimeFromMainThread()->jitJSContext;
-    MOZ_ASSERT(cx);
-    return cx;
+    return js::TlsPerThreadData.get()->contextFromMainThread();
 }
 
 /*
  * Flags accompany script version data so that a) dynamically created scripts
  * can inherit their caller's compile-time properties and b) scripts can be
  * appropriately compared in the eval cache across global option changes. An
  * example of the latter is enabling the top-level-anonymous-function-is-error
  * option: subsequent evals of the same, previously-valid script text may have
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1390,37 +1390,33 @@ jit::JitActivation::JitActivation(JSCont
     rematerializedFrames_(nullptr),
     ionRecovery_(cx),
     bailoutData_(nullptr),
     lastProfilingFrame_(nullptr),
     lastProfilingCallSite_(nullptr)
 {
     if (active) {
         prevJitTop_ = cx->runtime()->jitTop;
-        prevJitJSContext_ = cx->runtime()->jitJSContext;
         prevJitActivation_ = cx->runtime()->jitActivation;
-        cx->runtime()->jitJSContext = cx;
         cx->runtime()->jitActivation = this;
 
         registerProfiling();
     } else {
         prevJitTop_ = nullptr;
-        prevJitJSContext_ = nullptr;
         prevJitActivation_ = nullptr;
     }
 }
 
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         if (isProfiling())
             unregisterProfiling();
 
         cx_->runtime()->jitTop = prevJitTop_;
-        cx_->runtime()->jitJSContext = prevJitJSContext_;
         cx_->runtime()->jitActivation = prevJitActivation_;
     }
 
     // All reocvered value are taken from activation during the bailout.
     MOZ_ASSERT(ionRecovery_.empty());
 
     // The BailoutFrameInfo should have unregistered itself from the
     // JitActivations.
@@ -1460,28 +1456,25 @@ jit::JitActivation::setActive(JSContext*
     // Only allowed to deactivate/activate if activation is top.
     // (Not tested and will probably fail in other situations.)
     MOZ_ASSERT(cx->runtime()->activation_ == this);
     MOZ_ASSERT(active != active_);
 
     if (active) {
         *((volatile bool*) active_) = true;
         prevJitTop_ = cx->runtime()->jitTop;
-        prevJitJSContext_ = cx->runtime()->jitJSContext;
         prevJitActivation_ = cx->runtime()->jitActivation;
-        cx->runtime()->jitJSContext = cx;
         cx->runtime()->jitActivation = this;
 
         registerProfiling();
 
     } else {
         unregisterProfiling();
 
         cx->runtime()->jitTop = prevJitTop_;
-        cx->runtime()->jitJSContext = prevJitJSContext_;
         cx->runtime()->jitActivation = prevJitActivation_;
 
         *((volatile bool*) active_) = false;
     }
 }
 
 void
 jit::JitActivation::removeRematerializedFrame(uint8_t* top)
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1426,17 +1426,16 @@ namespace jit {
 
 class BailoutFrameInfo;
 
 // A JitActivation is used for frames running in Baseline or Ion.
 class JitActivation : public Activation
 {
     uint8_t* prevJitTop_;
     JitActivation* prevJitActivation_;
-    JSContext* prevJitJSContext_;
     bool active_;
 
     // Rematerialized Ion frames which has info copied out of snapshots. Maps
     // frame pointers (i.e. jitTop) to a vector of rematerializations of all
     // inline frames associated with that frame.
     //
     // This table is lazily initialized by calling getRematerializedFrame.
     typedef Vector<RematerializedFrame*> RematerializedFrameVector;
@@ -1493,19 +1492,16 @@ class JitActivation : public Activation
         return prevJitTop_;
     }
     JitActivation* prevJitActivation() const {
         return prevJitActivation_;
     }
     static size_t offsetOfPrevJitTop() {
         return offsetof(JitActivation, prevJitTop_);
     }
-    static size_t offsetOfPrevJitJSContext() {
-        return offsetof(JitActivation, prevJitJSContext_);
-    }
     static size_t offsetOfPrevJitActivation() {
         return offsetof(JitActivation, prevJitActivation_);
     }
     static size_t offsetOfActiveUint8() {
         MOZ_ASSERT(sizeof(bool) == 1);
         return offsetof(JitActivation, active_);
     }
 
--- a/layout/base/DisplayItemScrollClip.cpp
+++ b/layout/base/DisplayItemScrollClip.cpp
@@ -22,16 +22,28 @@ DisplayItemScrollClip::IsAncestor(const 
     if (sc == aAncestor) {
       return true;
     }
   }
 
   return false;
 }
 
+bool
+DisplayItemScrollClip::HasRoundedCorners() const
+{
+  for (const DisplayItemScrollClip* scrollClip = this;
+       scrollClip; scrollClip = scrollClip->mParent) {
+    if (scrollClip->mClip->GetRoundedRectCount() > 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
 /* static */ nsCString
 DisplayItemScrollClip::ToString(const DisplayItemScrollClip* aScrollClip)
 {
   nsAutoCString str;
   for (const DisplayItemScrollClip* scrollClip = aScrollClip;
        scrollClip; scrollClip = scrollClip->mParent) {
     str.AppendPrintf("<%s>%s", scrollClip->mClip ? scrollClip->mClip->ToString().get() : "null",
                      scrollClip->mIsAsyncScrollable ? " [async-scrollable]" : "");
--- a/layout/base/DisplayItemScrollClip.h
+++ b/layout/base/DisplayItemScrollClip.h
@@ -85,16 +85,18 @@ public:
                          const DisplayItemScrollClip* aDescendant);
 
   /**
    * Return a string which contains the list of stringified clips for this
    * scroll clip and its ancestors. aScrollClip can be null.
    */
   static nsCString ToString(const DisplayItemScrollClip* aScrollClip);
 
+  bool HasRoundedCorners() const;
+
   /**
    * The previous (outer) scroll clip, or null.
    */
   const DisplayItemScrollClip* mParent;
 
   /**
    * The scrollable frame that this scroll clip is for. Always non-null.
    */
--- a/layout/base/DisplayListClipState.h
+++ b/layout/base/DisplayListClipState.h
@@ -264,16 +264,34 @@ public:
       //      contents" will be set to that scroll clip.
       //  (2) If one of our direct child items is a container item for which
       //      (1) or (2) happened.
       *aOutContainerSC = mState.CurrentAncestorScrollClipForStackingContextContents();
     }
     Restore();
   }
 
+  bool SavedStateHasRoundedCorners()
+  {
+    const DisplayItemScrollClip* scrollClip = mSavedState.GetCurrentInnermostScrollClip();
+    if (scrollClip && scrollClip->HasRoundedCorners()) {
+      return true;
+    }
+    const DisplayItemClip* clip = mSavedState.GetClipForContainingBlockDescendants();
+    if (clip && clip->GetRoundedRectCount() > 0) {
+      return true;
+    }
+
+    clip = mSavedState.GetClipForContentDescendants();
+    if (clip && clip->GetRoundedRectCount() > 0) {
+      return true;
+    }
+    return false;
+  }
+
   void TurnClipIntoScrollClipForContentDescendants(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
   {
     NS_ASSERTION(!mRestored, "Already restored!");
     mState.TurnClipIntoScrollClipForContentDescendants(aBuilder, aScrollableFrame);
 #ifdef DEBUG
     mClipUsed = true;
 #endif
   }
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1686,28 +1686,28 @@ TriggerPendingAnimations(nsIDocument* aD
   MOZ_ASSERT(!aReadyTime.IsNull(),
              "Animation ready time is not set. Perhaps we're using a layer"
              " manager that doesn't update it");
   TriggerPendingAnimationsOnSubDocuments(aDocument,
                                          const_cast<TimeStamp*>(&aReadyTime));
 }
 
 LayerManager*
-nsDisplayListBuilder::GetWidgetLayerManager(nsView** aView, bool* aAllowRetaining)
+nsDisplayListBuilder::GetWidgetLayerManager(nsView** aView)
 {
   nsView* view = RootReferenceFrame()->GetView();
   if (aView) {
     *aView = view;
   }
   if (RootReferenceFrame() != nsLayoutUtils::GetDisplayRootFrame(RootReferenceFrame())) {
     return nullptr;
   }
   nsIWidget* window = RootReferenceFrame()->GetNearestWidget();
   if (window) {
-    return window->GetLayerManager(aAllowRetaining);
+    return window->GetLayerManager();
   }
   return nullptr;
 }
 
 /**
  * We paint by executing a layer manager transaction, constructing a
  * single layer representing the display list, and then making it the
  * root of the layer manager, drawing into the PaintedLayers.
@@ -1715,21 +1715,20 @@ nsDisplayListBuilder::GetWidgetLayerMana
 already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder,
                                                         nsRenderingContext* aCtx,
                                                         uint32_t aFlags) {
   PROFILER_LABEL("nsDisplayList", "PaintRoot",
     js::ProfileEntry::Category::GRAPHICS);
 
   RefPtr<LayerManager> layerManager;
   bool widgetTransaction = false;
-  bool allowRetaining = false;
   bool doBeginTransaction = true;
   nsView *view = nullptr;
   if (aFlags & PAINT_USE_WIDGET_LAYERS) {
-    layerManager = aBuilder->GetWidgetLayerManager(&view, &allowRetaining);
+    layerManager = aBuilder->GetWidgetLayerManager(&view);
     if (layerManager) {
       doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION);
       widgetTransaction = true;
     }
   }
   if (!layerManager) {
     if (!aCtx) {
       NS_WARNING("Nowhere to paint into");
@@ -2084,19 +2083,20 @@ void nsDisplayList::HitTest(nsDisplayLis
     bool snap;
     nsRect r = item->GetBounds(aBuilder, &snap).Intersect(aRect);
     auto itemType = item->GetType();
     bool same3DContext =
       (itemType == nsDisplayItem::TYPE_TRANSFORM &&
        static_cast<nsDisplayTransform*>(item)->IsParticipating3DContext()) ||
       ((itemType == nsDisplayItem::TYPE_PERSPECTIVE ||
         itemType == nsDisplayItem::TYPE_OPACITY) &&
-       static_cast<nsDisplayPerspective*>(item)->Frame()->Extend3DContext());
+       item->Frame()->Extend3DContext());
     if (same3DContext &&
-        !static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext()) {
+        (itemType != nsDisplayItem::TYPE_TRANSFORM ||
+         !static_cast<nsDisplayTransform*>(item)->IsLeafOf3DContext())) {
       if (!item->GetClip().MayIntersect(aRect)) {
         continue;
       }
       AutoTArray<nsIFrame*, 1> neverUsed;
       // Start gethering leaves of the 3D rendering context, and
       // append leaves at the end of mItemBuffer.  Leaves are
       // processed at following iterations.
       aState->mInPreserves3D = true;
@@ -4711,31 +4711,45 @@ bool nsDisplayBlendContainer::TryMerge(n
     return false;
   MergeFromTrackingMergedFrames(static_cast<nsDisplayBlendContainer*>(aItem));
   return true;
 }
 
 nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayList* aList,
                                      uint32_t aFlags, ViewID aScrollTarget,
-                                     float aScrollbarThumbRatio)
+                                     float aScrollbarThumbRatio,
+                                     bool aForceActive)
     : nsDisplayWrapList(aBuilder, aFrame, aList)
     , mFlags(aFlags)
     , mScrollTarget(aScrollTarget)
     , mScrollbarThumbRatio(aScrollbarThumbRatio)
+    , mForceActive(aForceActive)
 {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOwnLayer::~nsDisplayOwnLayer() {
   MOZ_COUNT_DTOR(nsDisplayOwnLayer);
 }
 #endif
 
+LayerState
+nsDisplayOwnLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
+                                 LayerManager* aManager,
+                                 const ContainerLayerParameters& aParameters)
+{
+  if (mForceActive) {
+    return mozilla::LAYER_ACTIVE_FORCE;
+  }
+
+  return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, mAnimatedGeometryRoot);
+}
+
 // nsDisplayOpacity uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
                               LayerManager* aManager,
                               const ContainerLayerParameters& aContainerParameters)
 {
   RefPtr<ContainerLayer> layer = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -243,17 +243,17 @@ public:
   }
   void SetForPluginGeometry()
   {
     NS_ASSERTION(mMode == nsDisplayListBuilderMode::PAINTING, "Can only switch from PAINTING to PLUGIN_GEOMETRY");
     NS_ASSERTION(mWillComputePluginGeometry, "Should have signalled this in advance");
     mMode = nsDisplayListBuilderMode::PLUGIN_GEOMETRY;
   }
 
-  mozilla::layers::LayerManager* GetWidgetLayerManager(nsView** aView = nullptr, bool* aAllowRetaining = nullptr);
+  mozilla::layers::LayerManager* GetWidgetLayerManager(nsView** aView = nullptr);
 
   /**
    * @return true if the display is being built in order to determine which
    * frame is under the mouse position.
    */
   bool IsForEventDelivery()
   {
     return mMode == nsDisplayListBuilderMode::EVENT_DELIVERY;
@@ -3521,44 +3521,43 @@ public:
    * ComputeFrameMetrics, etc.
    * @param aScrollTarget when VERTICAL_SCROLLBAR or HORIZONTAL_SCROLLBAR
    * is set in the flags, this parameter should be the ViewID of the
    * scrollable content this scrollbar is for.
    */
   nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayList* aList, uint32_t aFlags = 0,
                     ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
-                    float aScrollbarThumbRatio = 0.0f);
+                    float aScrollbarThumbRatio = 0.0f,
+                    bool aForceActive = true);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayOwnLayer();
 #endif
   
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
-                                   const ContainerLayerParameters& aParameters) override
-  {
-    return mozilla::LAYER_ACTIVE_FORCE;
-  }
+                                   const ContainerLayerParameters& aParameters) override;
   virtual bool TryMerge(nsDisplayItem* aItem) override
   {
     // Don't allow merging, each sublist must have its own layer
     return false;
   }
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
   uint32_t GetFlags() { return mFlags; }
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
 protected:
   uint32_t mFlags;
   ViewID mScrollTarget;
   float mScrollbarThumbRatio;
+  bool mForceActive;
 };
 
 /**
  * A display item for subdocuments. This is more or less the same as nsDisplayOwnLayer,
  * except that it always populates the FrameMetrics instance on the ContainerLayer it
  * builds.
  */
 class nsDisplaySubDocument : public nsDisplayOwnLayer {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6521,19 +6521,18 @@ PresShell::Paint(nsView*        aViewToP
     return;
   }
 
   nsPresContext* presContext = GetPresContext();
   AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint);
 
   nsIFrame* frame = aViewToPaint->GetFrame();
 
-  bool isRetainingManager;
   LayerManager* layerManager =
-    aViewToPaint->GetWidget()->GetLayerManager(&isRetainingManager);
+    aViewToPaint->GetWidget()->GetLayerManager();
   NS_ASSERTION(layerManager, "Must be in paint event");
   bool shouldInvalidate = layerManager->NeedsWidgetInvalidation();
 
   nsAutoNotifyDidPaint notifyDidPaint(this, aFlags);
   AutoUpdateHitRegion updateHitRegion(this, frame);
 
   // Whether or not we should set first paint when painting is
   // suppressed is debatable. For now we'll do it because
@@ -6542,17 +6541,17 @@ PresShell::Paint(nsView*        aViewToP
   // See Bug 798245
   if (mIsFirstPaint && !mPaintingSuppressed) {
     layerManager->SetIsFirstPaint();
     mIsFirstPaint = false;
   }
 
   layerManager->BeginTransaction();
 
-  if (frame && isRetainingManager) {
+  if (frame) {
     // Try to do an empty transaction, if the frame tree does not
     // need to be updated. Do not try to do an empty transaction on
     // a non-retained layer manager (like the BasicLayerManager that
     // draws the window title bar on Mac), because a) it won't work
     // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE,
     // that will cause us to forget to update the real layer manager!
 
     if (!(aFlags & PAINT_LAYERS)) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2513,19 +2513,29 @@ nsIFrame::BuildDisplayListForStackingCon
    * to maintain preserve-3d. This matches the behaviour of blink and WebKit,
    * see bug 1250718.
    */
   if (useOpacity && !resultList.IsEmpty()) {
     CreateOpacityItem(aBuilder, this, resultList,
                       opacityItemForEventsOnly, containerItemScrollClip, hasPreserve3DChildren);
   }
 
+  /* If we're creating an nsDisplayTransform item that is going to combine its transform
+   * with its children (preserve-3d or perspective), then we can't have an intermediate
+   * surface. Mask layers force an intermediate surface, so if we're going to need both
+   * then create a separate wrapping layer for the mask.
+   */
+  bool needsLayerForMask = isTransformed && (Extend3DContext() || HasPerspective()) &&
+                           clipState.SavedStateHasRoundedCorners();
+  NS_ASSERTION(!Combines3DTransformWithAncestors() || !clipState.SavedStateHasRoundedCorners(),
+               "Can't support mask layers on intermediate preserve-3d frames");
+
   if (isTransformed && !resultList.IsEmpty()) {
     // Restore clip state now so nsDisplayTransform is clipped properly.
-    if (!HasPerspective() && !useFixedPosition && !useStickyPosition) {
+    if (!HasPerspective() && !useFixedPosition && !useStickyPosition && !needsLayerForMask) {
       clipState.ExitStackingContextContents(&containerItemScrollClip);
     }
     // Revert to the dirtyrect coming in from the parent, without our transform
     // taken into account.
     buildingDisplayList.SetDirtyRect(dirtyRectOutsideTransform);
     // Revert to the outer reference frame and offset because all display
     // items we create from now on are outside the transform.
     nsPoint toOuterReferenceFrame;
@@ -2544,30 +2554,37 @@ nsIFrame::BuildDisplayListForStackingCon
       nsDisplayTransform *transformItem =
         new (aBuilder) nsDisplayTransform(aBuilder, this,
                                           &resultList, dirtyRect, 0,
                                           isFullyVisible);
       resultList.AppendNewToTop(transformItem);
     }
 
     if (HasPerspective()) {
-      if (!useFixedPosition && !useStickyPosition) {
+      if (!useFixedPosition && !useStickyPosition && !needsLayerForMask) {
         clipState.ExitStackingContextContents(&containerItemScrollClip);
       }
       resultList.AppendNewToTop(
         new (aBuilder) nsDisplayPerspective(
           aBuilder, this,
           GetContainingBlock()->GetContent()->GetPrimaryFrame(), &resultList));
     }
   }
 
-  if (useFixedPosition || useStickyPosition) {
+  if (useFixedPosition || useStickyPosition || needsLayerForMask) {
     clipState.ExitStackingContextContents(&containerItemScrollClip);
   }
 
+  if (needsLayerForMask) {
+    resultList.AppendNewToTop(
+      new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList, 0,
+                                       mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
+                                       0.0f, /* aForceActive = */ false));
+  }
+
   /* If we have sticky positioning, wrap it in a sticky position item.
    */
   if (useFixedPosition) {
     resultList.AppendNewToTop(
         new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList));
   } else if (useStickyPosition) {
     resultList.AppendNewToTop(
         new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList));
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1980,17 +1980,17 @@ nsImageFrame::GetContentForEvent(WidgetE
 // XXX what should clicks on transparent pixels do?
 nsresult
 nsImageFrame::HandleEvent(nsPresContext* aPresContext,
                           WidgetGUIEvent* aEvent,
                           nsEventStatus* aEventStatus)
 {
   NS_ENSURE_ARG_POINTER(aEventStatus);
 
-  if ((aEvent->mMessage == eMouseUp && 
+  if ((aEvent->mMessage == eMouseClick &&
        aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) ||
       aEvent->mMessage == eMouseMove) {
     nsImageMap* map = GetImageMap();
     bool isServerMap = IsServerImageMap();
     if ((nullptr != map) || isServerMap) {
       nsIntPoint p;
       TranslateEventCoords(
         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this), p);
@@ -2020,18 +2020,18 @@ nsImageFrame::HandleEvent(nsPresContext*
           if (p.x < 0) p.x = 0;
           if (p.y < 0) p.y = 0;
           nsAutoCString spec;
           uri->GetSpec(spec);
           spec += nsPrintfCString("?%d,%d", p.x, p.y);
           uri->SetSpec(spec);                
           
           bool clicked = false;
-          if (aEvent->mMessage == eMouseUp) {
-            *aEventStatus = nsEventStatus_eConsumeDoDefault; 
+          if (aEvent->mMessage == eMouseClick && !aEvent->DefaultPrevented()) {
+            *aEventStatus = nsEventStatus_eConsumeDoDefault;
             clicked = true;
           }
           nsContentUtils::TriggerLink(anchorNode, aPresContext, uri, target,
                                       clicked, true, true);
         }
       }
     }
   }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/mask-layer-1.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>border-radius should work correctly for elements with perspective</title>
+
+<style>
+
+#a {
+  position: relative;
+  width: 300px;
+  height: 300px;
+  border-radius: 10px;
+  overflow: hidden;
+  background: red;
+  perspective: 1000px;
+}
+
+#b {
+  position: relative;
+  background: green;
+  height: 100%;
+  width: 10000px;
+  transform: translateX(0px);
+}
+</style>
+
+<div id="a">
+  <div id="b"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/mask-layer-2.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>border-radius should work correctly for elements with perspective and preserve-3d</title>
+
+<style>
+
+#a {
+  position: relative;
+  width: 300px;
+  height: 300px;
+  border-radius: 10px;
+  overflow: hidden;
+  background: red;
+  perspective: 1000px;
+}
+
+#b {
+  height: 100%;
+  transform-style: preserve-3d;
+  transform: rotateX(90deg);
+}
+
+#c {
+  position: relative;
+  background: green;
+  height: 100%;
+  width: 10000px;
+  transform: rotateX(90deg);
+}
+</style>
+
+<div id="a">
+  <div id="b">
+    <div id="c"></div>
+  </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/mask-layer-3.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>border-radius should work correctly for elements with preserve-3d</title>
+
+<style>
+
+#a {
+  position: relative;
+  width: 300px;
+  height: 300px;
+  border-radius: 10px;
+  overflow: hidden;
+  background: red;
+}
+
+#b {
+  height: 100%;
+  transform-style: preserve-3d;
+  transform: rotateX(90deg);
+}
+
+#c {
+  position: relative;
+  background: green;
+  height: 100%;
+  width: 10000px;
+  transform: rotateX(90deg);
+}
+</style>
+
+<div id="a">
+  <div id="b">
+    <div id="c"></div>
+  </div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/transform-3d/mask-layer-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>border-radius should work correctly for transformed elements</title>
+
+<style>
+
+#a {
+  position: relative;
+  width: 300px;
+  height: 300px;
+  border-radius: 10px;
+  overflow: hidden;
+  background: red;
+}
+
+#b {
+  position: relative;
+  background: green;
+  height: 100%;
+  width: 10000px;
+  transform: translateZ(1px);
+}
+</style>
+
+<div id="a">
+  <div id="b"></div>
+</div>
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -73,8 +73,11 @@ fuzzy-if(cocoaWidget,128,9) == animate-p
 fuzzy-if(cocoaWidget,128,9) == animate-preserve3d-child.html animate-preserve3d-ref.html # intermittently fuzzy on Mac
 == animate-backface-hidden.html about:blank
 == 1245450-1.html green-rect.html
 fuzzy(1,2000) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
 fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
 fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
 fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
 == snap-perspective-1.html snap-perspective-1-ref.html
+== mask-layer-1.html mask-layer-ref.html
+== mask-layer-2.html mask-layer-ref.html
+== mask-layer-3.html mask-layer-ref.html
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -632,17 +632,18 @@ struct nsStyleImageLayers {
                                   // This property is used for mask layer only.
                                   // For a background layer, it should always
                                   // be the initial value, which is nullptr.
                                   // Store mask-image URI so that we can resolve
                                   // SVG mask path later.
     Position      mPosition;      // [reset] See nsStyleConsts.h
     Size          mSize;          // [reset]
     uint8_t       mClip;          // [reset] See nsStyleConsts.h
-    uint8_t       mOrigin;        // [reset] See nsStyleConsts.h
+    MOZ_INIT_OUTSIDE_CTOR
+      uint8_t     mOrigin;        // [reset] See nsStyleConsts.h
     uint8_t       mAttachment;    // [reset] See nsStyleConsts.h
                                   // background-only property
                                   // This property is used for background layer
                                   // only. For a mask layer, it should always
                                   // be the initial value, which is
                                   // NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL.
     uint8_t       mBlendMode;     // [reset] See nsStyleConsts.h
                                   // background-only property
--- a/media/mtransport/transportlayerdtls.cpp
+++ b/media/mtransport/transportlayerdtls.cpp
@@ -922,16 +922,20 @@ bool TransportLayerDtls::CheckAlpn() {
       alpn_ = alpn_default_;
       return !alpn_.empty();
 
     case SSL_NEXT_PROTO_NO_OVERLAP:
       // This only happens if there is a custom NPN/ALPN callback installed and
       // that callback doesn't properly handle ALPN.
       MOZ_MTLOG(ML_ERROR, LAYER_INFO << "error in ALPN selection callback");
       return false;
+
+    case SSL_NEXT_PROTO_EARLY_VALUE:
+      MOZ_CRASH("Unexpected 0-RTT ALPN value");
+      return false;
   }
 
   // Warning: NSS won't null terminate the ALPN string for us.
   std::string chosen(chosenAlpn, chosenAlpnLen);
   MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "Selected ALPN string: " << chosen);
   if (alpn_allowed_.find(chosen) == alpn_allowed_.end()) {
     // Maybe our peer chose a protocol we didn't offer (when we are client), or
     // something is seriously wrong.
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5048,18 +5048,18 @@ pref("dom.mobileconnection.enabled", fal
 pref("dom.voicemail.enabled", true);
 #else
 pref("dom.voicemail.enabled", false);
 #endif
 // Numeric default service id for Voice Mail API calls with |serviceId|
 // parameter omitted.
 pref("dom.voicemail.defaultServiceId", 0);
 
-// Disable mapped array buffer by default.
-pref("dom.mapped_arraybuffer.enabled", false);
+// Enable mapped array buffer by default.
+pref("dom.mapped_arraybuffer.enabled", true);
 
 // The tables used for Safebrowsing phishing and malware checks.
 pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,test-malware-simple,test-unwanted-simple");
 pref("urlclassifier.phishTable", "goog-phish-shavar,test-phish-simple");
 
 // Tables for application reputation.
 pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");
 
--- a/netwerk/base/Tickler.cpp
+++ b/netwerk/base/Tickler.cpp
@@ -28,48 +28,26 @@ Tickler::Tickler()
     , mEnabled(false)
     , mDelay(16)
     , mDuration(TimeDuration::FromMilliseconds(400))
     , mFD(nullptr)
 {
   MOZ_ASSERT(NS_IsMainThread());
 }
 
-class TicklerThreadDestructor  : public Runnable
-{
-public:
-  explicit TicklerThreadDestructor(nsIThread *aThread)
-    : mThread(aThread) { }
-
-  NS_IMETHOD Run() override
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    if (mThread)
-      mThread->Shutdown();
-    return NS_OK;
-  }
-
-private:
-  ~TicklerThreadDestructor() { }
-  nsCOMPtr<nsIThread> mThread;
-};
-
 Tickler::~Tickler()
 {
   // non main thread uses of the tickler should hold weak
   // references to it if they must hold a reference at all
   MOZ_ASSERT(NS_IsMainThread());
 
-  // Shutting down a thread can spin the event loop - which is a surprising
-  // thing to do from a dtor. Running it on its own event is safer.
-  nsCOMPtr<nsIRunnable> event = new TicklerThreadDestructor(mThread);
-  if (NS_FAILED(NS_DispatchToCurrentThread(event))) {
-    mThread->Shutdown();
+  if (mThread) {
+    mThread->AsyncShutdown();
+    mThread = nullptr;
   }
-  mThread = nullptr;
 
   if (mTimer)
     mTimer->Cancel();
   if (mFD)
     PR_Close(mFD);
 }
 
 nsresult
--- a/netwerk/cache2/CacheEntry.cpp
+++ b/netwerk/cache2/CacheEntry.cpp
@@ -204,22 +204,22 @@ CacheEntry::CacheEntry(const nsACString&
 , mSortingExpirationTime(uint32_t(-1))
 , mLock("CacheEntry")
 , mFileStatus(NS_ERROR_NOT_INITIALIZED)
 , mURI(aURI)
 , mEnhanceID(aEnhanceID)
 , mStorageID(aStorageID)
 , mUseDisk(aUseDisk)
 , mSkipSizeCheck(aSkipSizeCheck)
+, mIsDoomed(false)
 , mSecurityInfoLoaded(false)
 , mPreventCallbacks(false)
 , mHasData(false)
 , mPinned(aPin)
 , mPinningKnown(false)
-, mIsDoomed(false)
 , mState(NOTLOADED)
 , mRegistration(NEVERREGISTERED)
 , mWriter(nullptr)
 , mPredictedDataSize(0)
 , mUseCount(0)
 {
   LOG(("CacheEntry::CacheEntry [this=%p]", this));
 
--- a/netwerk/cache2/CacheEntry.h
+++ b/netwerk/cache2/CacheEntry.h
@@ -287,20 +287,26 @@ private:
   // Using ReleaseAcquire since we only control access to mFile with this.
   // When mFileStatus is read and found success it is ensured there is mFile and
   // that it is after a successful call to Init().
   ::mozilla::Atomic<nsresult, ::mozilla::ReleaseAcquire> mFileStatus;
   nsCString mURI;
   nsCString mEnhanceID;
   nsCString mStorageID;
 
+  // mUseDisk, mSkipSizeCheck, mIsDoomed are plain "bool", not "bool:1",
+  // so as to avoid bitfield races with the byte containing
+  // mSecurityInfoLoaded et al.  See bug 1278524.
+  //
   // Whether it's allowed to persist the data to disk
-  bool const mUseDisk : 1;
+  bool const mUseDisk;
   // Whether it should skip max size check.
-  bool const mSkipSizeCheck : 1;
+  bool const mSkipSizeCheck;
+  // Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
+  bool mIsDoomed;
 
   // Following flags are all synchronized with the cache entry lock.
 
   // Whether security info has already been looked up in metadata.
   bool mSecurityInfoLoaded : 1;
   // Prevents any callback invocation
   bool mPreventCallbacks : 1;
   // true: after load and an existing file, or after output stream has been opened.
@@ -311,20 +317,16 @@ private:
   //        fails to open an output stream.
   bool mHasData : 1;
   // The indication of pinning this entry was open with
   bool mPinned : 1;
   // Whether the pinning state of the entry is known (equals to the actual state
   // of the cache file)
   bool mPinningKnown : 1;
 
-  // Set when entry is doomed with AsyncDoom() or DoomAlreadyRemoved().
-  // Left as a standalone flag to not bother with locking (there is no need).
-  bool mIsDoomed;
-
   static char const * StateString(uint32_t aState);
 
   enum EState {      // transiting to:
     NOTLOADED = 0,   // -> LOADING | EMPTY
     LOADING = 1,     // -> EMPTY | READY
     EMPTY = 2,       // -> WRITING
     WRITING = 3,     // -> EMPTY | READY
     READY = 4,       // -> REVALIDATING
--- a/old-configure.in
+++ b/old-configure.in
@@ -2452,17 +2452,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.25, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.26, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_SYSTEM_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS="-I${DIST}/include/nss"
 fi
 
--- a/python/mozbuild/mozbuild/artifacts.py
+++ b/python/mozbuild/mozbuild/artifacts.py
@@ -721,29 +721,32 @@ class ArtifactCache(CacheManager):
         self.log(logging.INFO, 'artifact',
             {'filename': result + PROCESSED_SUFFIX},
             'Last installed binaries from local processed file {filename}')
 
 
 class Artifacts(object):
     '''Maintain state to efficiently fetch build artifacts from a Firefox tree.'''
 
-    def __init__(self, tree, substs, defines, job=None, log=None, cache_dir='.', hg=None, git=None, skip_cache=False):
+    def __init__(self, tree, substs, defines, job=None, log=None,
+                 cache_dir='.', hg=None, git=None, skip_cache=False,
+                 topsrcdir=None):
         if (hg and git) or (not hg and not git):
             raise ValueError("Must provide path to exactly one of hg and git")
 
         self._substs = substs
         self._defines = defines
         self._tree = tree
         self._job = job or self._guess_artifact_job()
         self._log = log
         self._hg = hg
         self._git = git
         self._cache_dir = cache_dir
         self._skip_cache = skip_cache
+        self._topsrcdir = topsrcdir
 
         try:
             self._artifact_job = get_job_details(self._job, log=self._log)
         except KeyError:
             self.log(logging.INFO, 'artifact',
                 {'job': self._job},
                 'Unknown job {job}')
             raise KeyError("Unknown job")
@@ -856,17 +859,17 @@ class Artifacts(object):
         if self._git:
             return self._get_hg_revisions_from_git()
 
         return subprocess.check_output([
             self._hg, 'log',
             '--template', '{node}\n',
             '-r', 'last(public() and ::., {num})'.format(
                 num=NUM_REVISIONS_TO_QUERY)
-        ]).splitlines()
+        ], cwd=self._topsrcdir).splitlines()
 
     def _find_pushheads(self):
         """Returns an iterator of recent pushhead revisions, starting with the
         working parent.
         """
 
         last_revs = self._get_recent_public_revisions()
         candidate_pushheads = set(self._pushheads_from_rev(last_revs[0].rstrip(),
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -1481,17 +1481,18 @@ class PackageFrontend(MachCommandBase):
                 git = which.which('git.exe')
             else:
                 git = which.which('git')
 
         # Absolutely must come after the virtualenv is populated!
         from mozbuild.artifacts import Artifacts
         artifacts = Artifacts(tree, self.substs, self.defines, job,
                               log=self.log, cache_dir=cache_dir,
-                              skip_cache=skip_cache, hg=hg, git=git)
+                              skip_cache=skip_cache, hg=hg, git=git,
+                              topsrcdir=self.topsrcdir)
         return artifacts
 
     @ArtifactSubCommand('artifact', 'install',
         'Install a good pre-built artifact.')
     @CommandArgument('source', metavar='SRC', nargs='?', type=str,
         help='Where to fetch and install artifacts from.  Can be omitted, in '
             'which case the current hg repository is inspected; an hg revision; '
             'a remote URL; or a local file.',
--- a/security/nss/.taskcluster.yml
+++ b/security/nss/.taskcluster.yml
@@ -47,35 +47,27 @@ tasks:
             The task that creates all of the other tasks in the task graph
 
       workerType: "hg-worker"
       provisionerId: "aws-provisioner-v1"
 
       tags:
         createdForUser: {{owner}}
 
-      scopes:
-        - "queue:route:tc-treeherder-stage.nss.{{revision_hash}}"
-        - "queue:route:tc-treeherder.nss.{{revision_hash}}"
-        - "scheduler:extend-task-graph:*"
-        # mozilla-taskcluster will append the appropriate assume:repo:<repo>
-        # scope here.
-
       routes:
-        - "tc-treeherder-stage.nss.{{revision_hash}}"
-        - "tc-treeherder.nss.{{revision_hash}}"
+        - "tc-treeherder-stage.v2.{{project}}.{{revision}}.{{pushlog_id}}"
+        - "tc-treeherder.v2.{{project}}.{{revision}}.{{pushlog_id}}"
 
       payload:
-        image: "ttaubert/nss-ci:0.0.16"
+        image: "ttaubert/nss-ci:0.0.17"
 
         env:
           TC_OWNER: {{owner}}
           TC_SOURCE: {{{source}}}
-          TC_REVISION: '{{revision}}'
-          TC_REVISION_HASH: '{{revision_hash}}'
+          NSS_PUSHLOG_ID: '{{pushlog_id}}'
           NSS_HEAD_REPOSITORY: '{{{url}}}'
           NSS_HEAD_REVISION: '{{revision}}'
 
         maxRunTime: 1800
 
         command:
           - bash
           - -cx
@@ -90,14 +82,12 @@ tasks:
             expires: "{{#from_now}}7 days{{/from_now}}"
 
         graphs:
           - /home/worker/artifacts/graph.json
 
       extra:
         treeherder:
           symbol: D
-          revision: '{{revision}}'
-          revision_hash: '{{revision_hash}}'
           build:
             platform: nss-decision
           machine:
             platform: nss-decision
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_25_RC1
+NSS_3.26_BETA1
--- a/security/nss/automation/taskcluster/docker/Dockerfile
+++ b/security/nss/automation/taskcluster/docker/Dockerfile
@@ -1,27 +1,27 @@
 FROM ubuntu:16.04
 MAINTAINER Tim Taubert <ttaubert@mozilla.com>
 
 RUN useradd -d /home/worker -s /bin/bash -m worker
 WORKDIR /home/worker
 
-# Install non-build specific dependencies.
-ADD setup.sh /tmp/setup.sh
-RUN bash /tmp/setup.sh
-
 # Add build and test scripts.
 ADD bin /home/worker/bin
 RUN chmod +x /home/worker/bin/*
 
-# Set variables usually configured at login.
+# Install dependencies.
+ADD setup.sh /tmp/setup.sh
+RUN bash /tmp/setup.sh
+
+# Env variables.
 ENV HOME /home/worker
 ENV SHELL /bin/bash
 ENV USER worker
 ENV LOGNAME worker
 ENV HOSTNAME taskcluster-worker
 ENV LANG en_US.UTF-8
 ENV LC_ALL en_US.UTF-8
-env HOST localhost
-env DOMSUF localdomain
+ENV HOST localhost
+ENV DOMSUF localdomain
 
 # Set a default command for debugging.
 CMD ["/bin/bash", "--login"]
--- a/security/nss/automation/taskcluster/docker/setup.sh
+++ b/security/nss/automation/taskcluster/docker/setup.sh
@@ -17,22 +17,16 @@ apt_packages+=('lib32z1-dev')
 apt_packages+=('gcc-multilib')
 apt_packages+=('g++-multilib')
 
 # Install prerequisites.
 apt-get -y update
 export DEBIAN_FRONTEND=noninteractive
 apt-get install -y --no-install-recommends curl apt-utils
 
-# clang(-format)-3.8
-apt_packages+=('clang-3.8')
-apt_packages+=('clang-format-3.8')
-curl http://llvm.org/apt/llvm-snapshot.gpg.key | apt-key add -
-echo "deb http://llvm.org/apt/xenial/ llvm-toolchain-xenial-3.8 main" > /etc/apt/sources.list.d/docker.list
-
 # Install the first round of packages.
 apt-get -y update
 apt-get install -y --no-install-recommends ${apt_packages[@]}
 
 # gcc 6
 apt_packages=()
 apt_packages+=('g++-6')
 apt_packages+=('g++-4.8')
@@ -43,19 +37,22 @@ echo "deb http://ppa.launchpad.net/ubunt
 
 # Install the second round of packages.
 apt-get -y update
 apt-get install -y --no-install-recommends ${apt_packages[@]}
 
 # 32-bit builds
 ln -s /usr/include/x86_64-linux-gnu/zconf.h /usr/include
 
+# Install clang-3.8 into /usr/local/.
+curl http://llvm.org/releases/3.8.0/clang+llvm-3.8.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar xJv -C /usr/local --strip-components=1
+
 # Compiler options.
-update-alternatives --install /usr/bin/gcc gcc /usr/bin/clang-3.8 5
-update-alternatives --install /usr/bin/g++ g++ /usr/bin/clang++-3.8 5
+update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/clang 5
+update-alternatives --install /usr/bin/g++ g++ /usr/local/bin/clang++ 5
 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 10
 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 10
 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 20
 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-6 20
 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 30
 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 30
 
 locale-gen en_US.UTF-8
--- a/security/nss/automation/taskcluster/graph/build.js
+++ b/security/nss/automation/taskcluster/graph/build.js
@@ -5,20 +5,19 @@
 var fs = require("fs");
 var path = require("path");
 var merge = require("merge");
 var yaml = require("js-yaml");
 var slugid = require("slugid");
 var flatmap = require("flatmap");
 
 // Default values for debugging.
-var TC_REVISION = process.env.TC_REVISION || "{{tc_rev}}";
-var TC_REVISION_HASH = process.env.TC_REVISION_HASH || "{{tc_rev_hash}}";
 var TC_OWNER = process.env.TC_OWNER || "{{tc_owner}}";
 var TC_SOURCE = process.env.TC_SOURCE || "{{tc_source}}";
+var NSS_PUSHLOG_ID = process.env.NSS_PUSHLOG_ID || "{{nss_pushlog_id}}";
 var NSS_HEAD_REPOSITORY = process.env.NSS_HEAD_REPOSITORY || "{{nss_head_repo}}";
 var NSS_HEAD_REVISION = process.env.NSS_HEAD_REVISION || "{{nss_head_rev}}";
 
 // Register custom YAML types.
 var YAML_SCHEMA = yaml.Schema.create([
   // Point in time at $now + x hours.
   new yaml.Type('!from_now', {
     kind: "scalar",
@@ -60,27 +59,20 @@ function parseYamlFile(file, fallback) {
   return yaml.load(source, {schema: YAML_SCHEMA});
 }
 
 // Add base information to the given task.
 function decorateTask(task) {
   // Assign random task id.
   task.taskId = slugid.v4();
 
-  // Permissions.
-  task.task.scopes = [
-    "queue:route:tc-treeherder-stage.nss." + TC_REVISION_HASH,
-    "queue:route:tc-treeherder.nss." + TC_REVISION_HASH,
-    "scheduler:extend-task-graph:*"
-  ];
-
   // TreeHerder routes.
   task.task.routes = [
-    "tc-treeherder-stage.nss." + TC_REVISION_HASH,
-    "tc-treeherder.nss." + TC_REVISION_HASH
+    "tc-treeherder-stage.v2.nss." + NSS_HEAD_REVISION + "." + NSS_PUSHLOG_ID,
+    "tc-treeherder.v2.nss." + NSS_HEAD_REVISION + "." + NSS_PUSHLOG_ID
   ];
 }
 
 // Generate all tasks for a given build.
 function generateBuildTasks(platform, file) {
   var dir = path.join(__dirname, "./" + platform);
 
   // Parse base definitions.
--- a/security/nss/automation/taskcluster/graph/linux/_build_base.yml
+++ b/security/nss/automation/taskcluster/graph/linux/_build_base.yml
@@ -9,17 +9,17 @@ task:
   schedulerId: task-graph-scheduler
 
   metadata:
     owner: !env TC_OWNER
     source: !env TC_SOURCE
 
   payload:
     maxRunTime: 3600
-    image: ttaubert/nss-ci:0.0.16
+    image: ttaubert/nss-ci:0.0.17
 
     artifacts:
       public:
         type: directory
         path: /home/worker/artifacts
         expires: !from_now 24
 
     command:
@@ -30,11 +30,9 @@ task:
     env:
       NSS_HEAD_REPOSITORY: !env NSS_HEAD_REPOSITORY
       NSS_HEAD_REVISION: !env NSS_HEAD_REVISION
       GCC_VERSION: gcc-5
       GXX_VERSION: g++-5
 
   extra:
     treeherder:
-      revision: !env TC_REVISION
-      revision_hash: !env TC_REVISION_HASH
       symbol: B
--- a/security/nss/automation/taskcluster/graph/linux/_test_base.yml
+++ b/security/nss/automation/taskcluster/graph/linux/_test_base.yml
@@ -9,14 +9,14 @@ task:
   schedulerId: task-graph-scheduler
 
   metadata:
     owner: !env TC_OWNER
     source: !env TC_SOURCE
 
   payload:
     maxRunTime: 3600
-    image: ttaubert/nss-ci:0.0.16
+    image: ttaubert/nss-ci:0.0.17
 
     command:
       - "/bin/bash"
       - "-c"
       - "bin/checkout.sh && nss/automation/taskcluster/scripts/run_tests.sh"
--- a/security/nss/automation/taskcluster/graph/linux/build32-debug.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build32-debug.yml
@@ -27,52 +27,46 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - tools
 
 - task:
     metadata:
       name: "Linux 32 (debug, no TLS 1.3)"
       description: "Linux 32 (debug, no TLS 1.3)"
 
-    payload:
-      env:
-        NSS_TESTS: ssl
-
     extra:
       treeherder:
         build:
           platform: linux32
         machine:
           platform: linux32
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
-  tests:
-    - ssl
-
 - task:
     metadata:
       name: "Linux 32 (debug, clang-3.8)"
       description: "Linux 32 (debug, clang-3.8)"
 
     payload:
       env:
         NSS_ENABLE_TLS_1_3: 1
-        GCC_VERSION: clang-3.8
-        GXX_VERSION: clang++-3.8
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
 
     extra:
       treeherder:
         build:
           platform: linux32
         machine:
           platform: linux32
         collection:
--- a/security/nss/automation/taskcluster/graph/linux/build32-opt.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build32-opt.yml
@@ -28,53 +28,50 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - tools
 
 - task:
     metadata:
       name: "Linux 32 (opt, no TLS 1.3)"
       description: "Linux 32 (opt, no TLS 1.3)"
 
     payload:
       env:
-        NSS_TESTS: ssl
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
         machine:
           platform: linux32
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
-  tests:
-    - ssl
-
 - task:
     metadata:
       name: "Linux 32 (opt, clang-3.8)"
       description: "Linux 32 (opt, clang-3.8)"
 
     payload:
       env:
         NSS_ENABLE_TLS_1_3: 1
-        GCC_VERSION: clang-3.8
-        GXX_VERSION: clang++-3.8
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         BUILD_OPT: 1
 
     extra:
       treeherder:
         build:
           platform: linux32
         machine:
           platform: linux32
--- a/security/nss/automation/taskcluster/graph/linux/build64-asan.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-asan.yml
@@ -1,19 +1,19 @@
 ---
 - task:
     metadata:
       name: "Linux 64 (ASan, debug)"
       description: "Linux 64 (ASan, debug)"
 
     payload:
       env:
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         NSS_ENABLE_TLS_1_3: 1
-        GCC_VERSION: clang-3.8
-        GXX_VERSION: clang++-3.8
         USE_ASAN: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
         machine:
@@ -31,36 +31,10 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - tools
-
-- task:
-    metadata:
-      name: "Linux 64 (ASan, debug, no TLS 1.3)"
-      description: "Linux 64 (ASan, debug, no TLS 1.3)"
-
-    payload:
-      env:
-        GCC_VERSION: clang-3.8
-        GXX_VERSION: clang++-3.8
-        NSS_TESTS: ssl
-        USE_ASAN: 1
-        USE_64: 1
-
-    extra:
-      treeherder:
-        build:
-          platform: linux64
-        machine:
-          platform: linux64
-        collection:
-          asan: true
-        groupSymbol: SSL
-        groupName: SSL tests
-
-  tests:
-    - ssl
--- a/security/nss/automation/taskcluster/graph/linux/build64-debug.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-debug.yml
@@ -22,59 +22,57 @@
     - chains
     - cipher
     - crmf
     - db
     - ec
     - fips
     - gtests
     - lowhash
+    - memleak
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - tools
 
 - task:
     metadata:
       name: "Linux 64 (debug, no TLS 1.3)"
       description: "Linux 64 (debug, no TLS 1.3)"
 
     payload:
       env:
-        NSS_TESTS: ssl
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
         machine:
           platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
-  tests:
-    - ssl
-
 - task:
     metadata:
       name: "Linux 64 (debug, clang-3.8)"
       description: "Linux 64 (debug, clang-3.8)"
 
     payload:
       env:
         NSS_ENABLE_TLS_1_3: 1
-        GCC_VERSION: clang-3.8
-        GXX_VERSION: clang++-3.8
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
         machine:
           platform: linux64
@@ -149,8 +147,31 @@
           platform: linux64
         machine:
           platform: linux64
         collection:
           debug: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noPkcs11Bypass
+
+- task:
+    metadata:
+      name: "Linux 64 (debug, NSS_DISABLE_LIBPKIX=1)"
+      description: "Linux 64 (debug, NSS_DISABLE_LIBPKIX=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NSS_DISABLE_LIBPKIX: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        machine:
+          platform: linux64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noLibpkix
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/graph/linux/build64-lsan.yml
@@ -0,0 +1,35 @@
+---
+- task:
+    metadata:
+      name: "Linux 64 (LSan, debug)"
+      description: "Linux 64 (LSan, debug)"
+
+    payload:
+      env:
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
+        NSS_DISABLE_ARENA_FREE_LIST: 1
+        NSS_DISABLE_UNLOAD: 1
+        NSS_ENABLE_TLS_1_3: 1
+        NSS_ENABLE_LSAN: 1
+        USE_ASAN: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: linux64
+        machine:
+          platform: linux64
+        collection:
+          lsan: true
+
+  tests:
+    - cipher
+    - ec
+    - gtests
+    - lowhash
+    - merge
+    - ocsp
+    - pkits
+    - sdr
deleted file mode 100644
--- a/security/nss/automation/taskcluster/graph/linux/build64-memleak.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-- task:
-    metadata:
-      name: "Linux 64 (MemLeak, debug)"
-      description: "Linux 64 (MemLeak, debug)"
-
-    payload:
-      env:
-        NSS_TESTS: memleak
-        USE_64: 1
-
-    extra:
-      treeherder:
-        build:
-          platform: linux64
-        machine:
-          platform: linux64
-        collection:
-          memleak: true
-
-  tests:
-    - memleak
--- a/security/nss/automation/taskcluster/graph/linux/build64-opt.yml
+++ b/security/nss/automation/taskcluster/graph/linux/build64-opt.yml
@@ -29,54 +29,51 @@
     - gtests
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
+    - ssl
     - tools
 
 - task:
     metadata:
       name: "Linux 64 (opt, no TLS 1.3)"
       description: "Linux 64 (opt, no TLS 1.3)"
 
     payload:
       env:
-        NSS_TESTS: ssl
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
         machine:
           platform: linux64
         collection:
           opt: true
         groupSymbol: Builds
         groupName: Various builds
         symbol: noTLSv1.3
 
-  tests:
-    - ssl
-
 - task:
     metadata:
       name: "Linux 64 (opt, clang-3.8)"
       description: "Linux 64 (opt, clang-3.8)"
 
     payload:
       env:
         NSS_ENABLE_TLS_1_3: 1
-        GCC_VERSION: clang-3.8
-        GXX_VERSION: clang++-3.8
+        GCC_VERSION: clang
+        GXX_VERSION: clang++
         BUILD_OPT: 1
         USE_64: 1
 
     extra:
       treeherder:
         build:
           platform: linux64
         machine:
--- a/security/nss/automation/taskcluster/graph/tests/memleak.yml
+++ b/security/nss/automation/taskcluster/graph/tests/memleak.yml
@@ -2,204 +2,243 @@
 - task:
     metadata:
       name: "MemLeak tests (ocsp)"
       description: "MemLeak tests (ocsp)"
 
     payload:
       env:
         NSS_MEMLEAK_TESTS: ocsp
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         symbol: ocsp
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, standard)"
       description: "MemLeak tests (ssl_server, standard)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "standard"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: standard
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: standard
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, pkix)"
       description: "MemLeak tests (ssl_server, pkix)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "pkix"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: pkix
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: pkix
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, sharedb)"
       description: "MemLeak tests (ssl_server, sharedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "sharedb"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: sharedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: sharedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_server, upgradedb)"
       description: "MemLeak tests (ssl_server, upgradedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_server"
-        NSS_CYCLES: "upgradedb"
+        NSS_MEMLEAK_TESTS: ssl_server
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Server
         groupName: MemLeak tests (ssl_server)
         symbol: upgradedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, standard)"
       description: "MemLeak tests (ssl_client, standard)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "standard"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_CYCLES: standard
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: standard
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, pkix)"
       description: "MemLeak tests (ssl_client, pkix)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "pkix"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_TESTS: memleak
+        NSS_CYCLES: pkix
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: pkix
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, sharedb)"
       description: "MemLeak tests (ssl_client, sharedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "sharedb"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_CYCLES: sharedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: sharedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (ssl_client, upgradedb)"
       description: "MemLeak tests (ssl_client, upgradedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "ssl_client"
-        NSS_CYCLES: "upgradedb"
+        NSS_MEMLEAK_TESTS: ssl_client
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Client
         groupName: MemLeak tests (ssl_client)
         symbol: upgradedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, standard)"
       description: "MemLeak tests (chains, standard)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "standard"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_CYCLES: standard
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: standard
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, pkix)"
       description: "MemLeak tests (chains, pkix)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "pkix"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_TESTS: memleak
+        NSS_CYCLES: pkix
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: pkix
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, sharedb)"
       description: "MemLeak tests (chains, sharedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "sharedb"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_CYCLES: sharedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: sharedb
+        collection:
+          memleak: true
 
 - task:
     metadata:
       name: "MemLeak tests (chains, upgradedb)"
       description: "MemLeak tests (chains, upgradedb)"
 
     payload:
       env:
-        NSS_MEMLEAK_TESTS: "chains"
-        NSS_CYCLES: "upgradedb"
+        NSS_MEMLEAK_TESTS: chains
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: memleak
 
     extra:
       treeherder:
         groupSymbol: Chains
         groupName: MemLeak tests (chains)
         symbol: upgradedb
+        collection:
+          memleak: true
--- a/security/nss/automation/taskcluster/graph/tests/ssl.yml
+++ b/security/nss/automation/taskcluster/graph/tests/ssl.yml
@@ -2,60 +2,64 @@
 - task:
     metadata:
       name: "SSL tests (standard)"
       description: "SSL tests (standard)"
 
     payload:
       maxRunTime: 7200
       env:
-        NSS_CYCLES: "standard"
+        NSS_CYCLES: standard
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: standard
         groupSymbol: SSL
         groupName: SSL tests
 
 - task:
     metadata:
       name: "SSL tests (pkix)"
       description: "SSL tests (pkix)"
 
     payload:
       env:
-        NSS_CYCLES: "pkix"
+        NSS_CYCLES: pkix
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: pkix
         groupSymbol: SSL
         groupName: SSL tests
 
 - task:
     metadata:
       name: "SSL tests (sharedb)"
       description: "SSL tests (sharedb)"
 
     payload:
       env:
-        NSS_CYCLES: "sharedb"
+        NSS_CYCLES: sharedb
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: sharedb
         groupSymbol: SSL
         groupName: SSL tests
 
 - task:
     metadata:
       name: "SSL tests (upgradedb)"
       description: "SSL tests (upgradedb)"
 
     payload:
       env:
-        NSS_CYCLES: "upgradedb"
+        NSS_CYCLES: upgradedb
+        NSS_TESTS: ssl
 
     extra:
       treeherder:
         symbol: upgradedb
         groupSymbol: SSL
         groupName: SSL tests
--- a/security/nss/automation/taskcluster/graph/tools/clang-format.yml
+++ b/security/nss/automation/taskcluster/graph/tools/clang-format.yml
@@ -10,17 +10,17 @@
     metadata:
       owner: !env TC_OWNER
       source: !env TC_SOURCE
       name: clang-format-3.8
       description: clang-format-3.8
 
     payload:
       maxRunTime: 3600
-      image: ttaubert/nss-ci:0.0.16
+      image: ttaubert/nss-ci:0.0.17
 
       command:
         - "/bin/bash"
         - "-c"
         - "bin/checkout.sh && nss/automation/taskcluster/scripts/run_clang_format.sh nss/lib/ssl"
 
       env:
         NSS_HEAD_REPOSITORY: !env NSS_HEAD_REPOSITORY
@@ -28,10 +28,8 @@
 
     extra:
       treeherder:
         build:
           platform: nss-tools
         machine:
           platform: nss-tools
         symbol: clang-format-3.8
-        revision: !env TC_REVISION
-        revision_hash: !env TC_REVISION_HASH
--- a/security/nss/automation/taskcluster/graph/windows/_build_base.yml
+++ b/security/nss/automation/taskcluster/graph/windows/_build_base.yml
@@ -28,11 +28,9 @@ task:
       PATH: "c:\\mozilla-build\\python;c:\\mozilla-build\\msys\\local\\bin;c:\\mozilla-build\\7zip;c:\\mozilla-build\\info-zip;c:\\mozilla-build\\python\\Scripts;c:\\mozilla-build\\yasm;c:\\mozilla-build\\msys\\bin;c:\\Windows\\system32;c:\\mozilla-build\\upx391w;c:\\mozilla-build\\moztools-x64\\bin;c:\\mozilla-build\\wget"
       NSS_HEAD_REPOSITORY: !env NSS_HEAD_REPOSITORY
       NSS_HEAD_REVISION: !env NSS_HEAD_REVISION
       DOMSUF: localdomain
       HOST: localhost
 
   extra:
     treeherder:
-      revision: !env TC_REVISION
-      revision_hash: !env TC_REVISION_HASH
       symbol: B
--- a/security/nss/automation/taskcluster/graph/windows/build64-debug.yml
+++ b/security/nss/automation/taskcluster/graph/windows/build64-debug.yml
@@ -28,8 +28,52 @@
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
     - tools
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (debug, no TLS 1.3)"
+      description: "Windows 2012 64 (debug, no TLS 1.3)"
+
+    payload:
+      env:
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (debug, NO_PKCS11_BYPASS=1)"
+      description: "Windows 2012 64 (debug, NO_PKCS11_BYPASS=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NO_PKCS11_BYPASS: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          debug: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
--- a/security/nss/automation/taskcluster/graph/windows/build64-opt.yml
+++ b/security/nss/automation/taskcluster/graph/windows/build64-opt.yml
@@ -29,8 +29,54 @@
     - lowhash
     - merge
     - ocsp
     - pkits
     - pkix
     - sdr
     - smime
     - tools
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (opt, no TLS 1.3)"
+      description: "Windows 2012 64 (opt, no TLS 1.3)"
+
+    payload:
+      env:
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noTLSv1.3
+
+- task:
+    metadata:
+      name: "Windows 2012 64 (opt, NO_PKCS11_BYPASS=1)"
+      description: "Windows 2012 64 (opt, NO_PKCS11_BYPASS=1)"
+
+    payload:
+      env:
+        NSS_ENABLE_TLS_1_3: 1
+        NO_PKCS11_BYPASS: 1
+        BUILD_OPT: 1
+        USE_64: 1
+
+    extra:
+      treeherder:
+        build:
+          platform: windows2012-64
+        machine:
+          platform: windows2012-64
+        collection:
+          opt: true
+        groupSymbol: Builds
+        groupName: Various builds
+        symbol: noPkcs11Bypass
--- a/security/nss/automation/taskcluster/scripts/build.sh
+++ b/security/nss/automation/taskcluster/scripts/build.sh
@@ -1,33 +1,31 @@
 #!/usr/bin/env bash
 
 set -v -e -x
 
 if [ $(id -u) = 0 ]; then
-    # Switch compilers.
-    GCC=${GCC_VERSION:-gcc-5}
-    GXX=${GXX_VERSION:-g++-5}
+    source $(dirname $0)/tools.sh
 
-    update-alternatives --set gcc "/usr/bin/$GCC"
-    update-alternatives --set g++ "/usr/bin/$GXX"
+    # Set compiler.
+    switch_compilers
 
     # Drop privileges by re-running this script.
     exec su worker $0
 fi
 
 # Clone NSPR if needed.
 if [ ! -d "nspr" ]; then
     hg clone https://hg.mozilla.org/projects/nspr
 fi
 
 # Build.
-cd nss && make nss_build_all
+cd nss && make nss_build_all && cd ..
 
 # Generate certificates.
-cd tests && NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" ./all.sh
+NSS_TESTS=cert NSS_CYCLES="standard pkix sharedb" $(dirname $0)/run_tests.sh
 
 # Reset test counter so that test runs pick up our certificates.
-cd && echo 1 > tests_results/security/localhost
+echo 1 > tests_results/security/localhost
 
 # Package.
 mkdir artifacts
 tar cvfjh artifacts/dist.tar.bz2 dist tests_results
--- a/security/nss/automation/taskcluster/scripts/run_clang_format.sh
+++ b/security/nss/automation/taskcluster/scripts/run_clang_format.sh
@@ -8,14 +8,14 @@ if [ $(id -u) = 0 ]; then
 fi
 
 # Apply clang-format 3.8 on the provided folder and verify that this doesn't change any file.
 # If any file differs after formatting, the script eventually exits with 1.
 # Any differences between formatted and unformatted files is printed to stdout to give a hint what's wrong.
 
 STATUS=0
 for i in $(find $1 -type f -name '*.[ch]' -print); do
-    if ! clang-format-3.8 $i | diff -Naur $i -; then
+    if ! clang-format $i | diff -Naur $i -; then
         echo "Sorry, $i is not formatted properly. Please use clang-format 3.8 on your patch before landing."
         STATUS=1
     fi
 done
 exit $STATUS
--- a/security/nss/automation/taskcluster/scripts/run_tests.sh
+++ b/security/nss/automation/taskcluster/scripts/run_tests.sh
@@ -1,19 +1,17 @@
 #!/usr/bin/env bash
 
 set -v -e -x
 
 if [ $(id -u) = 0 ]; then
-    # Switch compilers.
-    GCC=${GCC_VERSION:-gcc-5}
-    GXX=${GXX_VERSION:-g++-5}
+    source $(dirname $0)/tools.sh
 
-    update-alternatives --set gcc "/usr/bin/$GCC"
-    update-alternatives --set g++ "/usr/bin/$GXX"
+    # Set compiler.
+    switch_compilers
 
     # Stupid Docker.
     echo "127.0.0.1 localhost.localdomain" >> /etc/hosts
 
     # Drop privileges by re-running this script.
     exec su worker $0
 fi
 
new file mode 100644
--- /dev/null
+++ b/security/nss/automation/taskcluster/scripts/tools.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -v -e -x
+
+switch_compilers() {
+    GCC=`which ${GCC_VERSION:-gcc-5}`
+    GXX=`which ${GXX_VERSION:-g++-5}`
+
+    if [ -e "$GCC" ] && [ -e "$GXX" ]; then
+        update-alternatives --set gcc $GCC
+        update-alternatives --set g++ $GXX
+    else
+        echo "Unknown compiler $GCC_VERSION/$GXX_VERSION."
+        exit 1
+    fi
+}
--- a/security/nss/cmd/bltest/blapitest.c
+++ b/security/nss/cmd/bltest/blapitest.c
@@ -349,60 +349,52 @@ key_from_filedata(PLArenaPool *arena, SE
             }
             it++;
         }
         fpos += len;
     }
 }
 
 static RSAPrivateKey *
-rsakey_from_filedata(SECItem *filedata)
+rsakey_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     RSAPrivateKey *key;
-    PLArenaPool *arena;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     key = (RSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(RSAPrivateKey));
     key->arena = arena;
     key_from_filedata(arena, &key->version, 0, 9, filedata);
     return key;
 }
 
 static PQGParams *
-pqg_from_filedata(SECItem *filedata)
+pqg_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     PQGParams *pqg;
-    PLArenaPool *arena;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     pqg = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams));
     pqg->arena = arena;
     key_from_filedata(arena, &pqg->prime, 0, 3, filedata);
     return pqg;
 }
 
 static DSAPrivateKey *
-dsakey_from_filedata(SECItem *filedata)
+dsakey_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     DSAPrivateKey *key;
-    PLArenaPool *arena;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey));
     key->params.arena = arena;
     key_from_filedata(arena, &key->params.prime, 0, 5, filedata);
     return key;
 }
 
 #ifndef NSS_DISABLE_ECC
 static ECPrivateKey *
-eckey_from_filedata(SECItem *filedata)
+eckey_from_filedata(PLArenaPool *arena, SECItem *filedata)
 {
     ECPrivateKey *key;
-    PLArenaPool *arena;
     SECStatus rv;
     ECParams *tmpECParams = NULL;
-    arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
     /* read and convert params */
     key->ecParams.arena = arena;
     key_from_filedata(arena, &key->ecParams.DEREncoding, 0, 1, filedata);
     rv = SECOID_Init();
     CHECKERROR(rv, __LINE__);
     rv = EC_DecodeParams(&key->ecParams.DEREncoding, &tmpECParams);
     CHECKERROR(rv, __LINE__);
@@ -1805,20 +1797,20 @@ bltest_dsa_init(bltestCipherInfo *cipher
         }
         TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps);
         /* Free the n key objects */
         for (i = 0; i < cipherInfo->cxreps; i++)
             PORT_FreeArena(dummyKey[i]->params.arena, PR_TRUE);
         PORT_Free(dummyKey);
     }
     if (!dsap->pqg && dsap->pqgdata.buf.len > 0) {
-        dsap->pqg = pqg_from_filedata(&dsap->pqgdata.buf);
+        dsap->pqg = pqg_from_filedata(cipherInfo->arena, &dsap->pqgdata.buf);
     }
     if (!asymk->privKey && asymk->key.buf.len > 0) {
-        asymk->privKey = dsakey_from_filedata(&asymk->key.buf);
+        asymk->privKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
     }
     if (encrypt) {
         cipherInfo->cipher.pubkeyCipher = dsa_signDigest;
     } else {
         /* Have to convert private key to public key.  Memory
          * is freed with private key's arena  */
         DSAPublicKey *pubkey;
         DSAPrivateKey *key = (DSAPrivateKey *)asymk->privKey;
@@ -1859,17 +1851,17 @@ bltest_ecdsa_init(bltestCipherInfo *ciph
         }
         TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps);
         /* Free the n key objects */
         for (i = 0; i < cipherInfo->cxreps; i++)
             PORT_FreeArena(dummyKey[i]->ecParams.arena, PR_TRUE);
         PORT_Free(dummyKey);
     }
     if (!asymk->privKey && asymk->key.buf.len > 0) {
-        asymk->privKey = eckey_from_filedata(&asymk->key.buf);
+        asymk->privKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf);
     }
     if (encrypt) {
         cipherInfo->cipher.pubkeyCipher = ecdsa_signDigest;
     } else {
         /* Have to convert private key to public key.  Memory
      * is freed with private key's arena  */
         ECPublicKey *pubkey;
         ECPrivateKey *key = (ECPrivateKey *)asymk->privKey;
@@ -2226,33 +2218,33 @@ pubkeyInitKey(bltestCipherInfo *cipherIn
                 SECITEM_AllocItem(cipherInfo->arena, &expitem, sizeof(int));
                 for (i = 1; i <= sizeof(int); i++)
                     expitem.data[i - 1] = exponent >> (8 * (sizeof(int) - i));
                 *rsaKey = RSA_NewKey(keysize * 8, &expitem);
                 serialize_key(&(*rsaKey)->version, 9, file);
                 rsap->keysizeInBits = keysize * 8;
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
-                *rsaKey = rsakey_from_filedata(&asymk->key.buf);
+                *rsaKey = rsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
                 rsap->keysizeInBits = (*rsaKey)->modulus.len * 8;
             }
             break;
         case bltestDSA:
             dsap = &asymk->cipherParams.dsa;
             dsaKey = (DSAPrivateKey **)&asymk->privKey;
             if (keysize > 0) {
                 dsap->keysize = keysize * 8;
                 if (!dsap->pqg)
                     bltest_pqg_init(dsap);
                 rv = DSA_NewKey(dsap->pqg, dsaKey);
                 CHECKERROR(rv, __LINE__);
                 serialize_key(&(*dsaKey)->params.prime, 5, file);
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
-                *dsaKey = dsakey_from_filedata(&asymk->key.buf);
+                *dsaKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
                 dsap->keysize = (*dsaKey)->params.prime.len * 8;
             }
             break;
 #ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             ecKey = (ECPrivateKey **)&asymk->privKey;
             if (curveName != NULL) {
                 tmpECParamsDER = getECParams(curveName);
@@ -2273,17 +2265,17 @@ pubkeyInitKey(bltestCipherInfo *cipherIn
                 ecSerialize[2].len = (*ecKey)->privateValue.len;
                 serialize_key(&(ecSerialize[0]), 3, file);
                 SECITEM_FreeItem(tmpECParamsDER, PR_TRUE);
                 PORT_FreeArena(tmpECParams->arena, PR_TRUE);
                 rv = SECOID_Shutdown();
                 CHECKERROR(rv, __LINE__);
             } else {
                 setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
-                *ecKey = eckey_from_filedata(&asymk->key.buf);
+                *ecKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf);
             }
             break;
 #endif
         default:
             return SECFailure;
     }
     return SECSuccess;
 }
@@ -3065,43 +3057,43 @@ get_params(PLArenaPool *arena, bltestPar
             params->asymk.cipherParams.rsa.maskHashAlg =
                 mode_str_to_hash_alg(&tempIO.buf);
         /* fall through */
         case bltestRSA:
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j);
             load_file_data(arena, &params->asymk.key, filename,
                            bltestBase64Encoded);
             params->asymk.privKey =
-                (void *)rsakey_from_filedata(&params->asymk.key.buf);
+                (void *)rsakey_from_filedata(arena, &params->asymk.key.buf);
             break;
         case bltestDSA:
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j);
             load_file_data(arena, &params->asymk.key, filename, bltestBase64Encoded);
             params->asymk.privKey =
-                (void *)dsakey_from_filedata(&params->asymk.key.buf);
+                (void *)dsakey_from_filedata(arena, &params->asymk.key.buf);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "pqg", j);
             load_file_data(arena, &params->asymk.cipherParams.dsa.pqgdata, filename,
                            bltestBase64Encoded);
             params->asymk.cipherParams.dsa.pqg =
-                pqg_from_filedata(&params->asymk.cipherParams.dsa.pqgdata.buf);
+                pqg_from_filedata(arena, &params->asymk.cipherParams.dsa.pqgdata.buf);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "keyseed", j);
             load_file_data(arena, &params->asymk.cipherParams.dsa.keyseed, filename,
                            bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j);
             load_file_data(arena, &params->asymk.cipherParams.dsa.sigseed, filename,
                            bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j);
             load_file_data(arena, &params->asymk.sig, filename, bltestBase64Encoded);
             break;
 #ifndef NSS_DISABLE_ECC
         case bltestECDSA:
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j);
             load_file_data(arena, &params->asymk.key, filename, bltestBase64Encoded);
             params->asymk.privKey =
-                (void *)eckey_from_filedata(&params->asymk.key.buf);
+                (void *)eckey_from_filedata(arena, &params->asymk.key.buf);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j);
             load_file_data(arena, &params->asymk.cipherParams.ecdsa.sigseed,
                            filename, bltestBase64Encoded);
             sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext", j);
             load_file_data(arena, &params->asymk.sig, filename, bltestBase64Encoded);
             break;
 #endif
         case bltestMD2:
@@ -3162,26 +3154,29 @@ verify_self_test(bltestIO *result, bltes
                 printf("Decryption self-test for %s failed!\n", modestr);
             }
         }
     }
     return equal ? SECSuccess : SECFailure;
 }
 
 static SECStatus
-ReadFileToItem(SECItem *dst, const char *filename)
+ReadFileToItem(PLArenaPool *arena, SECItem *dst, const char *filename)
 {
+    SECItem tmp = {siBuffer, NULL, 0};
     PRFileDesc *file;
     SECStatus rv;
 
     file = PR_Open(filename, PR_RDONLY, 00660);
     if (!file) {
         return SECFailure;
     }
-    rv = SECU_FileToItem(dst, file);
+    rv = SECU_FileToItem(&tmp, file);
+    rv |= SECITEM_CopyItem(arena, dst, &tmp);
+    SECITEM_FreeItem(&tmp, PR_FALSE);
     PR_Close(file);
     return rv;
 }
 
 static SECStatus
 blapi_selftest(bltestCipherMode *modes, int numModes, int inoff, int outoff,
                PRBool encrypt, PRBool decrypt)
 {
@@ -3210,17 +3205,17 @@ blapi_selftest(bltestCipherMode *modes, 
             fprintf(stderr, "%s: Skipping invalid mode.\n", progName);
             continue;
         }
         modestr = mode_strings[mode];
         cipherInfo.mode = mode;
         params = &cipherInfo.params;
         /* get the number of tests in the directory */
         sprintf(filename, "%s/tests/%s/%s", testdir, modestr, "numtests");
-        if (ReadFileToItem(&item, filename) != SECSuccess) {
+        if (ReadFileToItem(arena, &item, filename) != SECSuccess) {
             fprintf(stderr, "%s: Cannot read file %s.\n", progName, filename);
             rv = SECFailure;
             continue;
         }
         /* loop over the tests in the directory */
         numtests = 0;
         for (j = 0; j < item.len; j++) {
             if (!isdigit(item.data[j])) {
@@ -3288,46 +3283,47 @@ blapi_selftest(bltestCipherMode *modes, 
             misalignBuffer(arena, &cipherInfo.output, outoff);
             srv = SECSuccess;
             srv |= cipherDoOp(&cipherInfo);
             rv |= cipherFinish(&cipherInfo);
             rv |= verify_self_test(&cipherInfo.output,
                                    &pt, mode, PR_FALSE, srv);
         }
     }
+    PORT_FreeArena(arena, PR_FALSE);
     return rv;
 }
 
 SECStatus
 dump_file(bltestCipherMode mode, char *filename)
 {
     bltestIO keydata;
     PLArenaPool *arena = NULL;
     arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
     if (mode == bltestRSA || mode == bltestRSA_PSS || mode == bltestRSA_OAEP) {
         RSAPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
-        key = rsakey_from_filedata(&keydata.buf);
+        key = rsakey_from_filedata(arena, &keydata.buf);
         dump_rsakey(key);
     } else if (mode == bltestDSA) {
 #if 0
     PQGParams *pqg;
     get_file_data(filename, &item, PR_TRUE);
     pqg = pqg_from_filedata(&item);
     dump_pqg(pqg);
 #endif
         DSAPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
-        key = dsakey_from_filedata(&keydata.buf);
+        key = dsakey_from_filedata(arena, &keydata.buf);
         dump_dsakey(key);
 #ifndef NSS_DISABLE_ECC
     } else if (mode == bltestECDSA) {
         ECPrivateKey *key;
         load_file_data(arena, &keydata, filename, bltestBase64Encoded);
-        key = eckey_from_filedata(&keydata.buf);
+        key = eckey_from_filedata(arena, &keydata.buf);
         dump_eckey(key);
 #endif
     }
     PORT_FreeArena(arena, PR_FALSE);
     return SECFailure;
 }
 
 void
--- a/security/nss/cmd/certcgi/certcgi.c
+++ b/security/nss/cmd/certcgi/certcgi.c
@@ -914,17 +914,23 @@ AddPrivKeyUsagePeriod(void *extHandle,
     if (!arena) {
         error_allocate();
     }
     pkup = PORT_ArenaZNew(arena, CERTPrivKeyUsagePeriod);
     if (pkup == NULL) {
         error_allocate();
     }
     notBeforeStr = (char *)PORT_Alloc(16);
+    if (notBeforeStr == NULL) {
+        error_allocate();
+    }
     notAfterStr = (char *)PORT_Alloc(16);
+    if (notAfterStr == NULL) {
+        error_allocate();
+    }
     *notBeforeStr = '\0';
     *notAfterStr = '\0';
     pkup->arena = arena;
     pkup->notBefore.len = 0;
     pkup->notBefore.data = NULL;
     pkup->notAfter.len = 0;
     pkup->notAfter.data = NULL;
     if (find_field_bool(data, "privKeyUsagePeriod-radio-notBefore", PR_TRUE) ||
@@ -1028,25 +1034,19 @@ AddPrivKeyUsagePeriod(void *extHandle,
 
     rv = EncodeAndAddExtensionValue(arena, extHandle, pkup,
                                     find_field_bool(data,
                                                     "privKeyUsagePeriod-crit",
                                                     PR_TRUE),
                                     SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD,
                                     (EXTEN_VALUE_ENCODER)
                                         CERT_EncodePrivateKeyUsagePeriod);
-    if (arena) {
-        PORT_FreeArena(arena, PR_FALSE);
-    }
-    if (notBeforeStr != NULL) {
-        PORT_Free(notBeforeStr);
-    }
-    if (notAfterStr != NULL) {
-        PORT_Free(notAfterStr);
-    }
+    PORT_FreeArena(arena, PR_FALSE);
+    PORT_Free(notBeforeStr);
+    PORT_Free(notAfterStr);
     return (rv);
 }
 
 static SECStatus
 AddBasicConstraint(void *extHandle,
                    Pair *data)
 {
     CERTBasicConstraints basicConstraint;
--- a/security/nss/cmd/certutil/certext.c
+++ b/security/nss/cmd/certutil/certext.c
@@ -267,24 +267,25 @@ GetYesNo(char *prompt)
  * nextPos is set to the token after found comma separator or to NULL.
  * NULL in nextPos should be used as indication of the last parsed token.
  * A special value "critical" can be parsed out from the supplied sting.*/
 
 static SECStatus
 parseNextCmdInput(const char *const *valueArray, int *value, char **nextPos,
                   PRBool *critical)
 {
-    char *thisPos = *nextPos;
+    char *thisPos;
     int keyLen = 0;
     int arrIndex = 0;
 
     if (!valueArray || !value || !nextPos || !critical) {
         PORT_SetError(SEC_ERROR_INVALID_ARGS);
         return SECFailure;
     }
+    thisPos = *nextPos;
     while (1) {
         if ((*nextPos = strchr(thisPos, ',')) == NULL) {
             keyLen = strlen(thisPos);
         } else {
             keyLen = *nextPos - thisPos;
             *nextPos += 1;
         }
         /* if critical keyword is found, go for another loop,
@@ -911,17 +912,17 @@ AddDNSSubjectAlt(PLArenaPool *arena, CER
 static SECStatus
 AddGeneralSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp,
                      const char *altNames)
 {
     return AddSubjectAltNames(arena, existingListp, altNames, 0);
 }
 
 static SECStatus
-AddBasicConstraint(void *extHandle)
+AddBasicConstraint(PLArenaPool *arena, void *extHandle)
 {
     CERTBasicConstraints basicConstraint;
     SECStatus rv;
     char buffer[10];
     PRBool yesNoAns;
 
     do {
         basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
@@ -933,17 +934,17 @@ AddBasicConstraint(void *extHandle)
                                      buffer, sizeof(buffer)) == SECFailure) {
             GEN_BREAK(SECFailure);
         }
         if (PORT_Strlen(buffer) > 0)
             basicConstraint.pathLenConstraint = PORT_Atoi(buffer);
 
         yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
 
-        rv = SECU_EncodeAndAddExtensionValue(NULL, extHandle,
+        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle,
                                              &basicConstraint, yesNoAns, SEC_OID_X509_BASIC_CONSTRAINTS,
                                              (EXTEN_EXT_VALUE_ENCODER)CERT_EncodeBasicConstraintValue);
     } while (0);
 
     return (rv);
 }
 
 static SECStatus
@@ -1977,20 +1978,26 @@ parseNextGenericExt(const char *nextExte
 
     return SECSuccess;
 }
 
 SECStatus
 AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
               certutilExtnList extList, const char *extGeneric)
 {
+    PLArenaPool *arena;
     SECStatus rv = SECSuccess;
     char *errstring = NULL;
     const char *nextExtension = NULL;
 
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if (arena == NULL) {
+        return SECFailure;
+    }
+
     do {
         /* Add key usage extension */
         if (extList[ext_keyUsage].activated) {
             rv = AddKeyUsage(extHandle, extList[ext_keyUsage].arg);
             if (rv) {
                 errstring = "KeyUsage";
                 break;
             }
@@ -2002,17 +2009,17 @@ AddExtensions(void *extHandle, const cha
             if (rv) {
                 errstring = "ExtendedKeyUsage";
                 break;
             }
         }
 
         /* Add basic constraint extension */
         if (extList[ext_basicConstraint].activated) {
-            rv = AddBasicConstraint(extHandle);
+            rv = AddBasicConstraint(arena, extHandle);
             if (rv) {
                 errstring = "BasicConstraint";
                 break;
             }
         }
 
         /* Add name constraints extension */
         if (extList[ext_nameConstraints].activated) {
@@ -2093,26 +2100,19 @@ AddExtensions(void *extHandle, const cha
             rv = AddInhibitAnyPolicy(extHandle);
             if (rv) {
                 errstring = "InhibitAnyPolicy";
                 break;
             }
         }
 
         if (emailAddrs || dnsNames || extList[ext_subjectAltName].activated) {
-            PLArenaPool *arena;
             CERTGeneralName *namelist = NULL;
             SECItem item = { 0, NULL, 0 };
 
-            arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-            if (arena == NULL) {
-                rv = SECFailure;
-                break;
-            }
-
             rv = SECSuccess;
 
             if (emailAddrs) {
                 rv |= AddEmailSubjectAlt(arena, &namelist, emailAddrs);
             }
 
             if (dnsNames) {
                 rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames);
@@ -2126,24 +2126,25 @@ AddExtensions(void *extHandle, const cha
             if (rv == SECSuccess) {
                 rv = CERT_EncodeAltNameExtension(arena, namelist, &item);
                 if (rv == SECSuccess) {
                     rv = CERT_AddExtension(extHandle,
                                            SEC_OID_X509_SUBJECT_ALT_NAME,
                                            &item, PR_FALSE, PR_TRUE);
                 }
             }
-            PORT_FreeArena(arena, PR_FALSE);
             if (rv) {
                 errstring = "SubjectAltName";
                 break;
             }
         }
     } while (0);
 
+    PORT_FreeArena(arena, PR_FALSE);
+
     if (rv != SECSuccess) {
         SECU_PrintError(progName, "Problem creating %s extension", errstring);
     }
 
     nextExtension = extGeneric;
     while (nextExtension && *nextExtension) {
         SECItem oid_item, value;
         PRBool isCritical;
@@ -2193,20 +2194,20 @@ AddExtensions(void *extHandle, const cha
             SECU_PrintError(progName, "unable to read file %s",
                             zeroTerminatedFilename);
         }
         PL_strfree(zeroTerminatedFilename);
         if (rv != SECSuccess) {
             break;
         }
         rv = CERT_AddExtensionByOID(extHandle, &oid_item, &value, isCritical,
-                                    PR_FALSE /*copyData*/);
+                                    PR_TRUE /*copyData*/);
+        SECITEM_FreeItem(&value, PR_FALSE);
+        SECITEM_FreeItem(&oid_item, PR_FALSE);
         if (rv != SECSuccess) {
-            SECITEM_FreeItem(&oid_item, PR_FALSE);
-            SECITEM_FreeItem(&value, PR_FALSE);
             SECU_PrintError(progName, "failed to add extension %s", nextExtension);
             break;
         }
         nextExtension = next;
     }
 
     return rv;
 }
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -214,21 +214,24 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
     if (!arena) {
         SECU_PrintError(progName, "out of memory");
         return SECFailure;
     }
 
     extHandle = CERT_StartCertificateRequestAttributes(cr);
     if (extHandle == NULL) {
         PORT_FreeArena(arena, PR_FALSE);
+        CERT_DestroyCertificateRequest(cr);
         return SECFailure;
     }
     if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric) !=
         SECSuccess) {
         PORT_FreeArena(arena, PR_FALSE);
+        CERT_FinishExtensions(extHandle);
+        CERT_DestroyCertificateRequest(cr);
         return SECFailure;
     }
     CERT_FinishExtensions(extHandle);
     CERT_FinishCertificateRequestAttributes(cr);
 
     /* Der encode the request */
     encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
                                   SEC_ASN1_GET(CERT_CertificateRequestTemplate));
@@ -384,16 +387,17 @@ ChangeTrustAttributes(CERTCertDBHandle *
             rv = CERT_ChangeCertTrust(handle, cert, trust);
         }
         if (rv != SECSuccess) {
             SECU_PrintError(progName, "unable to modify trust attributes");
             return SECFailure;
         }
     }
     CERT_DestroyCertificate(cert);
+    PORT_Free(trust);
 
     return SECSuccess;
 }
 
 static SECStatus
 DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii)
 {
     CERTCertificate *the_cert;
@@ -1965,17 +1969,17 @@ CreateCert(
     const char *dnsNames,
     PRBool ascii,
     PRBool selfsign,
     certutilExtnList extnList,
     const char *extGeneric,
     int certVersion,
     SECItem *certDER)
 {
-    void *extHandle;
+    void *extHandle = NULL;
     CERTCertificate *subjectCert = NULL;
     CERTCertificateRequest *certReq = NULL;
     SECStatus rv = SECSuccess;
     CERTCertExtension **CRexts;
 
     do {
         /* Create a certrequest object from the input cert request der */
         certReq = GetCertRequest(certReqDER);
@@ -2009,16 +2013,17 @@ CreateCert(
             if (rv != SECSuccess)
                 break;
             rv = CERT_MergeExtensions(extHandle, CRexts);
             if (rv != SECSuccess)
                 break;
         }
 
         CERT_FinishExtensions(extHandle);
+        extHandle = NULL;
 
         /* self-signing a cert request, find the private key */
         if (selfsign && *selfsignprivkey == NULL) {
             *selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg);
             if (!*selfsignprivkey) {
                 fprintf(stderr, "Failed to locate private key.\n");
                 rv = SECFailure;
                 break;
@@ -2049,16 +2054,19 @@ CreateCert(
                     PR_smprintf_free(wrapped);
                 }
                 PORT_Free(asciiDER);
             }
         } else {
             rv = SECITEM_CopyItem(NULL, certDER, &subjectCert->derCert);
         }
     } while (0);
+    if (extHandle) {
+        CERT_FinishExtensions(extHandle);
+    }
     CERT_DestroyCertificateRequest(certReq);
     CERT_DestroyCertificate(subjectCert);
     if (rv != SECSuccess) {
         PRErrorCode perr = PR_GetError();
         fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
                 SECU_Strerror(perr));
     }
     return (rv);
@@ -3149,16 +3157,17 @@ certutil_main(int argc, char **argv, PRB
                 SECU_PrintError(progName, "malformed extension OID %s",
                                 oid_str);
                 goto shutdown;
             }
             rv = ListCerts(certHandle, name, email, slot,
                            PR_TRUE /*binary*/, PR_FALSE /*ascii*/,
                            &oid_item,
                            outFile, &pwdata);
+            SECITEM_FreeItem(&oid_item, PR_FALSE);
         } else {
             rv = ListCerts(certHandle, name, email, slot,
                            certutil.options[opt_BinaryDER].activated,
                            certutil.options[opt_ASCIIForIO].activated,
                            NULL, outFile, &pwdata);
         }
         goto shutdown;
     }
--- a/security/nss/cmd/crlutil/crlgen.c
+++ b/security/nss/cmd/crlutil/crlgen.c
@@ -62,26 +62,33 @@ crlgen_FindEntry(CRLGENGeneratorData *cr
 }
 
 /* Removes CRLGENEntryData from hashtable according to certId
  * - certId : cert serial number*/
 static SECStatus
 crlgen_RmEntry(CRLGENGeneratorData *crlGenData, SECItem *certId)
 {
     CRLGENEntryData *data = NULL;
+    SECStatus rv = SECSuccess;
 
-    if (!crlGenData->entryDataHashTable)
+    if (!crlGenData->entryDataHashTable) {
         return SECSuccess;
+    }
+
     data = crlgen_FindEntry(crlGenData, certId);
-    if (!data)
+    if (!data) {
         return SECSuccess;
-    if (PL_HashTableRemove(crlGenData->entryDataHashTable, certId))
-        return SECSuccess;
+    }
+
+    if (!PL_HashTableRemove(crlGenData->entryDataHashTable, certId)) {
+        rv = SECFailure;
+    }
+
     destroyEntryData(data);
-    return SECFailure;
+    return rv;
 }
 
 /* Stores CRLGENEntryData in hashtable according to certId
  * - certId : cert serial number*/
 static CRLGENEntryData *
 crlgen_PlaceAnEntry(CRLGENGeneratorData *crlGenData,
                     CERTCrlEntry *entry, SECItem *certId)
 {
@@ -478,17 +485,16 @@ loser:
 /* Creates and adds CRLNumber extension to extension handle.
  * Since, this is CRL extension, extension handle is the one
  * related to CRL extensions */
 static SECStatus
 crlgen_AddCrlNumber(CRLGENGeneratorData *crlGenData, const char **dataArr)
 {
     PLArenaPool *arena = NULL;
     SECItem encodedItem;
-    void *extHandle = crlGenData->crlExtHandle;
     void *dummy;
     SECStatus rv = SECFailure;
     int code = 0;
 
     PORT_Assert(dataArr && crlGenData);
     if (!crlGenData || !dataArr) {
         goto loser;
     }
@@ -512,17 +518,18 @@ crlgen_AddCrlNumber(CRLGENGeneratorData 
     }
 
     dummy = SEC_ASN1EncodeInteger(arena, &encodedItem, code);
     if (!dummy) {
         rv = SECFailure;
         goto loser;
     }
 
-    rv = CERT_AddExtension(extHandle, SEC_OID_X509_CRL_NUMBER, &encodedItem,
+    rv = CERT_AddExtension(crlGenData->crlExtHandle, SEC_OID_X509_CRL_NUMBER,
+                           &encodedItem,
                            (*dataArr[1] == '1') ? PR_TRUE : PR_FALSE,
                            PR_TRUE);
 
 loser:
     if (arena)
         PORT_FreeArena(arena, PR_FALSE);
     return rv;
 }
--- a/security/nss/cmd/crlutil/crlutil.c
+++ b/security/nss/cmd/crlutil/crlutil.c
@@ -278,16 +278,17 @@ ImportCRL(CERTCertDBHandle *certHandle, 
             SECU_PrintError(progName, "unable to import CRL");
     } else {
         SEC_DestroyCrl(crl);
     }
 loser:
     if (slot) {
         PK11_FreeSlot(slot);
     }
+    SECITEM_FreeItem(&crlDER, PR_FALSE);
     return (rv);
 }
 
 SECStatus
 DumpCRL(PRFileDesc *inFile)
 {
     int rv;
     PLArenaPool *arena = NULL;
@@ -526,16 +527,18 @@ CreateNewCrl(PLArenaPool *arena, CERTCer
         goto loser;
     }
 
     /* set fields */
     signCrl->arena = arena;
     signCrl->dbhandle = certHandle;
     signCrl->crl.arena = arena;
 
+    PORT_ArenaUnmark(arena, mark);
+
     return signCrl;
 
 loser:
     PORT_ArenaRelease(arena, mark);
     return NULL;
 }
 
 static SECStatus
@@ -856,17 +859,17 @@ main(int argc, char **argv)
     int modifyCRL;
     int listCRL;
     int importCRL;
     int showFileCRL;
     int deleteCRL;
     int rv;
     char *nickName;
     char *url;
-    char *dbPrefix = "";
+    char *dbPrefix = PORT_Strdup("");
     char *alg = NULL;
     char *outFile = NULL;
     char *slotName = NULL;
     int ascii = 0;
     int crlType;
     PLOptState *optstate;
     PLOptStatus status;
     SECStatus secstatus;
@@ -933,103 +936,103 @@ main(int argc, char **argv)
                 break;
 
             case 'C':
             case 'L':
                 listCRL = 1;
                 break;
 
             case 'P':
-                dbPrefix = strdup(optstate->value);
+                PORT_Free(dbPrefix);
+                dbPrefix = PORT_Strdup(optstate->value);
                 break;
 
             case 'Z':
-                alg = strdup(optstate->value);
+                alg = PORT_Strdup(optstate->value);
                 break;
 
             case 'a':
                 ascii = 1;
                 break;
 
             case 'c':
                 inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
                 if (!inCrlInitFile) {
                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
                                progName, optstate->value);
-                    PL_DestroyOptState(optstate);
-                    return -1;
+                    rv = SECFailure;
+                    goto loser;
                 }
                 break;
 
             case 'd':
                 SECU_ConfigDirectory(optstate->value);
                 break;
 
             case 'f':
                 pwdata.source = PW_FROMFILE;
-                pwdata.data = strdup(optstate->value);
+                pwdata.data = PORT_Strdup(optstate->value);
                 break;
 
             case 'h':
-                slotName = strdup(optstate->value);
+                slotName = PORT_Strdup(optstate->value);
                 break;
 
             case 'i':
                 inFile = PR_Open(optstate->value, PR_RDONLY, 0);
                 if (!inFile) {
                     PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
                                progName, optstate->value);
-                    PL_DestroyOptState(optstate);
-                    return -1;
+                    rv = SECFailure;
+                    goto loser;
                 }
                 break;
 
             case 'n':
-                nickName = strdup(optstate->value);
+                nickName = PORT_Strdup(optstate->value);
                 break;
 
             case 'o':
-                outFile = strdup(optstate->value);
+                outFile = PORT_Strdup(optstate->value);
                 break;
 
             case 'p':
                 decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
                 break;
 
             case 'r': {
                 const char *str = optstate->value;
                 if (str && atoi(str) > 0)
                     iterations = atoi(str);
             } break;
 
             case 't': {
                 crlType = atoi(optstate->value);
                 if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
                     PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
-                    PL_DestroyOptState(optstate);
-                    return -1;
+                    rv = SECFailure;
+                    goto loser;
                 }
                 break;
 
                 case 'q':
                     quiet = PR_TRUE;
                     break;
 
                 case 'w':
                     pwdata.source = PW_PLAINTEXT;
-                    pwdata.data = strdup(optstate->value);
+                    pwdata.data = PORT_Strdup(optstate->value);
                     break;
 
                 case 'u':
-                    url = strdup(optstate->value);
+                    url = PORT_Strdup(optstate->value);
                     break;
             }
         }
     }
-    PL_DestroyOptState(optstate);
 
     if (deleteCRL && !nickName)
         Usage(progName);
     if (importCRL && !inFile)
         Usage(progName);
     if (showFileCRL && !inFile)
         Usage(progName);
     if ((generateCRL && !nickName) ||
@@ -1049,28 +1052,28 @@ main(int argc, char **argv)
 
     if (showFileCRL) {
         NSS_NoDB_Init(NULL);
     } else {
         secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
                                    "secmod.db", readonly ? NSS_INIT_READONLY : 0);
         if (secstatus != SECSuccess) {
             SECU_PrintPRandOSError(progName);
-            return -1;
+            rv = SECFailure;
+            goto loser;
         }
     }
 
     SECU_RegisterDynamicOids();
 
     certHandle = CERT_GetDefaultCertDB();
     if (certHandle == NULL) {
         SECU_PrintError(progName, "unable to open the cert db");
-        /*ignoring return value of NSS_Shutdown() as code returns -1*/
-        (void)NSS_Shutdown();
-        return (-1);
+        rv = SECFailure;
+        goto loser;
     }
 
     CRLGEN_InitCrlGenParserLock();
 
     for (i = 0; i < iterations; i++) {
         /* Read in the private key info */
         if (deleteCRL)
             DeleteCRL(certHandle, nickName, crlType);
@@ -1105,14 +1108,41 @@ main(int argc, char **argv)
             /* list CRLs */
             ListCRLNames(certHandle, crlType, PR_FALSE);
         }
 #endif
     }
 
     CRLGEN_DestroyCrlGenParserLock();
 
+loser:
+    PL_DestroyOptState(optstate);
+
+    if (inFile) {
+        PR_Close(inFile);
+    }
+    if (alg) {
+        PORT_Free(alg);
+    }
+    if (slotName) {
+        PORT_Free(slotName);
+    }
+    if (nickName) {
+        PORT_Free(nickName);
+    }
+    if