merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 08 Feb 2017 11:30:00 +0100
changeset 341333 3a95aa4246653a7863914ffec032897d13359fb0
parent 341332 64b970234605f682457ada10cd523608861d6864 (current diff)
parent 341273 de301f4f1519a3444ed227e2ffd23ca34d02ca3b (diff)
child 341334 c5b88e4e70f48955661dc7900b43a95c3c785836
child 341425 5b516731820c841dd85447c2155bd751ec9f7de6
child 341518 aee275b6f34d35a72be2bc908c3815aa88b08e22
push id86684
push usercbook@mozilla.com
push dateWed, 08 Feb 2017 10:31:03 +0000
treeherdermozilla-inbound@c5b88e4e70f4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.0a1
first release with
nightly linux32
3a95aa424665 / 54.0a1 / 20170208110248 / files
nightly linux64
3a95aa424665 / 54.0a1 / 20170208110248 / files
nightly mac
3a95aa424665 / 54.0a1 / 20170208030203 / files
nightly win32
3a95aa424665 / 54.0a1 / 20170208030203 / files
nightly win64
3a95aa424665 / 54.0a1 / 20170208030203 / 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
mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java
--- a/.eslintignore
+++ b/.eslintignore
@@ -19,17 +19,16 @@ editor/**
 embedding/**
 extensions/**
 gfx/**
 gradle/**
 hal/**
 image/**
 intl/**
 ipc/**
-js/**
 layout/**
 media/**
 memory/**
 mfbt/**
 modules/**
 mozglue/**
 netwerk/**
 nsprpub/**
@@ -149,16 +148,27 @@ devtools/client/debugger/test/mochitest/
 devtools/client/debugger/test/mochitest/code_math.min.js
 devtools/client/debugger/test/mochitest/code_math_bogus_map.js
 devtools/client/debugger/test/mochitest/code_ugly*
 devtools/client/debugger/test/mochitest/code_worker-source-map.js
 devtools/client/framework/test/code_ugly*
 devtools/server/tests/unit/babel_and_browserify_script_with_source_map.js
 devtools/server/tests/unit/setBreakpoint*
 
+# Exclude everything but self-hosted JS
+js/ductwork/**
+js/examples/**
+js/ipc/**
+js/public/**
+js/xpconnect/**
+js/src/devtools/**
+js/src/octane/**
+js/src/jit-test/**
+js/src/tests/**
+
 # mobile/android/ exclusions
 mobile/android/tests/
 
 # Uses `#filter substitution`
 mobile/android/b2gdroid/app/b2gdroid.js
 mobile/android/app/mobile.js
 mobile/android/chrome/content/healthreport-prefs.js
 
--- a/accessible/windows/msaa/DocAccessibleWrap.cpp
+++ b/accessible/windows/msaa/DocAccessibleWrap.cpp
@@ -122,16 +122,20 @@ DocAccessibleWrap::GetNativeWindow() con
     DocAccessibleChild* ipcDoc = IPCDoc();
     HWND hWnd = ipcDoc->GetEmulatedWindowHandle();
     if (hWnd) {
       return hWnd;
     }
 
     auto tab = static_cast<dom::TabChild*>(ipcDoc->Manager());
     MOZ_ASSERT(tab);
+    if (!tab) {
+      return nullptr;
+    }
+
     return reinterpret_cast<HWND>(tab->GetNativeWindowHandle());
   } else if (mHWND) {
     return mHWND;
   }
   return DocAccessible::GetNativeWindow();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/browser/extensions/formautofill/content/FormAutofillContent.js
+++ b/browser/extensions/formautofill/content/FormAutofillContent.js
@@ -286,28 +286,28 @@ AutofillProfileAutoCompleteSearch.protot
   /**
    * Get the input's information from FormAutofillContent's cache.
    *
    * @returns {Object}
    *          Target input's information that cached in FormAutofillContent.
    */
   getInputDetails() {
     // TODO: Maybe we'll need to wait for cache ready if detail is empty.
-    return FormAutofillContent.getInputDetails(formFillController.getFocusedInput());
+    return FormAutofillContent.getInputDetails(formFillController.focusedInput);
   },
 
   /**
    * Get the form's information from FormAutofillContent's cache.
    *
    * @returns {Array<Object>}
    *          Array of the inputs' information for the target form.
    */
   getFormDetails() {
     // TODO: Maybe we'll need to wait for cache ready if details is empty.
-    return FormAutofillContent.getFormDetails(formFillController.getFocusedInput());
+    return FormAutofillContent.getFormDetails(formFillController.focusedInput);
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AutofillProfileAutoCompleteSearch]);
 
 let ProfileAutocomplete = {
   _registered: false,
   _factory: null,
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -658,17 +658,17 @@ nsObjectLoadingContent::nsObjectLoadingC
   : mType(eType_Loading)
   , mFallbackType(eFallbackAlternate)
   , mRunID(0)
   , mHasRunID(false)
   , mChannelLoaded(false)
   , mInstantiating(false)
   , mNetworkCreated(true)
   , mActivated(false)
-  , mContentBlockingDisabled(false)
+  , mContentBlockingEnabled(false)
   , mIsStopping(false)
   , mIsLoading(false)
   , mScriptRequested(false)
   , mRewrittenYoutubeEmbed(false)
   , mPreferFallback(false)
   , mPreferFallbackKnown(false) {}
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
@@ -1053,36 +1053,36 @@ nsObjectLoadingContent::OnStartRequest(n
   NS_ASSERTION(!mChannelLoaded, "mChannelLoaded set already?");
   NS_ASSERTION(!mFinalListener, "mFinalListener exists already?");
 
   mChannelLoaded = true;
 
   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
   NS_ASSERTION(chan, "Why is our request not a channel?");
 
-  nsresult status;
+  nsresult status = NS_OK;
   bool success = IsSuccessfulRequest(aRequest, &status);
 
   if (status == NS_ERROR_BLOCKED_URI) {
     nsCOMPtr<nsIConsoleService> console(
       do_GetService("@mozilla.org/consoleservice;1"));
     if (console) {
       nsCOMPtr<nsIURI> uri;
       chan->GetURI(getter_AddRefs(uri));
       nsString message = NS_LITERAL_STRING("Blocking ") +
         NS_ConvertASCIItoUTF16(uri->GetSpecOrDefault().get()) +
         NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
       console->LogStringMessage(message.get());
     }
     Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
+    mContentBlockingEnabled = true;
     return NS_ERROR_FAILURE;
   } else if (status == NS_ERROR_TRACKING_URI) {
+    mContentBlockingEnabled = true;
     return NS_ERROR_FAILURE;
-  } else {
-    mContentBlockingDisabled = true;
   }
 
   if (!success) {
     LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
     // If the request fails, we still call LoadObject() to handle fallback
     // content and notifying of failure. (mChannelLoaded && !mChannel) indicates
     // the bad state.
     mChannel = nullptr;
@@ -3219,42 +3219,53 @@ nsObjectLoadingContent::GetRunID(SystemC
     return 0;
   }
   return mRunID;
 }
 
 static bool sPrefsInitialized;
 static uint32_t sSessionTimeoutMinutes;
 static uint32_t sPersistentTimeoutDays;
+static bool sBlockURIs;
+
+static void initializeObjectLoadingContentPrefs()
+{
+  if (!sPrefsInitialized) {
+    Preferences::AddUintVarCache(&sSessionTimeoutMinutes,
+                                 "plugin.sessionPermissionNow.intervalInMinutes", 60);
+    Preferences::AddUintVarCache(&sPersistentTimeoutDays,
+                                 "plugin.persistentPermissionAlways.intervalInDays", 90);
+
+    Preferences::AddBoolVarCache(&sBlockURIs, kPrefBlockURIs, false);
+    sPrefsInitialized = true;
+  }
+}
 
 bool
 nsObjectLoadingContent::ShouldBlockContent()
 {
-  if (mContentBlockingDisabled || !mURI)
-    return false;
-
-  if (!IsFlashMIME(mContentType) || !Preferences::GetBool(kPrefBlockURIs)) {
-    mContentBlockingDisabled = true;
-    return false;
+ 
+  if (!sPrefsInitialized) {
+    initializeObjectLoadingContentPrefs();
   }
 
-  return true;
+  if (mContentBlockingEnabled && mURI && IsFlashMIME(mContentType) && sBlockURIs ) {
+    return true;
+  }
+
+  return false;
 }
 
 bool
 nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType)
 {
   nsresult rv;
 
   if (!sPrefsInitialized) {
-    Preferences::AddUintVarCache(&sSessionTimeoutMinutes,
-                                 "plugin.sessionPermissionNow.intervalInMinutes", 60);
-    Preferences::AddUintVarCache(&sPersistentTimeoutDays,
-                                 "plugin.persistentPermissionAlways.intervalInDays", 90);
-    sPrefsInitialized = true;
+    initializeObjectLoadingContentPrefs();
   }
 
   if (BrowserTabsRemoteAutostart()) {
     bool shouldLoadInParent = nsPluginHost::ShouldLoadTypeInParent(mContentType);
     bool inParent = XRE_IsParentProcess();
 
     if (shouldLoadInParent != inParent) {
       // Plugins need to be locked to either the parent process or the content
--- a/dom/base/nsObjectLoadingContent.h
+++ b/dom/base/nsObjectLoadingContent.h
@@ -672,17 +672,17 @@ class nsObjectLoadingContent : public ns
     // it may lose the flag.
     bool                        mNetworkCreated : 1;
 
     // Used to keep track of whether or not a plugin has been explicitly
     // activated by PlayPlugin(). (see ShouldPlay())
     bool                        mActivated : 1;
 
     // Whether content blocking is enabled or not for this object.
-    bool                        mContentBlockingDisabled : 1;
+    bool                        mContentBlockingEnabled : 1;
 
     // Protects DoStopPlugin from reentry (bug 724781).
     bool                        mIsStopping : 1;
 
     // Protects LoadObject from re-entry
     bool                        mIsLoading : 1;
 
     // For plugin stand-in types (click-to-play) tracks
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -561,17 +561,19 @@ private:
 class AdjustedTarget
 {
 public:
   typedef CanvasRenderingContext2D::ContextState ContextState;
 
   explicit AdjustedTarget(CanvasRenderingContext2D* aCtx,
                           const gfx::Rect *aBounds = nullptr)
   {
-    mTarget = aCtx->mTarget;
+    // There are operations that can invalidate aCtx->mTarget along the way,
+    // so don't cache the pointer to it too soon.
+    mTarget = nullptr;
 
     // All rects in this function are in the device space of ctx->mTarget.
 
     // In order to keep our temporary surfaces as small as possible, we first
     // calculate what their maximum required bounds would need to be if we
     // were to fill the whole canvas. Everything outside those bounds we don't
     // need to render.
     gfx::Rect r(0, 0, aCtx->mWidth, aCtx->mHeight);
@@ -590,38 +592,44 @@ public:
 
     gfx::IntPoint offsetToFinalDT;
 
     // First set up the shadow draw target, because the shadow goes outside.
     // It applies to the post-filter results, if both a filter and a shadow
     // are used.
     if (aCtx->NeedToDrawShadow()) {
       mShadowTarget = MakeUnique<AdjustedTargetForShadow>(
-        aCtx, mTarget, boundsAfterFilter, op);
+        aCtx, aCtx->mTarget, boundsAfterFilter, op);
       mTarget = mShadowTarget->DT();
       offsetToFinalDT = mShadowTarget->OffsetToFinalDT();
 
       // If we also have a filter, the filter needs to be drawn with OP_OVER
       // because shadow drawing already applies op on the result.
       op = gfx::CompositionOp::OP_OVER;
     }
 
     // Now set up the filter draw target.
     if (aCtx->NeedToApplyFilter()) {
       bounds.RoundOut();
 
+      if (!mTarget) {
+        mTarget = aCtx->mTarget;
+      }
       gfx::IntRect intBounds;
       if (!bounds.ToIntRect(&intBounds)) {
         return;
       }
       mFilterTarget = MakeUnique<AdjustedTargetForFilter>(
         aCtx, mTarget, offsetToFinalDT, intBounds,
         gfx::RoundedToInt(boundsAfterFilter), op);
       mTarget = mFilterTarget->DT();
     }
+    if (!mTarget) {
+      mTarget = aCtx->mTarget;
+    }
   }
 
   ~AdjustedTarget()
   {
     // The order in which the targets are finalized is important.
     // Filters are inside, any shadow applies to the post-filter results.
     mFilterTarget.reset();
     mShadowTarget.reset();
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -436,17 +436,17 @@ support-files =
 [test_formData.html]
 [test_formSubmission.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_formSubmission2.html]
 skip-if = toolkit == 'android'
 [test_formelements.html]
 [test_fullscreen-api.html]
 tags = fullscreen
-skip-if = toolkit == 'android' || (e10s && os == 'linux') # Bug 1307347
+skip-if = toolkit == 'android'
 support-files =
   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
   file_fullscreen-hidden.html
--- a/dom/html/test/test_fullscreen-api.html
+++ b/dom/html/test/test_fullscreen-api.html
@@ -57,29 +57,46 @@ function finish() {
 
 function nextTest() {
   if (testWindow) {
     testWindow.close();
   }
   SimpleTest.executeSoon(runNextTest);
 }
 
+function shouldSkipTest(test) {
+  if (test == "file_fullscreen-plugins.html") {
+    if (!SpecialPowers.isMainProcess() &&
+        navigator.platform.indexOf('Linux') >= 0) {
+      // Bug 1330553
+      return true;
+    }
+  }
+  return false;
+}
+
 function runNextTest() {
   if (gTestIndex < gTestWindows.length) {
-    info("Run test " + gTestWindows[gTestIndex]);
-    testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500,scrollbars=yes");
-    // We'll wait for the window to load, then make sure our window is refocused
-    // before starting the test, which will get kicked off on "focus".
-    // This ensures that we're essentially back on the primary "desktop" on
-    // OS X Lion before we run the test.
-    testWindow.addEventListener("load", function() {
-      SimpleTest.waitForFocus(function() {
-        SimpleTest.waitForFocus(testWindow.begin, testWindow);
-      });
-    }, {once: true});
+    let test = gTestWindows[gTestIndex];
+    if (shouldSkipTest(test)) {
+      info(`Skip test ${test}`);
+      SimpleTest.executeSoon(runNextTest);
+    } else {
+      info(`Run test ${test}`);
+      testWindow = window.open(test, "", "width=500,height=500,scrollbars=yes");
+      // We'll wait for the window to load, then make sure our window is refocused
+      // before starting the test, which will get kicked off on "focus".
+      // This ensures that we're essentially back on the primary "desktop" on
+      // OS X Lion before we run the test.
+      testWindow.addEventListener("load", function() {
+        SimpleTest.waitForFocus(function() {
+          SimpleTest.waitForFocus(testWindow.begin, testWindow);
+        });
+      }, {once: true});
+    }
     gTestIndex++;
   } else {
     SimpleTest.finish();
   }
 }
 
 try {
   window.fullScreen = true;
--- a/dom/ipc/ContentPrefs.cpp
+++ b/dom/ipc/ContentPrefs.cpp
@@ -122,16 +122,17 @@ const char* mozilla::dom::ContentPrefs::
   "layout.css.prefixes.font-features",
   "layout.css.prefixes.gradients",
   "layout.css.prefixes.transforms",
   "layout.css.prefixes.transitions",
   "layout.css.prefixes.webkit",
   "layout.css.scope-pseudo.enabled",
   "layout.css.scroll-behavior.property-enabled",
   "layout.css.scroll-snap.enabled",
+  "layout.css.servo.enabled",
   "layout.css.shape-outside.enabled",
   "layout.css.text-align-unsafe-value.enabled",
   "layout.css.text-combine-upright-digits.enabled",
   "layout.css.text-combine-upright.enabled",
   "layout.css.touch_action.enabled",
   "layout.css.unprefixing-service.enabled",
   "layout.css.unprefixing-service.globally-whitelisted",
   "layout.css.unprefixing-service.include-test-domains",
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -155,17 +155,17 @@ parent:
 
   async Profile(nsCString aProfile);
 
   // Answers to request about site data
   async ReturnClearSiteData(NPError aRv, uint64_t aCallbackId);
 
   async ReturnSitesWithData(nsCString[] aSites, uint64_t aCallbackId);
 
-  intr GetKeyState(int32_t aVirtKey)
+  sync GetKeyState(int32_t aVirtKey)
     returns (int16_t aState);
 
   intr NPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(bool shouldRegister)
     returns (NPError result);
 };
 
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -2112,17 +2112,17 @@ PMCGetKeyState(int aVirtKey)
                           GetLastError()));
         MOZ_ASSERT(err != WAIT_FAILED);
         CloseHandle(semaphore);
         return 0;
     }
     PluginModuleChild* chromeInstance = PluginModuleChild::GetChrome();
     if (chromeInstance) {
         int16_t ret = 0;
-        if (chromeInstance->CallGetKeyState(aVirtKey, &ret)) {
+        if (chromeInstance->SendGetKeyState(aVirtKey, &ret)) {
           return ret;
         }
     }
     return sGetKeyStatePtrStub(aVirtKey);
 }
 #endif
 
 PPluginInstanceChild*
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -3398,24 +3398,24 @@ PluginModuleChromeParent::RecvProfile(co
 
     mProfile = aProfile;
     mGatherer->GatheredOOPProfile();
 #endif
     return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-PluginModuleParent::AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet)
+PluginModuleParent::RecvGetKeyState(const int32_t& aVirtKey, int16_t* aRet)
 {
     return IPC_FAIL_NO_REASON(this);
 }
 
 mozilla::ipc::IPCResult
-PluginModuleChromeParent::AnswerGetKeyState(const int32_t& aVirtKey,
+PluginModuleChromeParent::RecvGetKeyState(const int32_t& aVirtKey,
                                             int16_t* aRet)
 {
 #if defined(XP_WIN)
     *aRet = ::GetKeyState(aVirtKey);
     return IPC_OK();
 #else
-    return PluginModuleParent::AnswerGetKeyState(aVirtKey, aRet);
+    return PluginModuleParent::RecvGetKeyState(aVirtKey, aRet);
 #endif
 }
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -208,17 +208,17 @@ protected:
     static void TimeoutChanged(const char* aPref, void* aModule);
 
     virtual void UpdatePluginTimeout() {}
 
     virtual mozilla::ipc::IPCResult RecvNotifyContentModuleDestroyed() override { return IPC_OK(); }
 
     virtual mozilla::ipc::IPCResult RecvProfile(const nsCString& aProfile) override { return IPC_OK(); }
 
-    virtual mozilla::ipc::IPCResult AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
+    virtual mozilla::ipc::IPCResult RecvGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
 
     virtual mozilla::ipc::IPCResult RecvReturnClearSiteData(const NPError& aRv,
                                                             const uint64_t& aCallbackId) override;
 
     virtual mozilla::ipc::IPCResult RecvReturnSitesWithData(nsTArray<nsCString>&& aSites,
                                                             const uint64_t& aCallbackId) override;
 
     void SetPluginFuncs(NPPluginFuncs* aFuncs);
@@ -502,17 +502,17 @@ class PluginModuleChromeParent
     void StartProfiler(nsIProfilerStartParams* aParams);
     void StopProfiler();
 #endif
 
     virtual mozilla::ipc::IPCResult
     RecvProfile(const nsCString& aProfile) override;
 
     virtual mozilla::ipc::IPCResult
-    AnswerGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
+    RecvGetKeyState(const int32_t& aVirtKey, int16_t* aRet) override;
 
 private:
     virtual void
     EnteredCxxStack() override;
 
     void
     ExitedCxxStack() override;
 
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -1223,30 +1223,28 @@ nsCSPContext::PermitsAncestry(nsIDocShel
   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_GetInterface(ir));
   nsCOMPtr<nsIDocShellTreeItem> parentTreeItem;
   nsCOMPtr<nsIURI> currentURI;
   nsCOMPtr<nsIURI> uriClone;
 
   // iterate through each docShell parent item
   while (NS_SUCCEEDED(treeItem->GetParent(getter_AddRefs(parentTreeItem))) &&
          parentTreeItem != nullptr) {
+    // stop when reaching chrome
+    if (parentTreeItem->ItemType() == nsIDocShellTreeItem::typeChrome) {
+      break;
+    }
 
     nsIDocument* doc = parentTreeItem->GetDocument();
     NS_ASSERTION(doc, "Could not get nsIDocument from nsIDocShellTreeItem in nsCSPContext::PermitsAncestry");
     NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
     currentURI = doc->GetDocumentURI();
 
     if (currentURI) {
-      // stop when reaching chrome
-      bool isChrome = false;
-      rv = currentURI->SchemeIs("chrome", &isChrome);
-      NS_ENSURE_SUCCESS(rv, rv);
-      if (isChrome) { break; }
-
       // delete the userpass from the URI.
       rv = currentURI->CloneIgnoringRef(getter_AddRefs(uriClone));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // We don't care if this succeeds, just want to delete a userpass if
       // there was one.
       uriClone->SetUserPass(EmptyCString());
 
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -59,17 +59,17 @@ var ecmaGlobals =
     // NB: We haven't bothered to resolve constants like Infinity and NaN on
     // Xrayed windows (which are seen from the XBL scope). We could support
     // this if needed with some refactoring.
     {name: "Infinity", xbl: false},
     "Int16Array",
     "Int32Array",
     "Int8Array",
     "InternalError",
-    {name: "Intl", android: false},
+    "Intl",
     "Iterator",
     "JSON",
     "Map",
     "Math",
     {name: "NaN", xbl: false},
     "Number",
     "Object",
     "Promise",
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -34,17 +34,17 @@ var ecmaGlobals =
     "Float32Array",
     "Float64Array",
     "Function",
     "Infinity",
     "Int16Array",
     "Int32Array",
     "Int8Array",
     "InternalError",
-    {name: "Intl", android: false},
+    "Intl",
     "Iterator",
     "JSON",
     "Map",
     "Math",
     "NaN",
     "Number",
     "Object",
     "Promise",
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -34,17 +34,17 @@ var ecmaGlobals =
     "Float32Array",
     "Float64Array",
     "Function",
     "Infinity",
     "Int16Array",
     "Int32Array",
     "Int8Array",
     "InternalError",
-    {name: "Intl", android: false},
+    "Intl",
     "Iterator",
     "JSON",
     "Map",
     "Math",
     "NaN",
     "Number",
     "Object",
     "Promise",
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -760,17 +760,17 @@ GLBlitHelper::BlitPlanarYCbCrImage(layer
     BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation);
     BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation);
 
     if (needsAllocation) {
         mGL->fUniform2f(mYTexScaleLoc, (float)yuvData->mYSize.width/yuvData->mYStride, 1.0f);
         mGL->fUniform2f(mCbCrTexScaleLoc, (float)yuvData->mCbCrSize.width/yuvData->mCbCrStride, 1.0f);
     }
 
-    float* yuvToRgb = gfxUtils::Get3x3YuvColorMatrix(yuvData->mYUVColorSpace);
+    const auto& yuvToRgb = gfxUtils::YuvToRgbMatrix3x3ColumnMajor(yuvData->mYUVColorSpace);
     mGL->fUniformMatrix3fv(mYuvColorMatrixLoc, 1, 0, yuvToRgb);
 
     mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
     for (int i = 0; i < 3; i++) {
         mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
         mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
     }
     return true;
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -884,17 +884,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
       }
 
       if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) {
         // This can happen if we failed to upload the textures, most likely
         // because of unsupported dimensions (we don't tile YCbCr textures).
         return;
       }
 
-      float* yuvToRgb = gfxUtils::Get4x3YuvColorMatrix(ycbcrEffect->mYUVColorSpace);
+      const float* yuvToRgb = gfxUtils::YuvToRgbMatrix4x3RowMajor(ycbcrEffect->mYUVColorSpace);
       memcpy(&mPSConstants.yuvColorMatrix, yuvToRgb, sizeof(mPSConstants.yuvColorMatrix));
 
       TextureSourceD3D11* sourceY  = source->GetSubSource(Y)->AsSourceD3D11();
       TextureSourceD3D11* sourceCb = source->GetSubSource(Cb)->AsSourceD3D11();
       TextureSourceD3D11* sourceCr = source->GetSubSource(Cr)->AsSourceD3D11();
 
       ID3D11ShaderResourceView* srViews[3] = { sourceY->GetShaderResourceView(),
                                                sourceCb->GetShaderResourceView(),
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -415,17 +415,17 @@ CompositorD3D9::DrawQuad(const gfx::Rect
 
       if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) || !source->GetSubSource(Cr)) {
         // This can happen if we failed to upload the textures, most likely
         // because of unsupported dimensions (we don't tile YCbCr textures).
         return;
       }
 
 
-      float* yuvToRgb = gfxUtils::Get4x3YuvColorMatrix(ycbcrEffect->mYUVColorSpace);
+      const float* yuvToRgb = gfxUtils::YuvToRgbMatrix4x3RowMajor(ycbcrEffect->mYUVColorSpace);
       d3d9Device->SetPixelShaderConstantF(CBmYuvColorMatrix, yuvToRgb, 3);
 
       TextureSourceD3D9* sourceY  = source->GetSubSource(Y)->AsSourceD3D9();
       TextureSourceD3D9* sourceCb = source->GetSubSource(Cb)->AsSourceD3D9();
       TextureSourceD3D9* sourceCr = source->GetSubSource(Cr)->AsSourceD3D9();
 
 
       MOZ_ASSERT(sourceY->GetD3D9Texture());
@@ -569,17 +569,17 @@ CompositorD3D9::SetMask(const EffectChai
 
   device()->SetTexture(aMaskTexture, source->GetD3D9Texture());
 
   const gfx::Matrix4x4& maskTransform = maskEffect->mMaskTransform;
   NS_ASSERTION(maskTransform.Is2D(), "How did we end up with a 3D transform here?!");
   Rect bounds = Rect(Point(), Size(maskEffect->mSize));
   bounds = maskTransform.As2D().TransformBounds(bounds);
 
-  device()->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister, 
+  device()->SetVertexShaderConstantF(DeviceManagerD3D9::sMaskQuadRegister,
                                      ShaderConstantRect(bounds.x,
                                                         bounds.y,
                                                         bounds.width,
                                                         bounds.height),
                                      1);
 }
 
 /**
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -961,14 +961,14 @@ ShaderProgramOGL::SetBlurRadius(float aR
     gaussianKernel[i] /= sum;
   }
   SetArrayUniform(KnownUniform::BlurGaussianKernel, GAUSSIAN_KERNEL_HALF_WIDTH, gaussianKernel);
 }
 
 void
 ShaderProgramOGL::SetYUVColorSpace(YUVColorSpace aYUVColorSpace)
 {
-  float* yuvToRgb = gfxUtils::Get3x3YuvColorMatrix(aYUVColorSpace);
+  const float* yuvToRgb = gfxUtils::YuvToRgbMatrix3x3ColumnMajor(aYUVColorSpace);
   SetMatrix3fvUniform(KnownUniform::YuvColorMatrix, yuvToRgb);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -1164,50 +1164,70 @@ From Rec709:
 [B]   [1.1643835616438356,  2.1124017857142854,     0.0]                    [Cr - 128]
 
 For [0,1] instead of [0,255], and to 5 places:
 [R]   [1.16438,  0.00000,  1.79274]   [ Y - 0.06275]
 [G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
 [B]   [1.16438,  2.11240,  0.00000]   [Cr - 0.50196]
 */
 
-/* static */ float*
-gfxUtils::Get4x3YuvColorMatrix(YUVColorSpace aYUVColorSpace)
-{
-  static const float yuv_to_rgb_rec601[12] = { 1.16438f,  0.0f,      1.59603f, 0.0f,
-                                               1.16438f, -0.39176f, -0.81297f, 0.0f,
-                                               1.16438f,  2.01723f,  0.0f,     0.0f,
-                                             };
+static const float kRec601[9] = {
+  1.16438f, 0.00000f, 1.59603f,
+  1.16438f,-0.39176f,-0.81297f,
+  1.16438f, 2.01723f, 0.00000f,
+};
+static const float kRec709[9] = {
+  1.16438f, 0.00000f, 1.79274f,
+  1.16438f,-0.21325f,-0.53291f,
+  1.16438f, 2.11240f, 0.00000f,
+};
 
-  static const float yuv_to_rgb_rec709[12] = { 1.16438f,  0.0f,      1.79274f, 0.0f,
-                                               1.16438f, -0.21325f, -0.53291f, 0.0f,
-                                               1.16438f,  2.11240f,  0.0f,     0.0f,
-                                             };
+/* static */ const float*
+gfxUtils::YuvToRgbMatrix4x3RowMajor(YUVColorSpace aYUVColorSpace)
+{
+  #define X(x) { x[0], x[1], x[2], 0.0f, \
+                 x[3], x[4], x[5], 0.0f, \
+                 x[6], x[7], x[8], 0.0f }
+
+  static const float rec601[12] = X(kRec601);
+  static const float rec709[12] = X(kRec709);
 
-  if (aYUVColorSpace == YUVColorSpace::BT709) {
-    return const_cast<float*>(yuv_to_rgb_rec709);
-  } else {
-    return const_cast<float*>(yuv_to_rgb_rec601);
+  #undef X
+
+  switch (aYUVColorSpace) {
+  case YUVColorSpace::BT601:
+    return rec601;
+  case YUVColorSpace::BT709:
+    return rec709;
+  default: // YUVColorSpace::UNKNOWN
+    MOZ_ASSERT(false, "unknown aYUVColorSpace");
+    return rec601;
   }
 }
 
-/* static */ float*
-gfxUtils::Get3x3YuvColorMatrix(YUVColorSpace aYUVColorSpace)
+/* static */ const float*
+gfxUtils::YuvToRgbMatrix3x3ColumnMajor(YUVColorSpace aYUVColorSpace)
 {
-  static const float yuv_to_rgb_rec601[9] = {
-    1.16438f, 1.16438f, 1.16438f, 0.0f, -0.39176f, 2.01723f, 1.59603f, -0.81297f, 0.0f,
-  };
-  static const float yuv_to_rgb_rec709[9] = {
-    1.16438f, 1.16438f, 1.16438f, 0.0f, -0.21325f, 2.11240f, 1.79274f, -0.53291f, 0.0f,
-  };
+  #define X(x) { x[0], x[3], x[6], \
+                 x[1], x[4], x[7], \
+                 x[2], x[5], x[8] }
+
+  static const float rec601[9] = X(kRec601);
+  static const float rec709[9] = X(kRec709);
+
+  #undef X
 
-  if (aYUVColorSpace == YUVColorSpace::BT709) {
-    return const_cast<float*>(yuv_to_rgb_rec709);
-  } else {
-    return const_cast<float*>(yuv_to_rgb_rec601);
+  switch (aYUVColorSpace) {
+  case YUVColorSpace::BT601:
+    return rec601;
+  case YUVColorSpace::BT709:
+    return rec709;
+  default: // YUVColorSpace::UNKNOWN
+    MOZ_ASSERT(false, "unknown aYUVColorSpace");
+    return rec601;
   }
 }
 
 /* static */ void
 gfxUtils::WriteAsPNG(SourceSurface* aSurface, const nsAString& aFile)
 {
   WriteAsPNG(aSurface, NS_ConvertUTF16toUTF8(aFile).get());
 }
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -37,17 +37,16 @@ class gfxUtils {
 public:
     typedef mozilla::gfx::DataSourceSurface DataSourceSurface;
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::gfx::IntPoint IntPoint;
     typedef mozilla::gfx::Matrix Matrix;
     typedef mozilla::gfx::SourceSurface SourceSurface;
     typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
     typedef mozilla::image::ImageRegion ImageRegion;
-    typedef mozilla::YUVColorSpace YUVColorSpace;
 
     /*
      * Premultiply or Unpremultiply aSourceSurface, writing the result
      * to aDestSurface or back into aSourceSurface if aDestSurface is null.
      *
      * If aDestSurface is given, it must have identical format, dimensions, and
      * stride as the source.
      *
@@ -131,22 +130,18 @@ public:
      */
     static gfxFloat ClampToScaleFactor(gfxFloat aVal);
 
     /**
      * Clears surface to aColor (which defaults to transparent black).
      */
     static void ClearThebesSurface(gfxASurface* aSurface);
 
-    /**
-     * Get array of yuv to rgb conversion matrix.
-     */
-    static float* Get4x3YuvColorMatrix(YUVColorSpace aYUVColorSpace);
-
-    static float* Get3x3YuvColorMatrix(YUVColorSpace aYUVColorSpace);
+    static const float* YuvToRgbMatrix4x3RowMajor(mozilla::YUVColorSpace aYUVColorSpace);
+    static const float* YuvToRgbMatrix3x3ColumnMajor(mozilla::YUVColorSpace aYUVColorSpace);
 
     /**
      * Creates a copy of aSurface, but having the SurfaceFormat aFormat.
      *
      * This function always creates a new surface. Do not call it if aSurface's
      * format is the same as aFormat. Such a non-conversion would just be an
      * unnecessary and wasteful copy (this function asserts to prevent that).
      *
new file mode 100644
--- /dev/null
+++ b/js/src/builtin/.eslintrc.js
@@ -0,0 +1,22 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "../../../toolkit/.eslintrc.js"
+  ],
+
+  "rules": {
+    // We should fix those at some point, but we use this to detect NaNs.
+    "no-self-compare": "off",
+    // Disabling these two make it easier to implement the spec.
+    "spaced-comment": "off",
+    "no-lonely-if": "off",
+    // SpiderMonkey's style doesn't match any of the possible options.
+    "brace-style": "off",
+    // Manually defining all the selfhosted methods is a slog.
+    "no-undef": "off",
+    // Disabled until we can use let/const to fix those erorrs,
+    // and undefined names cause an exception and abort during runtime initialization.
+    "no-redeclare": "off",
+  }
+};
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -1579,17 +1579,17 @@ function Intl_Collator_supportedLocalesO
  * Collator internal properties.
  *
  * Spec: ECMAScript Internationalization API Specification, 9.1 and 10.2.3.
  */
 var collatorInternalProperties = {
     sortLocaleData: collatorSortLocaleData,
     searchLocaleData: collatorSearchLocaleData,
     _availableLocales: null,
-    availableLocales: function()
+    availableLocales: function() // eslint-disable-line object-shorthand
     {
         var locales = this._availableLocales;
         if (locales)
             return locales;
 
         locales = intl_Collator_availableLocales();
         addSpecialMissingLanguageTags(locales);
         return (this._availableLocales = locales);
@@ -1702,17 +1702,17 @@ function Intl_Collator_resolvedOptions()
 /**
  * NumberFormat internal properties.
  *
  * Spec: ECMAScript Internationalization API Specification, 9.1 and 11.2.3.
  */
 var numberFormatInternalProperties = {
     localeData: numberFormatLocaleData,
     _availableLocales: null,
-    availableLocales: function()
+    availableLocales: function() // eslint-disable-line object-shorthand
     {
         var locales = this._availableLocales;
         if (locales)
             return locales;
 
         locales = intl_NumberFormat_availableLocales();
         addSpecialMissingLanguageTags(locales);
         return (this._availableLocales = locales);
@@ -2693,17 +2693,17 @@ function Intl_DateTimeFormat_supportedLo
 /**
  * DateTimeFormat internal properties.
  *
  * Spec: ECMAScript Internationalization API Specification, 9.1 and 12.2.3.
  */
 var dateTimeFormatInternalProperties = {
     localeData: dateTimeFormatLocaleData,
     _availableLocales: null,
-    availableLocales: function()
+    availableLocales: function() // eslint-disable-line object-shorthand
     {
         var locales = this._availableLocales;
         if (locales)
             return locales;
 
         locales = intl_DateTimeFormat_availableLocales();
         addSpecialMissingLanguageTags(locales);
         return (this._availableLocales = locales);
@@ -2907,17 +2907,17 @@ function resolveICUPattern(pattern, resu
 
 /**
  * PluralRules internal properties.
  *
  * Spec: ECMAScript 402 API, PluralRules, 1.3.3.
  */
 var pluralRulesInternalProperties = {
     _availableLocales: null,
-    availableLocales: function()
+    availableLocales: function() // eslint-disable-line object-shorthand
     {
         var locales = this._availableLocales;
         if (locales)
             return locales;
 
         locales = intl_PluralRules_availableLocales();
         addSpecialMissingLanguageTags(locales);
         return (this._availableLocales = locales);
--- a/js/src/builtin/Module.js
+++ b/js/src/builtin/Module.js
@@ -79,24 +79,24 @@ function ModuleResolveExport(exportName,
     // Step 2
     for (let i = 0; i < resolveSet.length; i++) {
         let r = resolveSet[i];
         if (r.module === module && r.exportName === exportName)
             return null;
     }
 
     // Step 3
-    _DefineDataProperty(resolveSet, resolveSet.length, {module: module, exportName: exportName});
+    _DefineDataProperty(resolveSet, resolveSet.length, {module, exportName});
 
     // Step 4
     let localExportEntries = module.localExportEntries;
     for (let i = 0; i < localExportEntries.length; i++) {
         let e = localExportEntries[i];
         if (exportName === e.exportName)
-            return {module: module, bindingName: e.localName};
+            return {module, bindingName: e.localName};
     }
 
     // Step 5
     let indirectExportEntries = module.indirectExportEntries;
     for (let i = 0; i < indirectExportEntries.length; i++) {
         let e = indirectExportEntries[i];
         if (exportName === e.exportName) {
             let importedModule = CallModuleResolveHook(module, e.moduleRequest,
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -662,21 +662,23 @@ function String_static_raw(callSite, ...
  * Spec: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String#String_generic_methods
  */
 function String_static_localeCompare(str1, str2) {
     WarnDeprecatedStringMethod(STRING_GENERICS_LOCALE_COMPARE, "localeCompare");
     if (arguments.length < 1)
         ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "String.localeCompare");
     var locales = arguments.length > 2 ? arguments[2] : undefined;
     var options = arguments.length > 3 ? arguments[3] : undefined;
+/* eslint-disable no-unreachable */
 #if EXPOSE_INTL_API
     return callFunction(String_localeCompare, str1, str2, locales, options);
 #else
     return callFunction(std_String_localeCompare, str1, str2, locales, options);
 #endif
+/* eslint-enable no-unreachable */
 }
 
 // ES6 draft 2014-04-27 B.2.3.3
 function String_big() {
     RequireObjectCoercible(this);
     return "<big>" + ToString(this) + "</big>";
 }
 
--- a/js/src/builtin/TypedObject.js
+++ b/js/src/builtin/TypedObject.js
@@ -925,17 +925,17 @@ function StorageOfTypedObject(obj) {
     if (ObjectIsTransparentTypedObject(obj)) {
       if (!TypedObjectIsAttached(obj))
           ThrowTypeError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED);
 
       var descr = TypedObjectTypeDescr(obj);
       var byteLength = DESCR_SIZE(descr);
 
       return { buffer: TypedObjectBuffer(obj),
-               byteLength: byteLength,
+               byteLength,
                byteOffset: TypedObjectByteOffset(obj) };
     }
   }
 
   ThrowTypeError(JSMSG_TYPEDOBJECT_BAD_ARGS);
 }
 
 // This is the `objectType()` function defined in the spec.
@@ -1145,19 +1145,17 @@ function ComputeIterationSpace(arrayType
       iterationSpace[i] = grainLen;
       totalLength *= grainLen;
       grainType = grainType.elementType;
     } else {
       // RangeError("Depth "+depth+" too high");
       ThrowTypeError(JSMSG_TYPEDOBJECT_BAD_ARGS);
     }
   }
-  return { iterationSpace: iterationSpace,
-           grainType: grainType,
-           totalLength: totalLength };
+  return { iterationSpace, grainType, totalLength };
 }
 
 function IncrementIterationSpace(indices, iterationSpace) {
   // Increment something like
   //     [5, 5, 7, 8]
   // in an iteration space of
   //     [9, 9, 9, 9]
   // to
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -4614,31 +4614,34 @@ Parser<ParseHandler>::lexicalDeclaration
     return decl;
 }
 
 template <>
 bool
 Parser<FullParseHandler>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet)
 {
     if (tt == TOK_LC) {
-        TokenStream::Modifier modifier = TokenStream::KeywordIsName;
         while (true) {
             // Handle the forms |import {} from 'a'| and
             // |import { ..., } from 'a'| (where ... is non empty), by
             // escaping the loop early if the next token is }.
-            if (!tokenStream.peekToken(&tt, TokenStream::KeywordIsName))
+            if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
                 return false;
 
             if (tt == TOK_RC)
                 break;
 
             // If the next token is a keyword, the previous call to
             // peekToken matched it as a TOK_NAME, and put it in the
             // lookahead buffer, so this call will match keywords as well.
-            MUST_MATCH_TOKEN_MOD(TOK_NAME, TokenStream::KeywordIsName, JSMSG_NO_IMPORT_NAME);
+            if (tt != TOK_NAME) {
+                error(JSMSG_NO_IMPORT_NAME);
+                return false;
+            }
+
             Rooted<PropertyName*> importName(context, tokenStream.currentName());
             TokenPos importNamePos = pos();
 
             TokenKind maybeAs;
             if (!tokenStream.peekToken(&maybeAs))
                 return null();
 
             if (maybeAs == TOK_NAME &&
@@ -4686,27 +4689,28 @@ Parser<FullParseHandler>::namedImportsOr
                 return false;
 
             Node importSpec = handler.newBinary(PNK_IMPORT_SPEC, importNameNode, bindingName);
             if (!importSpec)
                 return false;
 
             handler.addList(importSpecSet, importSpec);
 
-            bool matched;
-            if (!tokenStream.matchToken(&matched, TOK_COMMA))
+            TokenKind next;
+            if (!tokenStream.getToken(&next))
                 return false;
 
-            if (!matched) {
-                modifier = TokenStream::None;
+            if (next == TOK_RC)
                 break;
+
+            if (next != TOK_COMMA) {
+                error(JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
+                return false;
             }
         }
-
-        MUST_MATCH_TOKEN_MOD(TOK_RC, modifier, JSMSG_RC_AFTER_IMPORT_SPEC_LIST);
     } else {
         MOZ_ASSERT(tt == TOK_MUL);
         if (!tokenStream.getToken(&tt))
             return false;
 
         if (tt != TOK_NAME || tokenStream.currentName() != context->names().as) {
             error(JSMSG_AS_AFTER_IMPORT_STAR);
             return false;
@@ -4937,22 +4941,27 @@ Parser<FullParseHandler>::exportDeclarat
         kid = handler.newList(PNK_EXPORT_SPEC_LIST);
         if (!kid)
             return null();
 
         while (true) {
             // Handle the forms |export {}| and |export { ..., }| (where ...
             // is non empty), by escaping the loop early if the next token
             // is }.
-            if (!tokenStream.peekToken(&tt))
-                return null();
+            if (!tokenStream.getToken(&tt))
+                return null();
+
             if (tt == TOK_RC)
                 break;
 
-            MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_BINDING_NAME);
+            if (tt != TOK_NAME) {
+                error(JSMSG_NO_BINDING_NAME);
+                return null();
+            }
+
             Node bindingName = newName(tokenStream.currentName());
             if (!bindingName)
                 return null();
 
             bool foundAs;
             if (!tokenStream.matchContextualKeyword(&foundAs, context->names().as))
                 return null();
             if (foundAs)
@@ -4966,24 +4975,28 @@ Parser<FullParseHandler>::exportDeclarat
                 return null();
 
             Node exportSpec = handler.newBinary(PNK_EXPORT_SPEC, bindingName, exportName);
             if (!exportSpec)
                 return null();
 
             handler.addList(kid, exportSpec);
 
-            bool matched;
-            if (!tokenStream.matchToken(&matched, TOK_COMMA))
-                return null();
-            if (!matched)
+            TokenKind next;
+            if (!tokenStream.getToken(&next))
+                return null();
+
+            if (next == TOK_RC)
                 break;
-        }
-
-        MUST_MATCH_TOKEN(TOK_RC, JSMSG_RC_AFTER_EXPORT_SPEC_LIST);
+
+            if (next != TOK_COMMA) {
+                error(JSMSG_RC_AFTER_EXPORT_SPEC_LIST);
+                return null();
+            }
+        }
 
         // Careful!  If |from| follows, even on a new line, it must start a
         // FromClause:
         //
         //   export { x }
         //   from "foo"; // a single ExportDeclaration
         //
         // But if it doesn't, we might have an ASI opportunity in Operand
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/regress/regalloc-i64-load-store-global.js
@@ -0,0 +1,24 @@
+load(libdir + "wasm.js");
+
+setJitCompilerOption('wasm.test-mode', 1);
+
+wasmFullPassI64(`
+    (module
+        (global (mut i64) (i64.const 9970292656026947164))
+        (func (export "get_global_0") (result i64) get_global 0)
+
+        (func (export "run") (result i64) (param i32)
+            i64.const 8692897571457488645
+            i64.const 1028567229461950342
+            i64.mul
+            get_global 0
+            f32.const 3.141592653
+            f32.floor
+            f32.const -13.37
+            f32.floor
+            f32.copysign
+            drop
+            i64.div_u
+        )
+    )
+`, createI64(1));
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -25,17 +25,17 @@ class TempAllocator;
 enum MethodStatus
 {
     Method_Error,
     Method_CantCompile,
     Method_Skipped,
     Method_Compiled
 };
 
-enum class AbortReason {
+enum class AbortReason : uint8_t {
     Alloc,
     Inlining,
     PreliminaryObjects,
     Disable,
     Error,
     NoAbort
 };
 
@@ -49,16 +49,21 @@ using mozilla::Ok;
 template <typename E>
 inline mozilla::GenericErrorResult<E>
 Err(E&& aErrorValue)
 {
     return mozilla::MakeGenericErrorResult(mozilla::Forward<E>(aErrorValue));
 }
 
 
+static_assert(sizeof(AbortReasonOr<Ok>) <= sizeof(uintptr_t),
+    "Unexpected size of AbortReasonOr<Ok>");
+static_assert(sizeof(AbortReasonOr<bool>) <= sizeof(uintptr_t),
+    "Unexpected size of AbortReasonOr<bool>");
+
 // A JIT context is needed to enter into either an JIT method or an instance
 // of a JIT compiler. It points to a temporary allocator and the active
 // JSContext, either of which may be nullptr, and the active compartment, which
 // will not be nullptr.
 
 class JitContext
 {
   public:
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4209,32 +4209,47 @@ LIRGenerator::visitWasmBoundsCheck(MWasm
 
     auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(input));
     add(lir, ins);
 }
 
 void
 LIRGenerator::visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins)
 {
-    LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
-    if (ins->type() == MIRType::Int64)
+    if (ins->type() == MIRType::Int64) {
+#ifdef JS_PUNBOX64
+        LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
+#else
+        LAllocation tlsPtr = useRegister(ins->tlsPtr());
+#endif
         defineInt64(new(alloc()) LWasmLoadGlobalVarI64(tlsPtr), ins);
-    else
+    } else {
+        LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
         define(new(alloc()) LWasmLoadGlobalVar(tlsPtr), ins);
+    }
 }
 
 void
 LIRGenerator::visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins)
 {
     MDefinition* value = ins->value();
-    LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
-    if (value->type() == MIRType::Int64)
-        add(new(alloc()) LWasmStoreGlobalVarI64(useInt64RegisterAtStart(value), tlsPtr), ins);
-    else
-        add(new(alloc()) LWasmStoreGlobalVar(useRegisterAtStart(value), tlsPtr), ins);
+    if (value->type() == MIRType::Int64) {
+#ifdef JS_PUNBOX64
+        LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
+        LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
+#else
+        LAllocation tlsPtr = useRegister(ins->tlsPtr());
+        LInt64Allocation valueAlloc = useInt64Register(value);
+#endif
+        add(new(alloc()) LWasmStoreGlobalVarI64(valueAlloc, tlsPtr), ins);
+    } else {
+        LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
+        LAllocation valueAlloc = useRegisterAtStart(value);
+        add(new(alloc()) LWasmStoreGlobalVar(valueAlloc, tlsPtr), ins);
+    }
 }
 
 void
 LIRGenerator::visitWasmParameter(MWasmParameter* ins)
 {
     ABIArg abi = ins->abi();
     if (abi.argInRegister()) {
 #if defined(JS_NUNBOX32)
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1026,17 +1026,17 @@ JSContext::JSContext(JSRuntime* runtime,
     if (!TlsContext.get())
         TlsContext.set(this);
 }
 
 JSContext::~JSContext()
 {
 #ifdef XP_WIN
     if (threadNative_)
-        CloseHandle((HANDLE)threadNative_);
+        CloseHandle((HANDLE)threadNative_.ref());
 #endif
 
     /* Free the stuff hanging off of cx. */
     MOZ_ASSERT(!resolvingList);
 
     if (dtoaState)
         DestroyDtoaState(dtoaState);
 
@@ -1046,16 +1046,28 @@ JSContext::~JSContext()
 #ifdef JS_SIMULATOR
     js::jit::Simulator::Destroy(simulator_);
 #endif
 
     if (TlsContext.get() == this)
         TlsContext.set(nullptr);
 }
 
+void
+JSContext::setRuntime(JSRuntime* rt)
+{
+    MOZ_ASSERT(!resolvingList);
+    MOZ_ASSERT(!compartment());
+    MOZ_ASSERT(!activation());
+    MOZ_ASSERT(!unwrappedException_.ref().initialized());
+    MOZ_ASSERT(!asyncStackForNewActivations_.ref().initialized());
+
+    runtime_ = rt;
+}
+
 bool
 JSContext::getPendingException(MutableHandleValue rval)
 {
     MOZ_ASSERT(throwing);
     rval.set(unwrappedException());
     if (IsAtomsCompartment(compartment()))
         return true;
     bool wasOverRecursed = overRecursed_;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -88,29 +88,33 @@ struct JSContext : public JS::RootingCon
                    public js::MallocProvider<JSContext>
 {
     explicit JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
     ~JSContext();
 
     bool init();
 
   private:
-    JSRuntime* const runtime_;
+    js::UnprotectedData<JSRuntime*> runtime_;
 
     // System handle for the thread this context is associated with.
-    size_t threadNative_;
+    js::WriteOnceData<size_t> threadNative_;
 
     // The thread on which this context is running, if this is performing a parse task.
     js::ThreadLocalData<js::HelperThread*> helperThread_;
 
     js::ThreadLocalData<JS::ContextOptions> options_;
 
     js::ThreadLocalData<js::gc::ArenaLists*> arenas_;
 
   public:
+    // This is used by helper threads to change the runtime their context is
+    // currently operating on.
+    void setRuntime(JSRuntime* rt);
+
     size_t threadNative() const { return threadNative_; }
 
     inline js::gc::ArenaLists* arenas() const { return arenas_; }
 
     template <typename T>
     bool isInsideCurrentZone(T thing) const {
         return thing->zoneFromAnyThread() == zone_;
     }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4466,16 +4466,21 @@ GCRuntime::findZoneEdgesForWeakMaps()
      * need for zone edges from the delegate's zone to the weakmap zone.
      *
      * Since the edges point into and not away from the zone the weakmap is in
      * we must find these edges in advance and store them in a set on the Zone.
      * If we run out of memory, we fall back to sweeping everything in one
      * group.
      */
 
+#ifdef DEBUG
+    for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
+        MOZ_ASSERT(zone->gcZoneGroupEdges().empty());
+#endif
+
     for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
         if (!WeakMapBase::findInterZoneEdges(zone))
             return false;
     }
 
     return true;
 }
 
@@ -4490,22 +4495,26 @@ GCRuntime::findZoneGroups(AutoLockForExc
     for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
         MOZ_ASSERT(zone->isGCMarking());
         finder.addNode(zone);
     }
     zoneGroups = finder.getResultsList();
     currentZoneGroup = zoneGroups;
     zoneGroupIndex = 0;
 
+#ifdef DEBUG
     for (Zone* head = currentZoneGroup; head; head = head->nextGroup()) {
         for (Zone* zone = head; zone; zone = zone->nextNodeInGroup())
             MOZ_ASSERT(zone->isGCMarking());
     }
 
     MOZ_ASSERT_IF(!isIncremental, !currentZoneGroup->nextGroup());
+    for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
+        MOZ_ASSERT(zone->gcZoneGroupEdges().empty());
+#endif
 }
 
 static void
 ResetGrayList(JSCompartment* comp);
 
 void
 GCRuntime::getNextZoneGroup()
 {
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -140,17 +140,17 @@ ObjectValueMap::findZoneEdges()
     for (Range r = all(); !r.empty(); r.popFront()) {
         JSObject* key = r.front().key();
         if (key->asTenured().isMarked(BLACK) && !key->asTenured().isMarked(GRAY))
             continue;
         JSObject* delegate = getDelegate(key);
         if (!delegate)
             continue;
         Zone* delegateZone = delegate->zone();
-        if (delegateZone == zone)
+        if (delegateZone == zone || !delegateZone->isGCMarking())
             continue;
         if (!delegateZone->gcZoneGroupEdges().put(key->zone()))
             return false;
     }
     return true;
 }
 
 ObjectWeakMap::ObjectWeakMap(JSContext* cx)
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -272,17 +272,25 @@ class WeakMap : public HashMap<Key, Valu
             }
         }
 
         return markedAny;
     }
 
     JSObject* getDelegate(JSObject* key) const {
         JSWeakmapKeyDelegateOp op = key->getClass()->extWeakmapKeyDelegateOp();
-        return op ? op(key) : nullptr;
+        if (!op)
+            return nullptr;
+
+        JSObject* obj = op(key);
+        if (!obj)
+            return nullptr;
+
+        MOZ_ASSERT(obj->runtimeFromMainThread() == zone->runtimeFromMainThread());
+        return obj;
     }
 
     JSObject* getDelegate(JSScript* script) const {
         return nullptr;
     }
 
   private:
     void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); }
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -868,16 +868,26 @@ GlobalHelperThreadState::checkTaskThread
             count++;
         if (count >= maxThreads)
             return false;
     }
 
     return true;
 }
 
+struct MOZ_RAII AutoSetContextRuntime
+{
+    explicit AutoSetContextRuntime(JSRuntime* rt) {
+        TlsContext.get()->setRuntime(rt);
+    }
+    ~AutoSetContextRuntime() {
+        TlsContext.get()->setRuntime(nullptr);
+    }
+};
+
 static inline bool
 IsHelperThreadSimulatingOOM(js::oom::ThreadType threadType)
 {
 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
     return js::oom::targetThread == threadType;
 #else
     return false;
 #endif
@@ -1177,25 +1187,25 @@ js::GCParallelTask::runFromMainThread(JS
     mozilla::TimeStamp timeStart = mozilla::TimeStamp::Now();
     run();
     duration_ = mozilla::TimeStamp::Now() - timeStart;
 }
 
 void
 js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
 {
-    JSContext cx(runtime(), JS::ContextOptions());
+    AutoSetContextRuntime ascr(runtime());
     gc::AutoSetThreadIsPerformingGC performingGC;
 
     {
         AutoUnlockHelperThreadState parallelSection(locked);
         mozilla::TimeStamp timeStart = mozilla::TimeStamp::Now();
-        cx.heapState = JS::HeapState::MajorCollecting;
+        TlsContext.get()->heapState = JS::HeapState::MajorCollecting;
         run();
-        cx.heapState = JS::HeapState::Idle;
+        TlsContext.get()->heapState = JS::HeapState::Idle;
         duration_ = mozilla::TimeStamp::Now() - timeStart;
     }
 
     state = Finished;
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
 }
 
 bool
@@ -1489,17 +1499,16 @@ HelperThread::handlePromiseTaskWorkload(
     MOZ_ASSERT(HelperThreadState().canStartPromiseTask(locked));
     MOZ_ASSERT(idle());
 
     PromiseTask* task = HelperThreadState().promiseTasks(locked).popCopy();
     currentTask.emplace(task);
 
     {
         AutoUnlockHelperThreadState unlock(locked);
-        JSContext cx(nullptr, JS::ContextOptions());
 
         task->execute();
 
         if (!task->runtime()->finishAsyncTaskCallback(task)) {
             // We cannot simply delete the task now because the PromiseTask must
             // be destroyed on its runtime's thread. Add it to a list of tasks
             // to delete before the next GC.
             AutoEnterOOMUnsafeRegion oomUnsafe;
@@ -1543,17 +1552,17 @@ HelperThread::handleIonWorkload(AutoLock
     {
         AutoUnlockHelperThreadState unlock(locked);
 
         TraceLoggerThread* logger = TraceLoggerForCurrentThread();
         TraceLoggerEvent event(logger, TraceLogger_AnnotateScripts, builder->script());
         AutoTraceLog logScript(logger, event);
         AutoTraceLog logCompile(logger, TraceLogger_IonCompilation);
 
-        JSContext cx(rt, JS::ContextOptions());
+        AutoSetContextRuntime ascr(rt);
         jit::JitContext jctx(jit::CompileRuntime::get(rt),
                              jit::CompileCompartment::get(builder->script()->compartment()),
                              &builder->alloc());
         builder->setBackgroundCodegen(jit::CompileBackEnd(builder));
     }
 
     FinishOffThreadIonCompile(builder, locked);
     currentTask.reset();
@@ -1660,23 +1669,23 @@ HelperThread::handleParseWorkload(AutoLo
 
     currentTask.emplace(HelperThreadState().parseWorklist(locked).popCopy());
     ParseTask* task = parseTask();
     task->cx->setHelperThread(this);
 
     for (size_t i = 0; i < ArrayLength(task->cx->nativeStackLimit); i++)
         task->cx->nativeStackLimit[i] = stackLimit;
 
-    MOZ_ASSERT(!TlsContext.get());
+    JSContext* oldcx = TlsContext.get();
     TlsContext.set(task->cx);
     {
         AutoUnlockHelperThreadState unlock(locked);
         task->parse();
     }
-    TlsContext.set(nullptr);
+    TlsContext.set(oldcx);
 
     // The callback is invoked while we are still off the main thread.
     task->callback(task, task->callbackData);
 
     // FinishOffThreadScript will need to be called on the script to
     // migrate it into the correct compartment.
     {
         AutoEnterOOMUnsafeRegion oomUnsafe;
@@ -1858,17 +1867,17 @@ void
 HelperThread::handleGCHelperWorkload(AutoLockHelperThreadState& locked)
 {
     MOZ_ASSERT(HelperThreadState().canStartGCHelperTask(locked));
     MOZ_ASSERT(idle());
 
     currentTask.emplace(HelperThreadState().gcHelperWorklist(locked).popCopy());
     GCHelperState* task = gcHelperTask();
 
-    JSContext cx(task->runtime(), JS::ContextOptions());
+    AutoSetContextRuntime ascr(task->runtime());
 
     {
         AutoUnlockHelperThreadState unlock(locked);
         task->work();
     }
 
     currentTask.reset();
     HelperThreadState().notifyAll(GlobalHelperThreadState::CONSUMER, locked);
@@ -1877,16 +1886,18 @@ HelperThread::handleGCHelperWorkload(Aut
 void
 HelperThread::threadLoop()
 {
     MOZ_ASSERT(CanUseExtraThreads());
 
     JS::AutoSuppressGCAnalysis nogc;
     AutoLockHelperThreadState lock;
 
+    JSContext cx(nullptr, JS::ContextOptions());
+
     // Compute the thread's stack limit, for over-recursed checks.
     uintptr_t stackLimit = GetNativeStackBase();
 #if JS_STACK_GROWTH_DIRECTION > 0
     stackLimit += HELPER_STACK_QUOTA;
 #else
     stackLimit -= HELPER_STACK_QUOTA;
 #endif
 
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -496,19 +496,21 @@ class BaseCompiler
     ValType                     latentType_;     // Operand type, if latentOp_ is true
     Assembler::Condition        latentIntCmp_;   // Comparison operator, if latentOp_ == Compare, int types
     Assembler::DoubleCondition  latentDoubleCmp_;// Comparison operator, if latentOp_ == Compare, float types
 
     FuncOffsets                 offsets_;
     MacroAssembler&             masm;            // No '_' suffix - too tedious...
 
     AllocatableGeneralRegisterSet availGPR_;
-    AllocatableFloatRegisterSet availFPU_;
+    AllocatableFloatRegisterSet   availFPU_;
 #ifdef DEBUG
-    bool                        scratchRegisterTaken_;
+    bool                          scratchRegisterTaken_;
+    AllocatableGeneralRegisterSet allGPR_;       // The registers available to the compiler
+    AllocatableFloatRegisterSet   allFPU_;       //   after removing ScratchReg, HeapReg, etc
 #endif
 
     Vector<Local, 8, SystemAllocPolicy> localInfo_;
     Vector<OutOfLineCode*, 8, SystemAllocPolicy> outOfLine_;
 
     // Index into localInfo_ of the special local used for saving the TLS
     // pointer. This follows the function's real arguments and locals.
     uint32_t                    tlsSlot_;
@@ -2023,16 +2025,60 @@ class BaseCompiler
     }
 
     // Peek at the stack, for calls.
 
     Stk& peek(uint32_t relativeDepth) {
         return stk_[stk_.length()-1-relativeDepth];
     }
 
+#ifdef DEBUG
+    // Check that we're not leaking registers by comparing the
+    // state of the stack + available registers with the set of
+    // all available registers.
+
+    // Call this before compiling any code.
+    void setupRegisterLeakCheck() {
+        allGPR_ = availGPR_;
+        allFPU_ = availFPU_;
+    }
+
+    // Call this between opcodes.
+    void performRegisterLeakCheck() {
+        AllocatableGeneralRegisterSet knownGPR_ = availGPR_;
+        AllocatableFloatRegisterSet knownFPU_ = availFPU_;
+        for (size_t i = 0 ; i < stk_.length() ; i++) {
+	    Stk& item = stk_[i];
+	    switch (item.kind_) {
+	      case Stk::RegisterI32:
+		knownGPR_.add(item.i32reg());
+		break;
+	      case Stk::RegisterI64:
+#ifdef JS_PUNBOX64
+		knownGPR_.add(item.i64reg().reg);
+#else
+		knownGPR_.add(item.i64reg().high);
+		knownGPR_.add(item.i64reg().low);
+#endif
+		break;
+	      case Stk::RegisterF32:
+		knownFPU_.add(item.f32reg());
+		break;
+	      case Stk::RegisterF64:
+		knownFPU_.add(item.f64reg());
+		break;
+	      default:
+		break;
+	    }
+	}
+	MOZ_ASSERT(knownGPR_.bits() == allGPR_.bits());
+	MOZ_ASSERT(knownFPU_.bits() == allFPU_.bits());
+    }
+#endif
+
     ////////////////////////////////////////////////////////////
     //
     // Control stack
 
     void initControl(Control& item)
     {
         // Make sure the constructor was run properly
         MOZ_ASSERT(item.framePushed == UINT32_MAX && item.stackSize == UINT32_MAX);
@@ -6621,16 +6667,20 @@ bool
 BaseCompiler::emitBody()
 {
     uint32_t overhead = 0;
 
     for (;;) {
 
         Nothing unused_a, unused_b;
 
+#ifdef DEBUG
+        performRegisterLeakCheck();
+#endif
+
 #define emitBinary(doEmit, type) \
         iter_.readBinary(type, &unused_a, &unused_b) && (deadCode_ || (doEmit(), true))
 
 #define emitUnary(doEmit, type) \
         iter_.readUnary(type, &unused_a) && (deadCode_ || (doEmit(), true))
 
 #define emitComparison(doEmit, operandType, compareOp) \
         iter_.readComparison(operandType, &unused_a, &unused_b) && \
@@ -7362,16 +7412,20 @@ BaseCompiler::BaseCompiler(const ModuleE
 #elif defined(JS_CODEGEN_ARM64)
     availGPR_.take(HeapReg);
     availGPR_.take(HeapLenReg);
 #elif defined(JS_CODEGEN_X86)
     availGPR_.take(ScratchRegX86);
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     availGPR_.take(HeapReg);
 #endif
+
+#ifdef DEBUG
+    setupRegisterLeakCheck();
+#endif
 }
 
 bool
 BaseCompiler::init()
 {
     if (!SigD_.append(ValType::F64))
         return false;
     if (!SigF_.append(ValType::F32))
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -78,18 +78,16 @@ head = head_ongc.js
 [test_onGarbageCollection-03.js]
 head = head_ongc.js
 [test_onGarbageCollection-04.js]
 head = head_ongc.js
 [test_onGarbageCollection-05.js]
 head = head_ongc.js
 [test_reflect_parse.js]
 [test_localeCompare.js]
-# Bug 676965: test fails consistently on Android
-fail-if = os == "android"
 [test_recursive_import.js]
 [test_xpcomutils.js]
 [test_unload.js]
 [test_attributes.js]
 [test_params.js]
 [test_tearoffs.js]
 [test_want_components.js]
 [test_components.js]
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -179,18 +179,16 @@ ServoRestyleManager::RecreateStyleContex
   // expensive checks in the common case.
   //
   // Also, we're going to need to check for pseudos of display: contents
   // elements, though that is buggy right now even in non-stylo mode, see
   // bug 1251799.
   const bool recreateContext = oldStyleContext &&
     oldStyleContext->StyleSource().AsServoComputedValues() != computedValues;
 
-  MOZ_ASSERT_IF(changeHint, recreateContext);
-
   if (recreateContext) {
     RefPtr<nsStyleContext> newContext =
       aStyleSet->GetContext(computedValues.forget(), aParentContext, nullptr,
                             CSSPseudoElementType::NotPseudo, aElement);
 
     // XXX This could not always work as expected: there are kinds of content
     // with the first split and the last sharing style, but others not. We
     // should handle those properly.
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -1767,56 +1767,74 @@ nsFlexContainerFrame::
   if (isMainMinSizeAuto) {
     aFlexItem.UpdateMainMinSize(resolvedMinSize);
   }
 }
 
 /**
  * A cached result for a measuring reflow.
  *
- * Right now we only need to cache the available size, the height and the
- * ascent. This can be extended later if needed.
+ * Right now we only need to cache the available size and the computed height
+ * for checking that the reflow input is valid, and the height and the ascent
+ * to be used. This can be extended later if needed.
  *
  * The assumption here is that a given flex item measurement won't change until
- * either the available size changes, or the flex container intrinsic size is
- * marked as dirty (due to a style or DOM change).
+ * either the available size or computed height changes, or the flex container
+ * intrinsic size is marked as dirty (due to a style or DOM change).
+ *
+ * In particular the computed height may change between measuring reflows due to
+ * how the mIsFlexContainerMeasuringReflow flag affects size computation (see
+ * bug 1336708).
  *
  * Caching it prevents us from doing exponential reflows in cases of deeply
  * nested flex and scroll frames.
  *
  * We store them in the frame property table for simplicity.
  */
-struct nsFlexContainerFrame::CachedMeasuringReflowResult
+class nsFlexContainerFrame::CachedMeasuringReflowResult
 {
-  LogicalSize mAvailableSize;
+  // Members that are part of the cache key:
+  const LogicalSize mAvailableSize;
+  const nscoord mComputedHeight;
+
+  // Members that are part of the cache value:
   const nscoord mHeight;
   const nscoord mAscent;
 
-  CachedMeasuringReflowResult(const LogicalSize& aAvailableSize,
-                              nscoord aHeight,
-                              nscoord aAscent)
-    : mAvailableSize(aAvailableSize)
-    , mHeight(aHeight)
-    , mAscent(aAscent)
+public:
+  CachedMeasuringReflowResult(const ReflowInput& aReflowInput,
+                              const ReflowOutput& aDesiredSize)
+    : mAvailableSize(aReflowInput.AvailableSize())
+    , mComputedHeight(aReflowInput.ComputedHeight())
+    , mHeight(aDesiredSize.Height())
+    , mAscent(aDesiredSize.BlockStartAscent())
   {}
+
+  bool IsValidFor(const ReflowInput& aReflowInput) const {
+    return mAvailableSize == aReflowInput.AvailableSize() &&
+      mComputedHeight == aReflowInput.ComputedHeight();
+  }
+
+  nscoord Height() const { return mHeight; }
+
+  nscoord Ascent() const { return mAscent; }
 };
 
 NS_DECLARE_FRAME_PROPERTY_DELETABLE(CachedFlexMeasuringReflow,
                                     CachedMeasuringReflowResult);
 
 const CachedMeasuringReflowResult&
 nsFlexContainerFrame::MeasureAscentAndHeightForFlexItem(
   FlexItem& aItem,
   nsPresContext* aPresContext,
   ReflowInput& aChildReflowInput)
 {
-  const auto availableSize = aChildReflowInput.AvailableSize();
   const FrameProperties props = aItem.Frame()->Properties();
   if (const auto* cachedResult = props.Get(CachedFlexMeasuringReflow())) {
-    if (cachedResult->mAvailableSize == availableSize) {
+    if (cachedResult->IsValidFor(aChildReflowInput)) {
       return *cachedResult;
     }
   }
 
   ReflowOutput childDesiredSize(aChildReflowInput);
   nsReflowStatus childReflowStatus;
 
   const uint32_t flags = NS_FRAME_NO_MOVE_FRAME;
@@ -1833,19 +1851,17 @@ nsFlexContainerFrame::MeasureAscentAndHe
              "should be complete");
 
   // Tell the child we're done with its initial reflow.
   // (Necessary for e.g. GetBaseline() to work below w/out asserting)
   FinishReflowChild(aItem.Frame(), aPresContext,
                     childDesiredSize, &aChildReflowInput, 0, 0, flags);
 
   auto result =
-    new CachedMeasuringReflowResult(availableSize,
-                                    childDesiredSize.Height(),
-                                    childDesiredSize.BlockStartAscent());
+    new CachedMeasuringReflowResult(aChildReflowInput, childDesiredSize);
 
   props.Set(CachedFlexMeasuringReflow(), result);
   return *result;
 }
 
 /* virtual */ void
 nsFlexContainerFrame::MarkIntrinsicISizesDirty()
 {
@@ -1880,21 +1896,21 @@ nsFlexContainerFrame::
   if (aForceVerticalResizeForMeasuringReflow) {
     childRIForMeasuringHeight.SetVResize(true);
   }
 
   const CachedMeasuringReflowResult& reflowResult =
     MeasureAscentAndHeightForFlexItem(aFlexItem, aPresContext,
                                       childRIForMeasuringHeight);
 
-  aFlexItem.SetAscent(reflowResult.mAscent);
+  aFlexItem.SetAscent(reflowResult.Ascent());
 
   // Subtract border/padding in vertical axis, to get _just_
   // the effective computed value of the "height" property.
-  nscoord childDesiredHeight = reflowResult.mHeight -
+  nscoord childDesiredHeight = reflowResult.Height() -
     childRIForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom();
 
   return std::max(0, childDesiredHeight);
 }
 
 FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput,
                    float aFlexGrow, float aFlexShrink, nscoord aFlexBaseSize,
                    nscoord aMainMinSize,  nscoord aMainMaxSize,
@@ -4055,33 +4071,33 @@ nsFlexContainerFrame::SizeItemInCrossAxi
 
   // Tentatively store the child's desired content-box cross-size.
   // Note that childDesiredSize is the border-box size, so we have to
   // subtract border & padding to get the content-box size.
   // (Note that at this point in the code, we know our cross axis is vertical,
   // so we don't bother with making aAxisTracker pick the cross-axis component
   // for us.)
   nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom();
-  if (reflowResult.mHeight < crossAxisBorderPadding) {
+  if (reflowResult.Height() < crossAxisBorderPadding) {
     // Child's requested size isn't large enough for its border/padding!
     // This is OK for the trivial nsFrame::Reflow() impl, but other frame
     // classes should know better. So, if we get here, the child had better be
     // an instance of nsFrame (i.e. it should return null from GetType()).
     // XXXdholbert Once we've fixed bug 765861, we should upgrade this to an
     // assertion that trivially passes if bug 765861's flag has been flipped.
     NS_WARNING_ASSERTION(
       !aItem.Frame()->GetType(),
       "Child should at least request space for border/padding");
     aItem.SetCrossSize(0);
   } else {
     // (normal case)
-    aItem.SetCrossSize(reflowResult.mHeight - crossAxisBorderPadding);
+    aItem.SetCrossSize(reflowResult.Height() - crossAxisBorderPadding);
   }
 
-  aItem.SetAscent(reflowResult.mAscent);
+  aItem.SetAscent(reflowResult.Ascent());
 }
 
 void
 FlexLine::PositionItemsInCrossAxis(nscoord aLineStartPosition,
                                    const FlexboxAxisTracker& aAxisTracker)
 {
   SingleLineCrossAxisPositionTracker lineCrossAxisPosnTracker(aAxisTracker);
 
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -51,17 +51,17 @@ public:
   friend nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
                                                     nsStyleContext* aContext);
 
   // Forward-decls of helper classes
   class FlexItem;
   class FlexLine;
   class FlexboxAxisTracker;
   struct StrutInfo;
-  struct CachedMeasuringReflowResult;
+  class CachedMeasuringReflowResult;
 
   // nsIFrame overrides
   void Init(nsIContent*       aContent,
             nsContainerFrame* aParent,
             nsIFrame*         aPrevInFlow) override;
 
   void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                         const nsRect&           aDirtyRect,
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001-ref.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link name="author" href="mailto:emilio@crisal.io">
+<style>
+html, body { margin: 0; padding: 0; }
+
+.content {
+  margin-top: 100px;
+  width: 200px;
+  height: 200px;
+  background: blue;
+}
+</style>
+<body>
+  <div class="content"></div>
+</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/flexbox/flexbox-align-items-center-nested-001.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Test: Flexbox nested containers with align-items: center and flexible items</title>
+<link rel="match" href="flexbox-align-items-center-nested-001-ref.html">
+<link name="author" href="mailto:emilio@crisal.io">
+<link rel="help" href="https://www.w3.org/TR/css-flexbox-1/#align-items-property">
+<style>
+html, body { margin: 0; padding: 0; }
+body {
+  height: 400px;
+  position: relative;
+}
+
+.container-0 {
+  display: flex;
+  position: absolute;
+  height: 100%;
+  flex-direction: column;
+}
+
+.container-1 {
+  flex: 1 0 auto;
+  display: flex;
+  align-items: center;
+}
+
+.container-2 {
+  height: 100%;
+  display: flex;
+  align-items: center;
+}
+
+.content {
+  width: 200px;
+  height: 200px;
+  background: blue;
+}
+</style>
+<body>
+  <div class="container-0">
+    <div class="container-1">
+      <div class="container-2">
+        <div class="content"></div>
+      </div>
+    </div>
+  </div>
+</body>
--- a/layout/reftests/w3c-css/submitted/flexbox/reftest.list
+++ b/layout/reftests/w3c-css/submitted/flexbox/reftest.list
@@ -34,16 +34,18 @@
 == flexbox-align-self-vert-002.xhtml  flexbox-align-self-vert-002-ref.xhtml
 == flexbox-align-self-vert-003.xhtml  flexbox-align-self-vert-003-ref.xhtml
 == flexbox-align-self-vert-004.xhtml  flexbox-align-self-vert-004-ref.xhtml
 fuzzy-if(Android,158,32) == flexbox-align-self-vert-rtl-001.xhtml  flexbox-align-self-vert-rtl-001-ref.xhtml
 == flexbox-align-self-vert-rtl-002.xhtml  flexbox-align-self-vert-rtl-002-ref.xhtml
 == flexbox-align-self-vert-rtl-003.xhtml  flexbox-align-self-vert-rtl-003-ref.xhtml
 == flexbox-align-self-vert-rtl-004.xhtml  flexbox-align-self-vert-rtl-004-ref.xhtml
 
+== flexbox-align-items-center-nested-001.html flexbox-align-items-center-nested-001-ref.html
+
 # Tests for computing the baseline of a flex container
 == flexbox-baseline-align-self-baseline-horiz-001.html flexbox-baseline-align-self-baseline-horiz-001-ref.html
 == flexbox-baseline-align-self-baseline-vert-001.html flexbox-baseline-align-self-baseline-vert-001-ref.html
 == flexbox-baseline-empty-001a.html flexbox-baseline-empty-001-ref.html
 == flexbox-baseline-empty-001b.html flexbox-baseline-empty-001-ref.html
 == flexbox-baseline-multi-item-horiz-001.html flexbox-baseline-multi-item-horiz-001-ref.html
 == flexbox-baseline-multi-item-vert-001.html flexbox-baseline-multi-item-vert-001-ref.html
 == flexbox-baseline-multi-line-horiz-001.html flexbox-baseline-multi-line-horiz-001-ref.html
--- a/mfbt/Result.h
+++ b/mfbt/Result.h
@@ -25,21 +25,28 @@ namespace mozilla {
  */
 struct Ok {};
 
 template <typename E> class GenericErrorResult;
 template <typename V, typename E> class Result;
 
 namespace detail {
 
-enum class VEmptiness { IsEmpty, IsNotEmpty };
-enum class Alignedness { IsAligned, IsNotAligned };
+enum class PackingStrategy {
+  Variant,
+  NullIsOk,
+  LowBitTagIsError,
+  PackedVariant,
+};
 
-template <typename V, typename E, VEmptiness EmptinessOfV, Alignedness Aligned>
-class ResultImplementation
+template <typename V, typename E, PackingStrategy Strategy>
+class ResultImplementation;
+
+template <typename V, typename E>
+class ResultImplementation<V, E, PackingStrategy::Variant>
 {
   mozilla::Variant<V, E> mStorage;
 
 public:
   explicit ResultImplementation(V aValue) : mStorage(aValue) {}
   explicit ResultImplementation(E aErrorValue) : mStorage(aErrorValue) {}
 
   bool isOk() const { return mStorage.template is<V>(); }
@@ -50,36 +57,36 @@ public:
   V unwrap() const { return mStorage.template as<V>(); }
   E unwrapErr() const { return mStorage.template as<E>(); }
 };
 
 /**
  * mozilla::Variant doesn't like storing a reference. This is a specialization
  * to store E as pointer if it's a reference.
  */
-template <typename V, typename E, VEmptiness EmptinessOfV, Alignedness Aligned>
-class ResultImplementation<V, E&, EmptinessOfV, Aligned>
+template <typename V, typename E>
+class ResultImplementation<V, E&, PackingStrategy::Variant>
 {
   mozilla::Variant<V, E*> mStorage;
 
 public:
   explicit ResultImplementation(V aValue) : mStorage(aValue) {}
   explicit ResultImplementation(E& aErrorValue) : mStorage(&aErrorValue) {}
 
   bool isOk() const { return mStorage.template is<V>(); }
   V unwrap() const { return mStorage.template as<V>(); }
   E& unwrapErr() const { return *mStorage.template as<E*>(); }
 };
 
 /**
  * Specialization for when the success type is Ok (or another empty class) and
  * the error type is a reference.
  */
-template <typename V, typename E, Alignedness Aligned>
-class ResultImplementation<V, E&, VEmptiness::IsEmpty, Aligned>
+template <typename V, typename E>
+class ResultImplementation<V, E&, PackingStrategy::NullIsOk>
 {
   E* mErrorValue;
 
 public:
   explicit ResultImplementation(V) : mErrorValue(nullptr) {}
   explicit ResultImplementation(E& aErrorValue) : mErrorValue(&aErrorValue) {}
 
   bool isOk() const { return mErrorValue == nullptr; }
@@ -87,18 +94,18 @@ public:
   V unwrap() const { return V(); }
   E& unwrapErr() const { return *mErrorValue; }
 };
 
 /**
  * Specialization for when alignment permits using the least significant bit as
  * a tag bit.
  */
-template <typename V, typename E, VEmptiness EmptinessOfV>
-class ResultImplementation<V*, E&, EmptinessOfV, Alignedness::IsAligned>
+template <typename V, typename E>
+class ResultImplementation<V*, E&, PackingStrategy::LowBitTagIsError>
 {
   uintptr_t mBits;
 
 public:
   explicit ResultImplementation(V* aValue)
     : mBits(reinterpret_cast<uintptr_t>(aValue))
   {
     MOZ_ASSERT((uintptr_t(aValue) % MOZ_ALIGNOF(V)) == 0,
@@ -109,17 +116,83 @@ public:
   {
     MOZ_ASSERT((uintptr_t(&aErrorValue) % MOZ_ALIGNOF(E)) == 0,
                "Result errors must not be misaligned");
   }
 
   bool isOk() const { return (mBits & 1) == 0; }
 
   V* unwrap() const { return reinterpret_cast<V*>(mBits); }
-  E& unwrapErr() const { return *reinterpret_cast<E*>(mBits & ~uintptr_t(1)); }
+  E& unwrapErr() const { return *reinterpret_cast<E*>(mBits ^ 1); }
+};
+
+// Return true if any of the struct can fit in a word.
+template<typename V, typename E>
+struct IsPackableVariant
+{
+  struct VEbool {
+      V v;
+      E e;
+      bool ok;
+  };
+  struct EVbool {
+      E e;
+      V v;
+      bool ok;
+  };
+
+  using Impl = typename Conditional<sizeof(VEbool) <= sizeof(EVbool),
+                                    VEbool, EVbool>::Type;
+
+  static const bool value = sizeof(Impl) <= sizeof(uintptr_t);
+};
+
+/**
+ * Specialization for when both type are not using all the bytes, in order to
+ * use one byte as a tag.
+ */
+template <typename V, typename E>
+class ResultImplementation<V, E, PackingStrategy::PackedVariant>
+{
+  using Impl = typename IsPackableVariant<V, E>::Impl;
+  Impl data;
+
+public:
+  explicit ResultImplementation(V aValue)
+  {
+    data.v = aValue;
+    data.ok = true;
+  }
+  explicit ResultImplementation(E aErrorValue)
+  {
+    data.e = aErrorValue;
+    data.ok = false;
+  }
+
+  bool isOk() const { return data.ok; }
+
+  V unwrap() const { return data.v; }
+  E unwrapErr() const { return data.e; }
+};
+
+// To use nullptr as a special value, we need the counter part to exclude zero
+// from its range of valid representations.
+//
+// By default assume that zero can be represented.
+template<typename T>
+struct UnusedZero
+{
+  static const bool value = false;
+};
+
+// References can't be null.
+template<typename T>
+struct UnusedZero<T&>
+{
+  static const bool value = true;
 };
 
 // A bit of help figuring out which of the above specializations to use.
 //
 // We begin by safely assuming types don't have a spare bit.
 template <typename T> struct HasFreeLSB { static const bool value = false; };
 
 // The lowest bit of a properly-aligned pointer is always zero if the pointee
@@ -130,16 +203,34 @@ template <typename T> struct HasFreeLSB<
 };
 
 // We store references as pointers, so they have a free bit if a pointer would
 // have one.
 template <typename T> struct HasFreeLSB<T&> {
   static const bool value = HasFreeLSB<T*>::value;
 };
 
+// Select one of the previous result implementation based on the properties of
+// the V and E types.
+template <typename V, typename E>
+struct SelectResultImpl
+{
+  static const PackingStrategy value =
+      (IsEmpty<V>::value && UnusedZero<E>::value)
+    ? PackingStrategy::NullIsOk
+    : (detail::HasFreeLSB<V>::value && detail::HasFreeLSB<E>::value)
+    ? PackingStrategy::LowBitTagIsError
+    : (IsDefaultConstructible<V>::value && IsDefaultConstructible<E>::value &&
+       IsPackableVariant<V, E>::value)
+    ? PackingStrategy::PackedVariant
+    : PackingStrategy::Variant;
+
+  using Type = detail::ResultImplementation<V, E, value>;
+};
+
 template <typename T>
 struct IsResult : FalseType { };
 
 template <typename V, typename E>
 struct IsResult<Result<V, E>> : TrueType { };
 
 } // namespace detail
 
@@ -167,25 +258,18 @@ struct IsResult<Result<V, E>> : TrueType
  * The purpose of Result is to reduce the screwups caused by using `false` or
  * `nullptr` to indicate errors.
  * What screwups? See <https://bugzilla.mozilla.org/show_bug.cgi?id=912928> for
  * a partial list.
  */
 template <typename V, typename E>
 class MOZ_MUST_USE_TYPE Result final
 {
-  using Impl =
-    detail::ResultImplementation<V, E,
-                                 IsEmpty<V>::value
-                                   ? detail::VEmptiness::IsEmpty
-                                   : detail::VEmptiness::IsNotEmpty,
-                                 (detail::HasFreeLSB<V>::value &&
-                                  detail::HasFreeLSB<E>::value)
-                                   ? detail::Alignedness::IsAligned
-                                   : detail::Alignedness::IsNotAligned>;
+  using Impl = typename detail::SelectResultImpl<V, E>::Type;
+
   Impl mImpl;
 
 public:
   /**
    * Create a success result.
    */
   MOZ_IMPLICIT Result(V aValue) : mImpl(aValue) { MOZ_ASSERT(isOk()); }
 
--- a/mfbt/TypeTraits.h
+++ b/mfbt/TypeTraits.h
@@ -569,32 +569,84 @@ struct IsUnsignedHelper<T, false, false,
  * mozilla::IsUnsigned<unsigned char>::value is true;
  * mozilla::IsUnsigned<float>::value is false.
  */
 template<typename T>
 struct IsUnsigned : detail::IsUnsignedHelper<T> {};
 
 namespace detail {
 
+struct DoIsDefaultConstructibleImpl
+{
+  template<typename T, typename = decltype(T())>
+  static TrueType test(int);
+  template<typename T>
+  static FalseType test(...);
+};
+
+template<typename T>
+struct IsDefaultConstructibleImpl : public DoIsDefaultConstructibleImpl
+{
+  typedef decltype(test<T>(0)) Type;
+};
+
+} // namespace detail
+
+/**
+ * IsDefaultConstructible determines whether a type has a public default
+ * constructor.
+ *
+ * struct S0 {};                    // Implicit default constructor.
+ * struct S1 { S1(); };
+ * struct S2 { explicit S2(int); }; // No implicit default constructor when
+ *                                  // another one is present.
+ * struct S3 { S3() = delete; };
+ * class C4 { C4(); };              // Default constructor is private.
+ *
+ * mozilla::IsDefaultConstructible<int>::value is true;
+ * mozilla::IsDefaultConstructible<S0>::value is true;
+ * mozilla::IsDefaultConstructible<S1>::value is true;
+ * mozilla::IsDefaultConstructible<S2>::value is false;
+ * mozilla::IsDefaultConstructible<S3>::value is false;
+ * mozilla::IsDefaultConstructible<S4>::value is false.
+ */
+template<typename T>
+struct IsDefaultConstructible
+  : public detail::IsDefaultConstructibleImpl<T>::Type
+{};
+
+namespace detail {
+
 struct DoIsDestructibleImpl
 {
   template<typename T, typename = decltype(DeclVal<T&>().~T())>
   static TrueType test(int);
   template<typename T>
   static FalseType test(...);
 };
 
 template<typename T>
 struct IsDestructibleImpl : public DoIsDestructibleImpl
 {
   typedef decltype(test<T>(0)) Type;
 };
 
 } // namespace detail
 
+/**
+ * IsDestructible determines whether a type has a public destructor.
+ *
+ * struct S0 {};                    // Implicit default destructor.
+ * struct S1 { ~S1(); };
+ * class C2 { ~C2(); };             // private destructor.
+ *
+ * mozilla::IsDestructible<S0>::value is true;
+ * mozilla::IsDestructible<S1>::value is true;
+ * mozilla::IsDestructible<C2>::value is false.
+ */
 template<typename T>
 struct IsDestructible : public detail::IsDestructibleImpl<T>::Type {};
 
 /* 20.9.5 Type property queries [meta.unary.prop.query] */
 
 /* 20.9.6 Relationships between types [meta.rel] */
 
 /**
--- a/mfbt/tests/TestResult.cpp
+++ b/mfbt/tests/TestResult.cpp
@@ -21,16 +21,38 @@ static_assert(sizeof(Result<Ok, Failed&>
               "Result with empty value type should be pointer-sized");
 static_assert(sizeof(Result<int*, Failed&>) == sizeof(uintptr_t),
               "Result with two aligned pointer types should be pointer-sized");
 static_assert(sizeof(Result<char*, Failed*>) > sizeof(char*),
               "Result with unaligned success type `char*` must not be pointer-sized");
 static_assert(sizeof(Result<int*, char*>) > sizeof(char*),
               "Result with unaligned error type `char*` must not be pointer-sized");
 
+enum Foo8 : uint8_t {};
+enum Foo16 : uint16_t {};
+enum Foo32 : uint32_t {};
+static_assert(sizeof(Result<Ok, Foo8>) <= sizeof(uintptr_t),
+              "Result with small types should be pointer-sized");
+static_assert(sizeof(Result<Ok, Foo16>) <= sizeof(uintptr_t),
+              "Result with small types should be pointer-sized");
+static_assert(sizeof(Foo32) >= sizeof(uintptr_t) ||
+              sizeof(Result<Ok, Foo32>) <= sizeof(uintptr_t),
+              "Result with small types should be pointer-sized");
+
+static_assert(sizeof(Result<Foo16, Foo8>) <= sizeof(uintptr_t),
+              "Result with small types should be pointer-sized");
+static_assert(sizeof(Result<Foo8, Foo16>) <= sizeof(uintptr_t),
+              "Result with small types should be pointer-sized");
+static_assert(sizeof(Foo32) >= sizeof(uintptr_t) ||
+              sizeof(Result<Foo32, Foo16>) <= sizeof(uintptr_t),
+              "Result with small types should be pointer-sized");
+static_assert(sizeof(Foo32) >= sizeof(uintptr_t) ||
+              sizeof(Result<Foo16, Foo32>) <= sizeof(uintptr_t),
+              "Result with small types should be pointer-sized");
+
 static GenericErrorResult<Failed&>
 Fail()
 {
   static Failed failed;
   return MakeGenericErrorResult<Failed&>(failed);
 }
 
 static Result<Ok, Failed&>
--- a/mfbt/tests/TestTypeTraits.cpp
+++ b/mfbt/tests/TestTypeTraits.cpp
@@ -18,25 +18,26 @@ using mozilla::AddPointer;
 using mozilla::AddRvalueReference;
 using mozilla::Decay;
 using mozilla::DeclVal;
 using mozilla::IsFunction;
 using mozilla::IsArray;
 using mozilla::IsBaseOf;
 using mozilla::IsClass;
 using mozilla::IsConvertible;
+using mozilla::IsDefaultConstructible;
+using mozilla::IsDestructible;
 using mozilla::IsEmpty;
 using mozilla::IsLvalueReference;
 using mozilla::IsPointer;
 using mozilla::IsReference;
 using mozilla::IsRvalueReference;
 using mozilla::IsSame;
 using mozilla::IsSigned;
 using mozilla::IsUnsigned;
-using mozilla::IsDestructible;
 using mozilla::MakeSigned;
 using mozilla::MakeUnsigned;
 using mozilla::RemoveExtent;
 using mozilla::RemovePointer;
 
 static_assert(!IsFunction<int>::value,
               "int is not a function type");
 static_assert(IsFunction<void(int)>::value,
@@ -348,16 +349,90 @@ class NotIntConstructible
   NotIntConstructible(int) = delete;
 };
 
 static_assert(!IsSigned<NotIntConstructible>::value,
               "non-arithmetic types are not signed");
 static_assert(!IsUnsigned<NotIntConstructible>::value,
               "non-arithmetic types are not unsigned");
 
+struct TrivialCtor0 {};
+struct TrivialCtor1 { int mX; };
+
+struct DefaultCtor0 { DefaultCtor0() {} };
+struct DefaultCtor1 { DefaultCtor1() = default; };
+struct DefaultCtor2 { DefaultCtor2() {} explicit DefaultCtor2(int) {} };
+
+struct NoDefaultCtor0 { explicit NoDefaultCtor0(int) {} };
+struct NoDefaultCtor1 { NoDefaultCtor1() = delete; };
+
+class PrivateCtor0 { PrivateCtor0() {} };
+class PrivateCtor1 { PrivateCtor1() = default; };
+
+enum EnumCtor0 {};
+enum EnumCtor1 : int {};
+
+enum class EnumClassCtor0 {};
+enum class EnumClassCtor1 : int {};
+
+union UnionCtor0 {};
+union UnionCtor1 { int mX; };
+
+union UnionCustomCtor0 { explicit UnionCustomCtor0(int) {} };
+union UnionCustomCtor1
+{
+  int mX;
+  explicit UnionCustomCtor1(int aX) : mX(aX) {}
+};
+
+static_assert(IsDefaultConstructible<int>::value,
+              "integral type is default-constructible");
+
+static_assert(IsDefaultConstructible<TrivialCtor0>::value,
+              "trivial constructor class 0 is default-constructible");
+static_assert(IsDefaultConstructible<TrivialCtor1>::value,
+              "trivial constructor class 1 is default-constructible");
+
+static_assert(IsDefaultConstructible<DefaultCtor0>::value,
+              "default constructor class 0 is default-constructible");
+static_assert(IsDefaultConstructible<DefaultCtor1>::value,
+              "default constructor class 1 is default-constructible");
+static_assert(IsDefaultConstructible<DefaultCtor2>::value,
+              "default constructor class 2 is default-constructible");
+
+static_assert(!IsDefaultConstructible<NoDefaultCtor0>::value,
+              "no default constructor class is not default-constructible");
+static_assert(!IsDefaultConstructible<NoDefaultCtor1>::value,
+              "deleted default constructor class is not default-constructible");
+
+static_assert(!IsDefaultConstructible<PrivateCtor0>::value,
+              "private default constructor class 0 is not default-constructible");
+static_assert(!IsDefaultConstructible<PrivateCtor1>::value,
+              "private default constructor class 1 is not default-constructible");
+
+static_assert(IsDefaultConstructible<EnumCtor0>::value,
+              "enum constructor 0 is default-constructible");
+static_assert(IsDefaultConstructible<EnumCtor1>::value,
+              "enum constructor 1 is default-constructible");
+
+static_assert(IsDefaultConstructible<EnumClassCtor0>::value,
+              "enum class constructor 0 is default-constructible");
+static_assert(IsDefaultConstructible<EnumClassCtor1>::value,
+              "enum class constructor 1 is default-constructible");
+
+static_assert(IsDefaultConstructible<UnionCtor0>::value,
+              "union constructor 0 is default-constructible");
+static_assert(IsDefaultConstructible<UnionCtor1>::value,
+              "union constructor 1 is default-constructible");
+
+static_assert(!IsDefaultConstructible<UnionCustomCtor0>::value,
+              "union with custom 1-arg constructor 0 is not default-constructible");
+static_assert(!IsDefaultConstructible<UnionCustomCtor1>::value,
+              "union with custom 1-arg constructor 1 is not default-constructible");
+
 class PublicDestructible
 {
 public:
   ~PublicDestructible();
 };
 class PrivateDestructible
 {
 private:
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -167,16 +167,17 @@ pref("browser.download.manager.flashCoun
 pref("browser.download.manager.displayedHistoryDays", 7);
 pref("browser.download.manager.addToRecentDocs", true);
 
 /* download helper */
 pref("browser.helperApps.deleteTempFileOnExit", false);
 
 /* password manager */
 pref("signon.rememberSignons", true);
+pref("signon.autofillForms.http", true);
 pref("signon.expireMasterPassword", false);
 pref("signon.debug", false);
 
 /* form helper (scroll to and optionally zoom into editable fields)  */
 pref("formhelper.mode", 2);  // 0 = disabled, 1 = enabled, 2 = dynamic depending on screen size
 pref("formhelper.autozoom", true);
 
 /* find helper */
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java
@@ -174,39 +174,46 @@ public class CrashHandler implements Thr
         }
         return uptimeMins / 1000;
     }
 
     private static String getJavaPackageName() {
         return CrashHandler.class.getPackage().getName();
     }
 
-    protected String getAppPackageName() {
-        final Context context = getAppContext();
-
-        if (context != null) {
-            return context.getPackageName();
-        }
-
+    private static String getProcessName() {
         try {
-            // Package name is also the command line string in most cases.
             final FileReader reader = new FileReader("/proc/self/cmdline");
             final char[] buffer = new char[64];
             try {
                 if (reader.read(buffer) > 0) {
                     // cmdline is delimited by '\0', and we want the first token.
                     final int nul = Arrays.asList(buffer).indexOf('\0');
                     return (new String(buffer, 0, nul < 0 ? buffer.length : nul)).trim();
                 }
             } finally {
                 reader.close();
             }
+        } catch (final IOException e) {
+        }
 
-        } catch (final IOException e) {
-            Log.i(LOGTAG, "Error reading package name", e);
+        return null;
+    }
+
+    protected String getAppPackageName() {
+        final Context context = getAppContext();
+
+        if (context != null) {
+            return context.getPackageName();
+        }
+
+        // Package name is also the process name in most cases.
+        String processName = getProcessName();
+        if (processName != null) {
+            return processName;
         }
 
         // Fallback to using CrashHandler's package name.
         return getJavaPackageName();
     }
 
     protected Context getAppContext() {
         return appContext;
@@ -218,20 +225,22 @@ public class CrashHandler implements Thr
      * @param thread The exception thread
      * @param exc An exception
      * @return "Extras" in the from of a Bundle
      */
     protected Bundle getCrashExtras(final Thread thread, final Throwable exc) {
         final Context context = getAppContext();
         final Bundle extras = new Bundle();
         final String pkgName = getAppPackageName();
+        final String processName = getProcessName();
 
         extras.putString("ProductName", pkgName);
         extras.putLong("CrashTime", getCrashTime());
         extras.putLong("StartupTime", getStartupTime());
+        extras.putString("AndroidProcessName", getProcessName());
 
         if (context != null) {
             final PackageManager pkgMgr = context.getPackageManager();
             try {
                 final PackageInfo pkgInfo = pkgMgr.getPackageInfo(pkgName, 0);
                 extras.putString("Version", pkgInfo.versionName);
                 extras.putInt("BuildID", pkgInfo.versionCode);
                 extras.putLong("InstallTime", pkgInfo.lastUpdateTime / 1000);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
@@ -492,16 +492,18 @@ public class GeckoThread extends Thread 
             final Context context = GeckoAppShell.getApplicationContext();
             mProfile = GeckoProfile.initFromArgs(context, mArgs);
         }
         return mProfile;
     }
 
     @Override
     public void run() {
+        Log.i(LOGTAG, "preparing to run Gecko");
+
         Looper.prepare();
         GeckoThread.msgQueue = Looper.myQueue();
         ThreadUtils.sGeckoThread = this;
         ThreadUtils.sGeckoHandler = new Handler();
 
         // Preparation for pumpMessageLoop()
         final MessageQueue.IdleHandler idleHandler = new MessageQueue.IdleHandler() {
             @Override public boolean queueIdle() {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java
@@ -76,38 +76,38 @@ public final class HardwareUtils {
         return sIsTelevision;
     }
 
     public static int getMemSize() {
         return SysInfo.getMemSize();
     }
 
     public static boolean isARMSystem() {
-        return Build.CPU_ABI != null && Build.CPU_ABI.startsWith("arm");
+        return Build.CPU_ABI != null && Build.CPU_ABI.equals("armeabi-v7a");
     }
 
     public static boolean isX86System() {
-        return Build.CPU_ABI != null && Build.CPU_ABI.startsWith("x86");
+        return Build.CPU_ABI != null && Build.CPU_ABI.equals("x86");
     }
 
     /**
      * @return false if the current system is not supported (e.g. APK/system ABI mismatch).
      */
     public static boolean isSupportedSystem() {
         // We've had crash reports from users on API 10 (with minSDK==15). That shouldn't even install,
         // but since it does we need to protect against it:
         if (Build.VERSION.SDK_INT < AppConstants.Versions.MIN_SDK_VERSION) {
             return false;
         }
 
         // See http://developer.android.com/ndk/guides/abis.html
         final boolean isSystemARM = isARMSystem();
         final boolean isSystemX86 = isX86System();
 
-        boolean isAppARM = BuildConfig.ANDROID_CPU_ARCH.startsWith("arm");
+        boolean isAppARM = BuildConfig.ANDROID_CPU_ARCH.startsWith("armeabi-v7a");
         boolean isAppX86 = BuildConfig.ANDROID_CPU_ARCH.startsWith("x86");
 
         // Only reject known incompatible ABIs. Better safe than sorry.
         if ((isSystemX86 && isAppARM) || (isSystemARM && isAppX86)) {
             return false;
         }
 
         if ((isSystemX86 && isAppX86) || (isSystemARM && isAppARM)) {
--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -3240,18 +3240,32 @@ nsStandardURL::Init(uint32_t urlType,
         NS_NOTREACHED("bad urlType");
         return NS_ERROR_INVALID_ARG;
     }
     mDefaultPort = defaultPort;
     mURLType = urlType;
 
     mOriginCharset.Truncate();
 
-    //if charset override is absent, use UTF8 as url encoding
-    if (charset != nullptr && *charset != '\0' && !IsUTFCharset(charset)) {
+    if (charset == nullptr || *charset == '\0') {
+        // check if baseURI provides an origin charset and use that.
+        if (baseURI)
+            baseURI->GetOriginCharset(mOriginCharset);
+
+        // URI can't be encoded in UTF-16, UTF-16BE, UTF-16LE, UTF-32,
+        // UTF-32-LE, UTF-32LE, UTF-32BE (yet?). Truncate mOriginCharset if
+        // it starts with "utf" (since an empty mOriginCharset implies
+        // UTF-8, this is safe even if mOriginCharset is UTF-8).
+
+        if (mOriginCharset.Length() > 3 &&
+            IsUTFCharset(mOriginCharset.get())) {
+            mOriginCharset.Truncate();
+        }
+    }
+    else if (!IsUTFCharset(charset)) {
         mOriginCharset = charset;
     }
 
     if (baseURI && net_IsAbsoluteURL(spec)) {
         baseURI = nullptr;
     }
 
     CALL_RUST_INIT;
--- a/netwerk/protocol/http/Http2HuffmanIncoming.h
+++ b/netwerk/protocol/http/Http2HuffmanIncoming.h
@@ -5,18 +5,18 @@
 #define mozilla__net__Http2HuffmanIncoming_h
 
 namespace mozilla {
 namespace net {
 
 struct HuffmanIncomingTable;
 
 struct HuffmanIncomingEntry {
-  const uint16_t mValue:9;      // 9 bits so it can hold 0..256
-  const uint16_t mPrefixLen:7;  // only holds 1..8
+  uint16_t mValue:9;      // 9 bits so it can hold 0..256
+  uint16_t mPrefixLen:7;  // only holds 1..8
 };
 
 // The data members are public only so they can be statically constructed. All
 // accesses should be done through the functions.
 struct HuffmanIncomingTable {
   // The normal entries, for indices in the range 0..(mNumEntries-1).
   const HuffmanIncomingEntry* const mEntries;
 
--- a/netwerk/protocol/http/Http2HuffmanOutgoing.h
+++ b/netwerk/protocol/http/Http2HuffmanOutgoing.h
@@ -7,17 +7,17 @@
 namespace mozilla {
 namespace net {
 
 struct HuffmanOutgoingEntry {
   uint32_t mValue;
   uint8_t mLength;
 };
 
-static HuffmanOutgoingEntry HuffmanOutgoing[] = {
+static const HuffmanOutgoingEntry HuffmanOutgoing[] = {
   { 0x00001ff8, 13 },
   { 0x007fffd8, 23 },
   { 0x0fffffe2, 28 },
   { 0x0fffffe3, 28 },
   { 0x0fffffe4, 28 },
   { 0x0fffffe5, 28 },
   { 0x0fffffe6, 28 },
   { 0x0fffffe7, 28 },
--- a/netwerk/protocol/http/make_incoming_tables.py
+++ b/netwerk/protocol/http/make_incoming_tables.py
@@ -139,18 +139,18 @@ sys.stdout.write('''/*
 #define mozilla__net__Http2HuffmanIncoming_h
 
 namespace mozilla {
 namespace net {
 
 struct HuffmanIncomingTable;
 
 struct HuffmanIncomingEntry {
-  const uint16_t mValue:9;      // 9 bits so it can hold 0..256
-  const uint16_t mPrefixLen:7;  // only holds 1..8
+  uint16_t mValue:9;      // 9 bits so it can hold 0..256
+  uint16_t mPrefixLen:7;  // only holds 1..8
 };
 
 // The data members are public only so they can be statically constructed. All
 // accesses should be done through the functions.
 struct HuffmanIncomingTable {
   // The normal entries, for indices in the range 0..(mNumEntries-1).
   const HuffmanIncomingEntry* const mEntries;
 
--- a/netwerk/protocol/http/make_outgoing_tables.py
+++ b/netwerk/protocol/http/make_outgoing_tables.py
@@ -15,17 +15,17 @@ sys.stdout.write('''/*
 namespace mozilla {
 namespace net {
 
 struct HuffmanOutgoingEntry {
   uint32_t mValue;
   uint8_t mLength;
 };
 
-static HuffmanOutgoingEntry HuffmanOutgoing[] = {
+static const HuffmanOutgoingEntry HuffmanOutgoing[] = {
 ''')
 
 entries = []
 for line in sys.stdin:
     line = line.strip()
     obracket = line.rfind('[')
     nbits = int(line[obracket + 1:-1])
 
--- a/old-configure.in
+++ b/old-configure.in
@@ -5339,24 +5339,17 @@ fi
 dnl win32 options
 AC_SUBST(WIN32_REDIST_DIR)
 AC_SUBST(WIN_UCRT_REDIST_DIR)
 
 dnl ========================================================
 dnl ICU Support
 dnl ========================================================
 
-# Internationalization is not built or exposed on Fennec.
-# See Bug 1215256
-
-if test "$MOZ_BUILD_APP" = "mobile/android"; then
-    _INTL_API=no
-else
-    _INTL_API=yes
-fi
+_INTL_API=yes
 
 if test "$MOZ_WIDGET_TOOLKIT" = "cocoa"; then
     USE_ICU=1
 fi
 
 MOZ_CONFIG_ICU()
 
 dnl Echo the CFLAGS to remove extra whitespace.
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-0750d7a0402b
+e3bca65235d5
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/gtests/common/scoped_ptrs.h
+++ b/security/nss/gtests/common/scoped_ptrs.h
@@ -20,16 +20,17 @@ struct ScopedDelete {
     CERT_DestroyCertificateList(list);
   }
   void operator()(CERTCertList* list) { CERT_DestroyCertList(list); }
   void operator()(CERTSubjectPublicKeyInfo* spki) {
     SECKEY_DestroySubjectPublicKeyInfo(spki);
   }
   void operator()(PK11SlotInfo* slot) { PK11_FreeSlot(slot); }
   void operator()(PK11SymKey* key) { PK11_FreeSymKey(key); }
+  void operator()(PRFileDesc* fd) { PR_Close(fd); }
   void operator()(SECAlgorithmID* id) { SECOID_DestroyAlgorithmID(id, true); }
   void operator()(SECItem* item) { SECITEM_FreeItem(item, true); }
   void operator()(SECKEYPublicKey* key) { SECKEY_DestroyPublicKey(key); }
   void operator()(SECKEYPrivateKey* key) { SECKEY_DestroyPrivateKey(key); }
 };
 
 template <class T>
 struct ScopedMaybeDelete {
@@ -44,16 +45,17 @@ struct ScopedMaybeDelete {
 #define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDelete<x> > Scoped##x
 
 SCOPED(CERTCertificate);
 SCOPED(CERTCertificateList);
 SCOPED(CERTCertList);
 SCOPED(CERTSubjectPublicKeyInfo);
 SCOPED(PK11SlotInfo);
 SCOPED(PK11SymKey);
+SCOPED(PRFileDesc);
 SCOPED(SECAlgorithmID);
 SCOPED(SECItem);
 SCOPED(SECKEYPublicKey);
 SCOPED(SECKEYPrivateKey);
 
 #undef SCOPED
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/gtest_utils.h
+++ b/security/nss/gtests/ssl_gtest/gtest_utils.h
@@ -29,17 +29,17 @@ class Timeout : public PollTarget {
   static void ExpiredCallback(PollTarget* target, Event event) {
     Timeout* timeout = static_cast<Timeout*>(target);
     timeout->handle_ = nullptr;
   }
 
   bool timed_out() const { return !handle_; }
 
  private:
-  Poller::Timer* handle_;
+  std::shared_ptr<Poller::Timer> handle_;
 };
 
 }  // namespace nss_test
 
 #define WAIT_(expression, timeout) \
   do {                             \
     Timeout tm(timeout);           \
     while (!(expression)) {        \
--- a/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_agent_unittest.cc
@@ -153,18 +153,18 @@ TEST_F(TlsAgentDgramTestClient, Encrypte
 }
 
 TEST_F(TlsAgentStreamTestClient, Set0RttOptionThenWrite) {
   EnsureInit();
   agent_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                           SSL_LIBRARY_VERSION_TLS_1_3);
   agent_->StartConnect();
   agent_->Set0RttEnabled(true);
-  auto filter =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeClientHello);
+  auto filter = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeClientHello);
   agent_->SetPacketFilter(filter);
   PRInt32 rv = PR_Write(agent_->ssl_fd(), k0RttData, strlen(k0RttData));
   EXPECT_EQ(-1, rv);
   int32_t err = PORT_GetError();
   EXPECT_EQ(PR_WOULD_BLOCK_ERROR, err);
   EXPECT_LT(0UL, filter->buffer().len());
 }
 
--- a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc
@@ -72,36 +72,37 @@ TEST_P(TlsConnectGeneric, ClientAuthBigR
   Reset(TlsAgent::kServerRsa, TlsAgent::kRsa2048);
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
   CheckKeys();
 }
 
 // Offset is the position in the captured buffer where the signature sits.
-static void CheckSigScheme(TlsInspectorRecordHandshakeMessage* capture,
-                           size_t offset, TlsAgent* peer,
-                           uint16_t expected_scheme, size_t expected_size) {
+static void CheckSigScheme(
+    std::shared_ptr<TlsInspectorRecordHandshakeMessage>& capture, size_t offset,
+    std::shared_ptr<TlsAgent>& peer, uint16_t expected_scheme,
+    size_t expected_size) {
   EXPECT_LT(offset + 2U, capture->buffer().len());
 
   uint32_t scheme = 0;
   capture->buffer().Read(offset, 2, &scheme);
   EXPECT_EQ(expected_scheme, static_cast<uint16_t>(scheme));
 
   ScopedCERTCertificate remote_cert(SSL_PeerCertificate(peer->ssl_fd()));
   ScopedSECKEYPublicKey remote_key(CERT_ExtractPublicKey(remote_cert.get()));
   EXPECT_EQ(expected_size, SECKEY_PublicKeyStrengthInBits(remote_key.get()));
 }
 
 // The server should prefer SHA-256 by default, even for the small key size used
 // in the default certificate.
 TEST_P(TlsConnectTls12, ServerAuthCheckSigAlg) {
   EnsureTlsSetup();
-  auto capture_ske =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+  auto capture_ske = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(capture_ske);
   Connect();
   CheckKeys();
 
   const DataBuffer& buffer = capture_ske->buffer();
   EXPECT_LT(3U, buffer.len());
   EXPECT_EQ(3U, buffer.data()[0]) << "curve_type == named_curve";
   uint32_t tmp;
@@ -109,30 +110,32 @@ TEST_P(TlsConnectTls12, ServerAuthCheckS
   EXPECT_EQ(ssl_grp_ec_curve25519, tmp);
   EXPECT_TRUE(buffer.Read(3, 1, &tmp)) << " read ECPoint";
   CheckSigScheme(capture_ske, 4 + tmp, client_, ssl_sig_rsa_pss_sha256, 1024);
 }
 
 TEST_P(TlsConnectTls12, ClientAuthCheckSigAlg) {
   EnsureTlsSetup();
   auto capture_cert_verify =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeCertificateVerify);
+      std::make_shared<TlsInspectorRecordHandshakeMessage>(
+          kTlsHandshakeCertificateVerify);
   client_->SetPacketFilter(capture_cert_verify);
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
   CheckKeys();
 
   CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pkcs1_sha1, 1024);
 }
 
 TEST_P(TlsConnectTls12, ClientAuthBigRsaCheckSigAlg) {
   Reset(TlsAgent::kServerRsa, TlsAgent::kRsa2048);
   auto capture_cert_verify =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeCertificateVerify);
+      std::make_shared<TlsInspectorRecordHandshakeMessage>(
+          kTlsHandshakeCertificateVerify);
   client_->SetPacketFilter(capture_cert_verify);
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   Connect();
   CheckKeys();
   CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_sha256, 2048);
 }
 
@@ -181,20 +184,21 @@ class TlsZeroCertificateRequestSigAlgsFi
     return CHANGE;
   }
 };
 
 // Check that we fall back to SHA-1 when the server doesn't provide any
 // supported_signature_algorithms in the CertificateRequest message.
 TEST_P(TlsConnectTls12, ClientAuthNoSigAlgsFallback) {
   EnsureTlsSetup();
-  auto filter = new TlsZeroCertificateRequestSigAlgsFilter();
+  auto filter = std::make_shared<TlsZeroCertificateRequestSigAlgsFilter>();
   server_->SetPacketFilter(filter);
   auto capture_cert_verify =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeCertificateVerify);
+      std::make_shared<TlsInspectorRecordHandshakeMessage>(
+          kTlsHandshakeCertificateVerify);
   client_->SetPacketFilter(capture_cert_verify);
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
 
   ConnectExpectFail();
 
   // We're expecting a bad signature here because we tampered with a handshake
   // message (CertReq). Previously, without the SHA-1 fallback, we would've
@@ -334,27 +338,27 @@ TEST_P(TlsConnectPre12, SignatureAlgorit
   server_->SetSignatureSchemes(SignatureSchemeEcdsaSha256,
                                PR_ARRAY_SIZE(SignatureSchemeEcdsaSha256));
   Connect();
 }
 
 // The signature_algorithms extension is mandatory in TLS 1.3.
 TEST_P(TlsConnectTls13, SignatureAlgorithmDrop) {
   client_->SetPacketFilter(
-      new TlsExtensionDropper(ssl_signature_algorithms_xtn));
+      std::make_shared<TlsExtensionDropper>(ssl_signature_algorithms_xtn));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
   server_->CheckErrorCode(SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION);
 }
 
 // TLS 1.2 has trouble detecting this sort of modification: it uses SHA1 and
 // only fails when the Finished is checked.
 TEST_P(TlsConnectTls12, SignatureAlgorithmDrop) {
   client_->SetPacketFilter(
-      new TlsExtensionDropper(ssl_signature_algorithms_xtn));
+      std::make_shared<TlsExtensionDropper>(ssl_signature_algorithms_xtn));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 }
 
 TEST_P(TlsConnectTls12Plus, RequestClientAuthWithSha384) {
   server_->SetSignatureSchemes(SignatureSchemeRsaSha384,
                                PR_ARRAY_SIZE(SignatureSchemeRsaSha384));
@@ -362,17 +366,18 @@ TEST_P(TlsConnectTls12Plus, RequestClien
   Connect();
 }
 
 class BeforeFinished : public TlsRecordFilter {
  private:
   enum HandshakeState { BEFORE_CCS, AFTER_CCS, DONE };
 
  public:
-  BeforeFinished(TlsAgent* client, TlsAgent* server, VoidFunction before_ccs,
+  BeforeFinished(std::shared_ptr<TlsAgent>& client,
+                 std::shared_ptr<TlsAgent>& server, VoidFunction before_ccs,
                  VoidFunction before_finished)
       : client_(client),
         server_(server),
         before_ccs_(before_ccs),
         before_finished_(before_finished),
         state_(BEFORE_CCS) {}
 
  protected:
@@ -385,18 +390,18 @@ class BeforeFinished : public TlsRecordF
         if (header.content_type() == kTlsChangeCipherSpecType) {
           before_ccs_();
 
           // Write the CCS out as a separate write, so that we can make
           // progress. Ordinarily, libssl sends the CCS and Finished together,
           // but that means that they both get processed together.
           DataBuffer ccs;
           header.Write(&ccs, 0, body);
-          server_->SendDirect(ccs);
-          client_->Handshake();
+          server_.lock()->SendDirect(ccs);
+          client_.lock()->Handshake();
           state_ = AFTER_CCS;
           // Request that the original record be dropped by the filter.
           return DROP;
         }
         break;
 
       case AFTER_CCS:
         EXPECT_EQ(kTlsHandshakeType, header.content_type());
@@ -409,18 +414,18 @@ class BeforeFinished : public TlsRecordF
 
       case DONE:
         break;
     }
     return KEEP;
   }
 
  private:
-  TlsAgent* client_;
-  TlsAgent* server_;
+  std::weak_ptr<TlsAgent> client_;
+  std::weak_ptr<TlsAgent> server_;
   VoidFunction before_ccs_;
   VoidFunction before_finished_;
   HandshakeState state_;
 };
 
 // Running code after the client has started processing the encrypted part of
 // the server's first flight, but before the Finished is processed is very hard
 // in TLS 1.3.  These encrypted messages are sent in a single encrypted blob.
@@ -435,113 +440,116 @@ class BeforeFinished13 : public PacketFi
   enum HandshakeState {
     INIT,
     BEFORE_FIRST_FRAGMENT,
     BEFORE_SECOND_FRAGMENT,
     DONE
   };
 
  public:
-  BeforeFinished13(TlsAgent* client, TlsAgent* server,
+  BeforeFinished13(std::shared_ptr<TlsAgent>& client,
+                   std::shared_ptr<TlsAgent>& server,
                    VoidFunction before_finished)
       : client_(client),
         server_(server),
         before_finished_(before_finished),
         records_(0) {}
 
  protected:
   virtual PacketFilter::Action Filter(const DataBuffer& input,
                                       DataBuffer* output) {
     switch (++records_) {
       case 1:
         // Packet 1 is the server's entire first flight.  Drop it.
         EXPECT_EQ(SECSuccess,
-                  SSLInt_SetMTU(server_->ssl_fd(), input.len() - 1));
+                  SSLInt_SetMTU(server_.lock()->ssl_fd(), input.len() - 1));
         return DROP;
 
       // Packet 2 is the first part of the server's retransmitted first
       // flight.  Keep that.
 
       case 3:
         // Packet 3 is the second part of the server's retransmitted first
         // flight.  Before passing that on, make sure that the client processes
         // packet 2, then call the before_finished_() callback.
-        client_->Handshake();
+        client_.lock()->Handshake();
         before_finished_();
         break;
 
       default:
         break;
     }
     return KEEP;
   }
 
  private:
-  TlsAgent* client_;
-  TlsAgent* server_;
+  std::weak_ptr<TlsAgent> client_;
+  std::weak_ptr<TlsAgent> server_;
   VoidFunction before_finished_;
   size_t records_;
 };
 
 static SECStatus AuthCompleteBlock(TlsAgent*, PRBool, PRBool) {
   return SECWouldBlock;
 }
 
 // This test uses an AuthCertificateCallback that blocks.  A filter is used to
 // split the server's first flight into two pieces.  Before the second piece is
 // processed by the client, SSL_AuthCertificateComplete() is called.
 TEST_F(TlsConnectDatagram13, AuthCompleteBeforeFinished) {
   client_->SetAuthCertificateCallback(AuthCompleteBlock);
-  server_->SetPacketFilter(new BeforeFinished13(client_, server_, [this]() {
-    EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
-  }));
+  server_->SetPacketFilter(
+      std::make_shared<BeforeFinished13>(client_, server_, [this]() {
+        EXPECT_EQ(SECSuccess,
+                  SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
+      }));
   Connect();
 }
 
 static void TriggerAuthComplete(PollTarget* target, Event event) {
   std::cerr << "client: call SSL_AuthCertificateComplete" << std::endl;
   EXPECT_EQ(TIMER_EVENT, event);
   TlsAgent* client = static_cast<TlsAgent*>(target);
   EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client->ssl_fd(), 0));
 }
 
 // This test uses a simple AuthCertificateCallback.  Due to the way that the
 // entire server flight is processed, the call to SSL_AuthCertificateComplete
 // will trigger after the Finished message is processed.
 TEST_F(TlsConnectDatagram13, AuthCompleteAfterFinished) {
   client_->SetAuthCertificateCallback(
       [this](TlsAgent*, PRBool, PRBool) -> SECStatus {
-        Poller::Timer* timer_handle;
+        std::shared_ptr<Poller::Timer> timer_handle;
         // This is really just to unroll the stack.
-        Poller::Instance()->SetTimer(1U, client_, TriggerAuthComplete,
+        Poller::Instance()->SetTimer(1U, client_.get(), TriggerAuthComplete,
                                      &timer_handle);
         return SECWouldBlock;
       });
   Connect();
 }
 
 TEST_P(TlsConnectGenericPre13, ClientWriteBetweenCCSAndFinishedWithFalseStart) {
   client_->EnableFalseStart();
-  server_->SetPacketFilter(new BeforeFinished(
+  server_->SetPacketFilter(std::make_shared<BeforeFinished>(
       client_, server_,
       [this]() { EXPECT_TRUE(client_->can_falsestart_hook_called()); },
       [this]() {
         // Write something, which used to fail: bug 1235366.
         client_->SendData(10);
       }));
 
   Connect();
   server_->SendData(10);
   Receive(10);
 }
 
 TEST_P(TlsConnectGenericPre13, AuthCompleteBeforeFinishedWithFalseStart) {
   client_->EnableFalseStart();
   client_->SetAuthCertificateCallback(AuthCompleteBlock);
-  server_->SetPacketFilter(new BeforeFinished(
+  server_->SetPacketFilter(std::make_shared<BeforeFinished>(
       client_, server_,
       []() {
         // Do nothing before CCS
       },
       [this]() {
         EXPECT_FALSE(client_->can_falsestart_hook_called());
         // AuthComplete before Finished still enables false start.
         EXPECT_EQ(SECSuccess,
@@ -578,17 +586,17 @@ TEST_P(TlsConnectGenericPre13, AuthCompl
   client_->Handshake();  // Send ClientHello
   server_->Handshake();  // Send ServerHello
   client_->Handshake();  // Send ClientKeyExchange and Finished
   server_->Handshake();  // Send Finished
   // The server should now report that it is connected
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
 
   // The client should send nothing from here on.
-  client_->SetPacketFilter(new EnforceNoActivity());
+  client_->SetPacketFilter(std::make_shared<EnforceNoActivity>());
   client_->Handshake();
   EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
 
   // This should allow the handshake to complete now.
   EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
   client_->Handshake();  // Transition to connected
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
@@ -605,17 +613,17 @@ TEST_P(TlsConnectTls13, AuthCompleteDela
   server_->StartConnect();
   client_->StartConnect();
   client_->Handshake();  // Send ClientHello
   server_->Handshake();  // Send ServerHello
   EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
   EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
 
   // The client will send nothing until AuthCertificateComplete is called.
-  client_->SetPacketFilter(new EnforceNoActivity());
+  client_->SetPacketFilter(std::make_shared<EnforceNoActivity>());
   client_->Handshake();
   EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
 
   // This should allow the handshake to complete now.
   client_->DeletePacketFilter();
   EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
   client_->Handshake();  // Send Finished
   server_->Handshake();  // Transition to connected and send NewSessionTicket
@@ -719,17 +727,17 @@ class TlsSignatureSchemeConfiguration
  public:
   TlsSignatureSchemeConfiguration()
       : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())),
         certificate_(std::get<2>(GetParam())),
         auth_type_(std::get<3>(GetParam())),
         signature_scheme_(std::get<4>(GetParam())) {}
 
  protected:
-  void TestSignatureSchemeConfig(TlsAgent* configPeer) {
+  void TestSignatureSchemeConfig(std::shared_ptr<TlsAgent>& configPeer) {
     EnsureTlsSetup();
     configPeer->SetSignatureSchemes(&signature_scheme_, 1);
     Connect();
     CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, auth_type_,
               signature_scheme_);
   }
 
   std::string certificate_;
@@ -739,18 +747,18 @@ class TlsSignatureSchemeConfiguration
 
 TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigServer) {
   Reset(certificate_);
   TestSignatureSchemeConfig(server_);
 }
 
 TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigClient) {
   Reset(certificate_);
-  TlsExtensionCapture* capture =
-      new TlsExtensionCapture(ssl_signature_algorithms_xtn);
+  auto capture =
+      std::make_shared<TlsExtensionCapture>(ssl_signature_algorithms_xtn);
   client_->SetPacketFilter(capture);
   TestSignatureSchemeConfig(client_);
 
   const DataBuffer& ext = capture->extension();
   ASSERT_EQ(2U + 2U, ext.len());
   uint32_t v = 0;
   ASSERT_TRUE(ext.Read(0, 2, &v));
   EXPECT_EQ(2U, v);
--- a/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_cert_ext_unittest.cc
@@ -18,47 +18,49 @@ namespace nss_test {
 
 // Tests for Certificate Transparency (RFC 6962)
 // These don't work with TLS 1.3: see bug 1252745.
 
 // Helper class - stores signed certificate timestamps as provided
 // by the relevant callbacks on the client.
 class SignedCertificateTimestampsExtractor {
  public:
-  SignedCertificateTimestampsExtractor(TlsAgent* client) : client_(client) {
-    client_->SetAuthCertificateCallback(
-        [&](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus {
+  SignedCertificateTimestampsExtractor(std::shared_ptr<TlsAgent>& client)
+      : client_(client) {
+    client->SetAuthCertificateCallback(
+        [this](TlsAgent* agent, bool checksig, bool isServer) -> SECStatus {
           const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd());
           EXPECT_TRUE(scts);
           if (!scts) {
             return SECFailure;
           }
           auth_timestamps_.reset(new DataBuffer(scts->data, scts->len));
           return SECSuccess;
         });
-    client_->SetHandshakeCallback([&](TlsAgent* agent) {
+    client->SetHandshakeCallback([this](TlsAgent* agent) {
       const SECItem* scts = SSL_PeerSignedCertTimestamps(agent->ssl_fd());
       ASSERT_TRUE(scts);
       handshake_timestamps_.reset(new DataBuffer(scts->data, scts->len));
     });
   }
 
   void assertTimestamps(const DataBuffer& timestamps) {
     EXPECT_TRUE(auth_timestamps_);
     EXPECT_EQ(timestamps, *auth_timestamps_);
 
     EXPECT_TRUE(handshake_timestamps_);
     EXPECT_EQ(timestamps, *handshake_timestamps_);
 
-    const SECItem* current = SSL_PeerSignedCertTimestamps(client_->ssl_fd());
+    const SECItem* current =
+        SSL_PeerSignedCertTimestamps(client_.lock()->ssl_fd());
     EXPECT_EQ(timestamps, DataBuffer(current->data, current->len));
   }
 
  private:
-  TlsAgent* client_;
+  std::weak_ptr<TlsAgent> client_;
   std::unique_ptr<DataBuffer> auth_timestamps_;
   std::unique_ptr<DataBuffer> handshake_timestamps_;
 };
 
 static const uint8_t kSctValue[] = {0x01, 0x23, 0x45, 0x67, 0x89};
 static const SECItem kSctItem = {siBuffer, const_cast<uint8_t*>(kSctValue),
                                  sizeof(kSctValue)};
 static const DataBuffer kSctBuffer(kSctValue, sizeof(kSctValue));
@@ -180,29 +182,30 @@ TEST_P(TlsConnectGeneric, OcspNotProvide
 TEST_P(TlsConnectGenericPre13, OcspMangled) {
   EnsureTlsSetup();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_ENABLE_OCSP_STAPLING, PR_TRUE));
   EXPECT_TRUE(
       server_->ConfigServerCert(TlsAgent::kServerRsa, true, &kOcspExtraData));
 
   static const uint8_t val[] = {1};
-  auto replacer = new TlsExtensionReplacer(ssl_cert_status_xtn,
-                                           DataBuffer(val, sizeof(val)));
+  auto replacer = std::make_shared<TlsExtensionReplacer>(
+      ssl_cert_status_xtn, DataBuffer(val, sizeof(val)));
   server_->SetPacketFilter(replacer);
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 TEST_P(TlsConnectGeneric, OcspSuccess) {
   EnsureTlsSetup();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_ENABLE_OCSP_STAPLING, PR_TRUE));
-  auto capture_ocsp = new TlsExtensionCapture(ssl_cert_status_xtn);
+  auto capture_ocsp =
+      std::make_shared<TlsExtensionCapture>(ssl_cert_status_xtn);
   server_->SetPacketFilter(capture_ocsp);
 
   // The value should be available during the AuthCertificateCallback
   client_->SetAuthCertificateCallback([](TlsAgent* agent, bool checksig,
                                          bool isServer) -> SECStatus {
     const SECItemArray* ocsp = SSL_PeerStapledOCSPResponses(agent->ssl_fd());
     if (!ocsp) {
       return SECFailure;
--- a/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_damage_unittest.cc
@@ -44,17 +44,17 @@ TEST_F(TlsConnectTest, DamageSecretHandl
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
 }
 
 TEST_F(TlsConnectTest, DamageSecretHandleServerFinished) {
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
                            SSL_LIBRARY_VERSION_TLS_1_3);
-  server_->SetPacketFilter(new AfterRecordN(
+  server_->SetPacketFilter(std::make_shared<AfterRecordN>(
       server_, client_,
       0,  // ServerHello.
       [this]() { SSLInt_DamageServerHsTrafficSecret(client_->ssl_fd()); }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
   server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
 }
 
--- a/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_dhe_unittest.cc
@@ -26,22 +26,23 @@ TEST_P(TlsConnectGeneric, ConnectDhe) {
   CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
 }
 
 TEST_P(TlsConnectTls13, SharesForBothEcdheAndDhe) {
   EnsureTlsSetup();
   client_->ConfigNamedGroups(kAllDHEGroups);
 
-  auto groups_capture = new TlsExtensionCapture(ssl_supported_groups_xtn);
-  auto shares_capture = new TlsExtensionCapture(ssl_tls13_key_share_xtn);
-  std::vector<PacketFilter*> captures;
-  captures.push_back(groups_capture);
-  captures.push_back(shares_capture);
-  client_->SetPacketFilter(new ChainedPacketFilter(captures));
+  auto groups_capture =
+      std::make_shared<TlsExtensionCapture>(ssl_supported_groups_xtn);
+  auto shares_capture =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn);
+  std::vector<std::shared_ptr<PacketFilter>> captures = {groups_capture,
+                                                         shares_capture};
+  client_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(captures));
 
   Connect();
 
   CheckKeys();
 
   bool ec, dh;
   auto track_group_type = [&ec, &dh](SSLNamedGroup group) {
     if ((group & 0xff00U) == 0x100U) {
@@ -55,22 +56,23 @@ TEST_P(TlsConnectTls13, SharesForBothEcd
   EXPECT_TRUE(ec) << "Should include an EC group and share";
   EXPECT_TRUE(dh) << "Should include an FFDHE group and share";
 }
 
 TEST_P(TlsConnectGeneric, ConnectFfdheClient) {
   EnableOnlyDheCiphers();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
-  auto groups_capture = new TlsExtensionCapture(ssl_supported_groups_xtn);
-  auto shares_capture = new TlsExtensionCapture(ssl_tls13_key_share_xtn);
-  std::vector<PacketFilter*> captures;
-  captures.push_back(groups_capture);
-  captures.push_back(shares_capture);
-  client_->SetPacketFilter(new ChainedPacketFilter(captures));
+  auto groups_capture =
+      std::make_shared<TlsExtensionCapture>(ssl_supported_groups_xtn);
+  auto shares_capture =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn);
+  std::vector<std::shared_ptr<PacketFilter>> captures = {groups_capture,
+                                                         shares_capture};
+  client_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(captures));
 
   Connect();
 
   CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
   auto is_ffdhe = [](SSLNamedGroup group) {
     // The group has to be in this range.
     EXPECT_LE(ssl_grp_ffdhe_2048, group);
     EXPECT_GE(ssl_grp_ffdhe_8192, group);
@@ -121,17 +123,17 @@ class TlsDheServerKeyExchangeDamager : p
 
 // Changing the prime in the server's key share results in an error.  This will
 // invalidate the signature over the ServerKeyShare. That's ok, NSS won't check
 // the signature until everything else has been checked.
 TEST_P(TlsConnectGenericPre13, DamageServerKeyShare) {
   EnableOnlyDheCiphers();
   EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                       SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
-  server_->SetPacketFilter(new TlsDheServerKeyExchangeDamager());
+  server_->SetPacketFilter(std::make_shared<TlsDheServerKeyExchangeDamager>());
 
   ConnectExpectFail();
 
   client_->CheckErrorCode(SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 class TlsDheSkeChangeY : public TlsHandshakeFilter {
@@ -244,34 +246,35 @@ class TlsDheSkeChangeYServer : public Tl
 
  private:
   bool modify_;
   DataBuffer p_;
 };
 
 class TlsDheSkeChangeYClient : public TlsDheSkeChangeY {
  public:
-  TlsDheSkeChangeYClient(ChangeYTo change,
-                         const TlsDheSkeChangeYServer* server_filter)
+  TlsDheSkeChangeYClient(
+      ChangeYTo change,
+      std::shared_ptr<const TlsDheSkeChangeYServer> server_filter)
       : TlsDheSkeChangeY(change), server_filter_(server_filter) {}
 
  protected:
   virtual PacketFilter::Action FilterHandshake(
       const TlsHandshakeFilter::HandshakeHeader& header,
       const DataBuffer& input, DataBuffer* output) override {
     if (header.handshake_type() != kTlsHandshakeClientKeyExchange) {
       return KEEP;
     }
 
     ChangeY(input, output, 0, server_filter_->prime());
     return CHANGE;
   }
 
  private:
-  const TlsDheSkeChangeYServer* server_filter_;
+  std::shared_ptr<const TlsDheSkeChangeYServer> server_filter_;
 };
 
 /* This matrix includes: mode (stream/datagram), TLS version, what change to
  * make to dh_Ys, whether the client will be configured to require DH named
  * groups.  Test all combinations. */
 typedef std::tuple<std::string, uint16_t, TlsDheSkeChangeY::ChangeYTo, bool>
     DamageDHYProfile;
 class TlsDamageDHYTest
@@ -284,17 +287,18 @@ class TlsDamageDHYTest
 
 TEST_P(TlsDamageDHYTest, DamageServerY) {
   EnableOnlyDheCiphers();
   if (std::get<3>(GetParam())) {
     EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                         SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
   }
   TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
-  server_->SetPacketFilter(new TlsDheSkeChangeYServer(change, true));
+  server_->SetPacketFilter(
+      std::make_shared<TlsDheSkeChangeYServer>(change, true));
 
   ConnectExpectFail();
   if (change == TlsDheSkeChangeY::kYZeroPad) {
     // Zero padding Y only manifests in a signature failure.
     // In TLS 1.0 and 1.1, the client reports a device error.
     if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
       client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR);
     } else {
@@ -309,23 +313,24 @@ TEST_P(TlsDamageDHYTest, DamageServerY) 
 
 TEST_P(TlsDamageDHYTest, DamageClientY) {
   EnableOnlyDheCiphers();
   if (std::get<3>(GetParam())) {
     EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
                                         SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE));
   }
   // The filter on the server is required to capture the prime.
-  TlsDheSkeChangeYServer* server_filter =
-      new TlsDheSkeChangeYServer(TlsDheSkeChangeY::kYZero, false);
+  auto server_filter =
+      std::make_shared<TlsDheSkeChangeYServer>(TlsDheSkeChangeY::kYZero, false);
   server_->SetPacketFilter(server_filter);
 
   // The client filter does the damage.
   TlsDheSkeChangeY::ChangeYTo change = std::get<2>(GetParam());
-  client_->SetPacketFilter(new TlsDheSkeChangeYClient(change, server_filter));
+  client_->SetPacketFilter(
+      std::make_shared<TlsDheSkeChangeYClient>(change, server_filter));
 
   ConnectExpectFail();
   if (change == TlsDheSkeChangeY::kYZeroPad) {
     // Zero padding Y only manifests in a finished error.
     client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
     server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
   } else {
     client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
@@ -373,17 +378,17 @@ class TlsDheSkeMakePEven : public TlsHan
 
     return CHANGE;
   }
 };
 
 // Even without requiring named groups, an even value for p is bad news.
 TEST_P(TlsConnectGenericPre13, MakeDhePEven) {
   EnableOnlyDheCiphers();
-  server_->SetPacketFilter(new TlsDheSkeMakePEven());
+  server_->SetPacketFilter(std::make_shared<TlsDheSkeMakePEven>());
 
   ConnectExpectFail();
 
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_DHE_KEY_SHARE);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 class TlsDheSkeZeroPadP : public TlsHandshakeFilter {
@@ -404,17 +409,17 @@ class TlsDheSkeZeroPadP : public TlsHand
 
     return CHANGE;
   }
 };
 
 // Zero padding only causes signature failure.
 TEST_P(TlsConnectGenericPre13, PadDheP) {
   EnableOnlyDheCiphers();
-  server_->SetPacketFilter(new TlsDheSkeZeroPadP());
+  server_->SetPacketFilter(std::make_shared<TlsDheSkeZeroPadP>());
 
   ConnectExpectFail();
 
   // In TLS 1.0 and 1.1, the client reports a device error.
   if (version_ < SSL_LIBRARY_VERSION_TLS_1_2) {
     client_->CheckErrorCode(SEC_ERROR_PKCS11_DEVICE_ERROR);
   } else {
     client_->CheckErrorCode(SEC_ERROR_BAD_SIGNATURE);
@@ -528,21 +533,21 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   Connect();
   SendReceive();  // Need to read so that we absorb the session ticket.
   CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   EnableOnlyDheCiphers();
-  TlsExtensionCapture* clientCapture =
-      new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+  auto clientCapture =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
   client_->SetPacketFilter(clientCapture);
-  TlsExtensionCapture* serverCapture =
-      new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+  auto serverCapture =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
   server_->SetPacketFilter(serverCapture);
   ExpectResumption(RESUME_TICKET);
   Connect();
   CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign, ssl_sig_none);
   ASSERT_LT(0UL, clientCapture->extension().len());
   ASSERT_LT(0UL, serverCapture->extension().len());
 }
 
@@ -594,16 +599,16 @@ TEST_P(TlsConnectGenericPre13, InvalidDE
       0x6d, 0xdc, 0xb8, 0x21, 0x87, 0xdd, 0x0d, 0xb9, 0x46, 0x09, 0x3e,
       0xef, 0x81, 0x5b, 0x37, 0x09, 0x39, 0xeb};
 
   Reset(TlsAgent::kServerDsa);
 
   const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ffdhe_2048};
   client_->ConfigNamedGroups(client_groups);
 
-  server_->SetPacketFilter(new TlsDheSkeChangeSignature(
+  server_->SetPacketFilter(std::make_shared<TlsDheSkeChangeSignature>(
       version_, kBogusDheSignature, sizeof(kBogusDheSignature)));
 
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 }
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_drop_unittest.cc
@@ -16,57 +16,57 @@ extern "C" {
 #include "scoped_ptrs.h"
 #include "tls_connect.h"
 #include "tls_filter.h"
 #include "tls_parser.h"
 
 namespace nss_test {
 
 TEST_P(TlsConnectDatagram, DropClientFirstFlightOnce) {
-  client_->SetPacketFilter(new SelectiveDropFilter(0x1));
+  client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x1));
   Connect();
   SendReceive();
 }
 
 TEST_P(TlsConnectDatagram, DropServerFirstFlightOnce) {
-  server_->SetPacketFilter(new SelectiveDropFilter(0x1));
+  server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x1));
   Connect();
   SendReceive();
 }
 
 // This drops the first transmission from both the client and server of all
 // flights that they send.  Note: In DTLS 1.3, the shorter handshake means that
 // this will also drop some application data, so we can't call SendReceive().
 TEST_P(TlsConnectDatagram, DropAllFirstTransmissions) {
-  client_->SetPacketFilter(new SelectiveDropFilter(0x15));
-  server_->SetPacketFilter(new SelectiveDropFilter(0x5));
+  client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x15));
+  server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x5));
   Connect();
 }
 
 // This drops the server's first flight three times.
 TEST_P(TlsConnectDatagram, DropServerFirstFlightThrice) {
-  server_->SetPacketFilter(new SelectiveDropFilter(0x7));
+  server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x7));
   Connect();
 }
 
 // This drops the client's second flight once
 TEST_P(TlsConnectDatagram, DropClientSecondFlightOnce) {
-  client_->SetPacketFilter(new SelectiveDropFilter(0x2));
+  client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x2));
   Connect();
 }
 
 // This drops the client's second flight three times.
 TEST_P(TlsConnectDatagram, DropClientSecondFlightThrice) {
-  client_->SetPacketFilter(new SelectiveDropFilter(0xe));
+  client_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0xe));
   Connect();
 }
 
 // This drops the server's second flight three times.
 TEST_P(TlsConnectDatagram, DropServerSecondFlightThrice) {
-  server_->SetPacketFilter(new SelectiveDropFilter(0xe));
+  server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0xe));
   Connect();
 }
 
 static void GetCipherAndLimit(uint16_t version, uint16_t* cipher,
                               uint64_t* limit = nullptr) {
   uint64_t l;
   if (!limit) limit = &l;
 
--- a/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ecdh_unittest.cc
@@ -70,18 +70,18 @@ TEST_P(TlsConnectGeneric, ConnectEcdheP3
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
 }
 
 // This causes a HelloRetryRequest in TLS 1.3.  Earlier versions don't care.
 TEST_P(TlsConnectGeneric, ConnectEcdheP384Server) {
   EnsureTlsSetup();
-  auto hrr_capture =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeHelloRetryRequest);
+  auto hrr_capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeHelloRetryRequest);
   server_->SetPacketFilter(hrr_capture);
   const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
   server_->ConfigNamedGroups(groups);
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
             ssl_sig_rsa_pss_sha256);
   EXPECT_EQ(version_ == SSL_LIBRARY_VERSION_TLS_1_3,
             hrr_capture->buffer().len() != 0);
@@ -218,31 +218,33 @@ class TlsKeyExchangeGroupCapture : publi
  private:
   SSLNamedGroup group_;
 };
 
 // If we strip the client's supported groups extension, the server should assume
 // P-256 is supported by the client (<= 1.2 only).
 TEST_P(TlsConnectGenericPre13, DropSupportedGroupExtensionP256) {
   EnsureTlsSetup();
-  client_->SetPacketFilter(new TlsExtensionDropper(ssl_supported_groups_xtn));
-  auto group_capture = new TlsKeyExchangeGroupCapture();
+  client_->SetPacketFilter(
+      std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn));
+  auto group_capture = std::make_shared<TlsKeyExchangeGroupCapture>();
   server_->SetPacketFilter(group_capture);
 
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 
   EXPECT_EQ(ssl_grp_ec_secp256r1, group_capture->group());
 }
 
 // Supported groups is mandatory in TLS 1.3.
 TEST_P(TlsConnectTls13, DropSupportedGroupExtension) {
   EnsureTlsSetup();
-  client_->SetPacketFilter(new TlsExtensionDropper(ssl_supported_groups_xtn));
+  client_->SetPacketFilter(
+      std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
   server_->CheckErrorCode(SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
 }
 
 // If we only have a lame group, we fall back to static RSA.
 TEST_P(TlsConnectGenericPre13, UseLameGroup) {
   const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp192r1};
@@ -554,24 +556,24 @@ class ECCServerKEXFilter : public TlsHan
     output->Write(1, curve, 2);             // write curve id
     output->Write(3, 0U, 1);                // point length 0
     return CHANGE;
   }
 };
 
 TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyServerPoint) {
   // add packet filter
-  server_->SetPacketFilter(new ECCServerKEXFilter());
+  server_->SetPacketFilter(std::make_shared<ECCServerKEXFilter>());
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH);
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyClientPoint) {
   // add packet filter
-  client_->SetPacketFilter(new ECCClientKEXFilter());
+  client_->SetPacketFilter(std::make_shared<ECCClientKEXFilter>());
   ConnectExpectFail();
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH);
 }
 
 INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
                         ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
                                            TlsConnectTestBase::kTlsV11Plus));
 
--- a/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_ems_unittest.cc
@@ -74,17 +74,17 @@ TEST_P(TlsConnectGenericPre13, ConnectEx
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectExtendedMasterSecretResumeWithout) {
   EnableExtendedMasterSecret();
   Connect();
 
   Reset();
   server_->EnableExtendedMasterSecret();
-  auto alert_recorder = new TlsAlertRecorder();
+  auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertHandshakeFailure, alert_recorder->description());
 }
 
 TEST_P(TlsConnectGenericPre13, ConnectNormalResumeWithExtendedMasterSecret) {
   ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
--- a/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_exporter_unittest.cc
@@ -9,17 +9,18 @@
 #include "gtest_utils.h"
 #include "tls_connect.h"
 
 namespace nss_test {
 
 static const char* kExporterLabel = "EXPORTER-duck";
 static const uint8_t kExporterContext[] = {0x12, 0x34, 0x56};
 
-static void ExportAndCompare(TlsAgent* client, TlsAgent* server, bool context) {
+static void ExportAndCompare(std::shared_ptr<TlsAgent>& client,
+                             std::shared_ptr<TlsAgent>& server, bool context) {
   static const size_t exporter_len = 10;
   uint8_t client_value[exporter_len] = {0};
   EXPECT_EQ(SECSuccess,
             SSL_ExportKeyingMaterial(
                 client->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
                 context ? PR_TRUE : PR_FALSE, kExporterContext,
                 sizeof(kExporterContext), client_value, sizeof(client_value)));
   uint8_t server_value[exporter_len] = {0xff};
@@ -91,17 +92,17 @@ int32_t RegularExporterShouldFail(TlsAge
 TEST_P(TlsConnectTls13, EarlyExporter) {
   SetupForZeroRtt();
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
   ExpectResumption(RESUME_TICKET);
 
   client_->Handshake();  // Send ClientHello.
   uint8_t client_value[10] = {0};
-  RegularExporterShouldFail(client_, nullptr, 0);
+  RegularExporterShouldFail(client_.get(), nullptr, 0);
   EXPECT_EQ(SECSuccess,
             SSL_ExportEarlyKeyingMaterial(
                 client_->ssl_fd(), kExporterLabel, strlen(kExporterLabel),
                 kExporterContext, sizeof(kExporterContext), client_value,
                 sizeof(client_value)));
 
   server_->SetSniCallback(RegularExporterShouldFail);
   server_->Handshake();  // Handle ClientHello.
--- a/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_extension_unittest.cc
@@ -161,35 +161,31 @@ class TlsExtensionAppender : public TlsH
 
 class TlsExtensionTestBase : public TlsConnectTestBase {
  protected:
   TlsExtensionTestBase(Mode mode, uint16_t version)
       : TlsConnectTestBase(mode, version) {}
   TlsExtensionTestBase(const std::string& mode, uint16_t version)
       : TlsConnectTestBase(mode, version) {}
 
-  void ClientHelloErrorTest(PacketFilter* filter,
+  void ClientHelloErrorTest(std::shared_ptr<PacketFilter> filter,
                             uint8_t alert = kTlsAlertDecodeError) {
-    auto alert_recorder = new TlsAlertRecorder();
+    auto alert_recorder = std::make_shared<TlsAlertRecorder>();
     server_->SetPacketFilter(alert_recorder);
-    if (filter) {
-      client_->SetPacketFilter(filter);
-    }
+    client_->SetPacketFilter(filter);
     ConnectExpectFail();
     EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
     EXPECT_EQ(alert, alert_recorder->description());
   }
 
-  void ServerHelloErrorTest(PacketFilter* filter,
+  void ServerHelloErrorTest(std::shared_ptr<PacketFilter> filter,
                             uint8_t alert = kTlsAlertDecodeError) {
-    auto alert_recorder = new TlsAlertRecorder();
+    auto alert_recorder = std::make_shared<TlsAlertRecorder>();
     client_->SetPacketFilter(alert_recorder);
-    if (filter) {
-      server_->SetPacketFilter(filter);
-    }
+    server_->SetPacketFilter(filter);
     ConnectExpectFail();
     EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
     EXPECT_EQ(alert, alert_recorder->description());
   }
 
   static void InitSimpleSni(DataBuffer* extension) {
     const char* name = "host.name";
     const size_t namelen = PL_strlen(name);
@@ -208,17 +204,17 @@ class TlsExtensionTestBase : public TlsC
         ssl_grp_ec_curve25519, ssl_grp_ec_secp384r1};
     client_->ConfigNamedGroups(client_groups);
     server_->ConfigNamedGroups(server_groups);
     EnsureTlsSetup();
     client_->StartConnect();
     server_->StartConnect();
     client_->Handshake();  // Send ClientHello
     server_->Handshake();  // Send HRR.
-    client_->SetPacketFilter(new TlsExtensionDropper(type));
+    client_->SetPacketFilter(std::make_shared<TlsExtensionDropper>(type));
     Handshake();
     client_->CheckErrorCode(client_error);
     server_->CheckErrorCode(server_error);
   }
 };
 
 class TlsExtensionTestDtls : public TlsExtensionTestBase,
                              public ::testing::WithParamInterface<uint16_t> {
@@ -247,29 +243,29 @@ class TlsExtensionTest12
 class TlsExtensionTest13 : public TlsExtensionTestBase,
                            public ::testing::WithParamInterface<std::string> {
  public:
   TlsExtensionTest13()
       : TlsExtensionTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
 
   void ConnectWithBogusVersionList(const uint8_t* buf, size_t len) {
     DataBuffer versions_buf(buf, len);
-    client_->SetPacketFilter(new TlsExtensionReplacer(
+    client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
         ssl_tls13_supported_versions_xtn, versions_buf));
     ConnectExpectFail();
     client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
     server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
   }
 
   void ConnectWithReplacementVersionList(uint16_t version) {
     DataBuffer versions_buf;
 
     size_t index = versions_buf.Write(0, 2, 1);
     versions_buf.Write(index, version, 2);
-    client_->SetPacketFilter(new TlsExtensionReplacer(
+    client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
         ssl_tls13_supported_versions_xtn, versions_buf));
     ConnectExpectFail();
   }
 };
 
 class TlsExtensionTest13Stream : public TlsExtensionTestBase {
  public:
   TlsExtensionTest13Stream()
@@ -290,94 +286,98 @@ class TlsExtensionTestPre13
       public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
  public:
   TlsExtensionTestPre13()
       : TlsExtensionTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
   }
 };
 
 TEST_P(TlsExtensionTestGeneric, DamageSniLength) {
-  ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 1));
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionDamager>(ssl_server_name_xtn, 1));
 }
 
 TEST_P(TlsExtensionTestGeneric, DamageSniHostLength) {
-  ClientHelloErrorTest(new TlsExtensionDamager(ssl_server_name_xtn, 4));
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionDamager>(ssl_server_name_xtn, 4));
 }
 
 TEST_P(TlsExtensionTestGeneric, TruncateSni) {
-  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_server_name_xtn, 7));
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionTruncator>(ssl_server_name_xtn, 7));
 }
 
 // A valid extension that appears twice will be reported as unsupported.
 TEST_P(TlsExtensionTestGeneric, RepeatSni) {
   DataBuffer extension;
   InitSimpleSni(&extension);
-  ClientHelloErrorTest(new TlsExtensionInjector(ssl_server_name_xtn, extension),
-                       kTlsAlertIllegalParameter);
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionInjector>(ssl_server_name_xtn, extension),
+      kTlsAlertIllegalParameter);
 }
 
 // An SNI entry with zero length is considered invalid (strangely, not if it is
 // the last entry, which is probably a bug).
 TEST_P(TlsExtensionTestGeneric, BadSni) {
   DataBuffer simple;
   InitSimpleSni(&simple);
   DataBuffer extension;
   extension.Allocate(simple.len() + 3);
   extension.Write(0, static_cast<uint32_t>(0), 3);
   extension.Write(3, simple);
   ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_server_name_xtn, extension));
+      std::make_shared<TlsExtensionReplacer>(ssl_server_name_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestGeneric, EmptySni) {
   DataBuffer extension;
   extension.Allocate(2);
   extension.Write(0, static_cast<uint32_t>(0), 2);
   ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_server_name_xtn, extension));
+      std::make_shared<TlsExtensionReplacer>(ssl_server_name_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestGeneric, EmptyAlpnExtension) {
   EnableAlpn();
   DataBuffer extension;
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
-      kTlsAlertIllegalParameter);
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+                           ssl_app_layer_protocol_xtn, extension),
+                       kTlsAlertIllegalParameter);
 }
 
 // An empty ALPN isn't considered bad, though it does lead to there being no
 // protocol for the server to select.
 TEST_P(TlsExtensionTestGeneric, EmptyAlpnList) {
   EnableAlpn();
   const uint8_t val[] = {0x00, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension),
-      kTlsAlertNoApplicationProtocol);
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+                           ssl_app_layer_protocol_xtn, extension),
+                       kTlsAlertNoApplicationProtocol);
 }
 
 TEST_P(TlsExtensionTestGeneric, OneByteAlpn) {
   EnableAlpn();
   ClientHelloErrorTest(
-      new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 1));
+      std::make_shared<TlsExtensionTruncator>(ssl_app_layer_protocol_xtn, 1));
 }
 
 TEST_P(TlsExtensionTestGeneric, AlpnMissingValue) {
   EnableAlpn();
   // This will leave the length of the second entry, but no value.
   ClientHelloErrorTest(
-      new TlsExtensionTruncator(ssl_app_layer_protocol_xtn, 5));
+      std::make_shared<TlsExtensionTruncator>(ssl_app_layer_protocol_xtn, 5));
 }
 
 TEST_P(TlsExtensionTestGeneric, AlpnZeroLength) {
   EnableAlpn();
   const uint8_t val[] = {0x01, 0x61, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestGeneric, AlpnMismatch) {
   const uint8_t client_alpn[] = {0x01, 0x61};
   client_->EnableAlpn(client_alpn, sizeof(client_alpn));
   const uint8_t server_alpn[] = {0x02, 0x61, 0x62};
   server_->EnableAlpn(server_alpn, sizeof(server_alpn));
 
@@ -385,178 +385,180 @@ TEST_P(TlsExtensionTestGeneric, AlpnMism
 }
 
 // Many of these tests fail in TLS 1.3 because the extension is encrypted, which
 // prevents modification of the value from the ServerHello.
 TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyList) {
   EnableAlpn();
   const uint8_t val[] = {0x00, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ServerHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+  ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, AlpnReturnedEmptyName) {
   EnableAlpn();
   const uint8_t val[] = {0x00, 0x01, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ServerHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+  ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, AlpnReturnedListTrailingData) {
   EnableAlpn();
   const uint8_t val[] = {0x00, 0x02, 0x01, 0x61, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ServerHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+  ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, AlpnReturnedExtraEntry) {
   EnableAlpn();
   const uint8_t val[] = {0x00, 0x04, 0x01, 0x61, 0x01, 0x62};
   DataBuffer extension(val, sizeof(val));
-  ServerHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+  ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, AlpnReturnedBadListLength) {
   EnableAlpn();
   const uint8_t val[] = {0x00, 0x99, 0x01, 0x61, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ServerHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+  ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, AlpnReturnedBadNameLength) {
   EnableAlpn();
   const uint8_t val[] = {0x00, 0x02, 0x99, 0x61};
   DataBuffer extension(val, sizeof(val));
-  ServerHelloErrorTest(
-      new TlsExtensionReplacer(ssl_app_layer_protocol_xtn, extension));
+  ServerHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_app_layer_protocol_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestDtls, SrtpShort) {
   EnableSrtp();
-  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_use_srtp_xtn, 3));
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionTruncator>(ssl_use_srtp_xtn, 3));
 }
 
 TEST_P(TlsExtensionTestDtls, SrtpOdd) {
   EnableSrtp();
   const uint8_t val[] = {0x00, 0x01, 0xff, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(new TlsExtensionReplacer(ssl_use_srtp_xtn, extension));
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionReplacer>(ssl_use_srtp_xtn, extension));
 }
 
 TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsBadLength) {
   const uint8_t val[] = {0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_signature_algorithms_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_signature_algorithms_xtn, extension));
 }
 
 TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsTrailingData) {
   const uint8_t val[] = {0x00, 0x02, 0x04, 0x01, 0x00};  // sha-256, rsa
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_signature_algorithms_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_signature_algorithms_xtn, extension));
 }
 
 TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsEmpty) {
   const uint8_t val[] = {0x00, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_signature_algorithms_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_signature_algorithms_xtn, extension));
 }
 
 TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
   const uint8_t val[] = {0x00, 0x01, 0x04};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_signature_algorithms_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_signature_algorithms_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestGeneric, NoSupportedGroups) {
-  ClientHelloErrorTest(new TlsExtensionDropper(ssl_supported_groups_xtn),
-                       version_ < SSL_LIBRARY_VERSION_TLS_1_3
-                           ? kTlsAlertDecryptError
-                           : kTlsAlertMissingExtension);
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionDropper>(ssl_supported_groups_xtn),
+      version_ < SSL_LIBRARY_VERSION_TLS_1_3 ? kTlsAlertDecryptError
+                                             : kTlsAlertMissingExtension);
 }
 
 TEST_P(TlsExtensionTestGeneric, SupportedCurvesShort) {
   const uint8_t val[] = {0x00, 0x01, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_elliptic_curves_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_elliptic_curves_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestGeneric, SupportedCurvesBadLength) {
   const uint8_t val[] = {0x09, 0x99, 0x00, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_elliptic_curves_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_elliptic_curves_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestGeneric, SupportedCurvesTrailingData) {
   const uint8_t val[] = {0x00, 0x02, 0x00, 0x00, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_elliptic_curves_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_elliptic_curves_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, SupportedPointsEmpty) {
   const uint8_t val[] = {0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_ec_point_formats_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_ec_point_formats_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, SupportedPointsBadLength) {
   const uint8_t val[] = {0x99, 0x00, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_ec_point_formats_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_ec_point_formats_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, SupportedPointsTrailingData) {
   const uint8_t val[] = {0x01, 0x00, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_ec_point_formats_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_ec_point_formats_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, RenegotiationInfoBadLength) {
   const uint8_t val[] = {0x99};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_renegotiation_info_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_renegotiation_info_xtn, extension));
 }
 
 TEST_P(TlsExtensionTestPre13, RenegotiationInfoMismatch) {
   const uint8_t val[] = {0x01, 0x00};
   DataBuffer extension(val, sizeof(val));
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_renegotiation_info_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_renegotiation_info_xtn, extension));
 }
 
 // The extension has to contain a length.
 TEST_P(TlsExtensionTestPre13, RenegotiationInfoExtensionEmpty) {
   DataBuffer extension;
-  ClientHelloErrorTest(
-      new TlsExtensionReplacer(ssl_renegotiation_info_xtn, extension));
+  ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
+      ssl_renegotiation_info_xtn, extension));
 }
 
 // This only works on TLS 1.2, since it relies on static RSA; otherwise libssl
 // picks the wrong cipher suite.
 TEST_P(TlsExtensionTest12, SignatureAlgorithmConfiguration) {
   const SSLSignatureScheme schemes[] = {ssl_sig_rsa_pss_sha512,
                                         ssl_sig_rsa_pss_sha384};
 
-  TlsExtensionCapture* capture =
-      new TlsExtensionCapture(ssl_signature_algorithms_xtn);
+  auto capture =
+      std::make_shared<TlsExtensionCapture>(ssl_signature_algorithms_xtn);
   client_->SetSignatureSchemes(schemes, PR_ARRAY_SIZE(schemes));
   client_->SetPacketFilter(capture);
   EnableOnlyStaticRsaCiphers();
   Connect();
 
   const DataBuffer& ext = capture->extension();
   EXPECT_EQ(2 + PR_ARRAY_SIZE(schemes) * 2, ext.len());
   for (size_t i = 0, cursor = 2;
@@ -566,27 +568,29 @@ TEST_P(TlsExtensionTest12, SignatureAlgo
     cursor += 2;
     EXPECT_EQ(schemes[i], static_cast<SSLSignatureScheme>(v));
   }
 }
 
 // Temporary test to verify that we choke on an empty ClientKeyShare.
 // This test will fail when we implement HelloRetryRequest.
 TEST_P(TlsExtensionTest13, EmptyClientKeyShare) {
-  ClientHelloErrorTest(new TlsExtensionTruncator(ssl_tls13_key_share_xtn, 2),
-                       kTlsAlertHandshakeFailure);
+  ClientHelloErrorTest(
+      std::make_shared<TlsExtensionTruncator>(ssl_tls13_key_share_xtn, 2),
+      kTlsAlertHandshakeFailure);
 }
 
 // These tests only work in stream mode because the client sends a
 // cleartext alert which causes a MAC error on the server. With
 // stream this causes handshake failure but with datagram, the
 // packet gets dropped.
 TEST_F(TlsExtensionTest13Stream, DropServerKeyShare) {
   EnsureTlsSetup();
-  server_->SetPacketFilter(new TlsExtensionDropper(ssl_tls13_key_share_xtn));
+  server_->SetPacketFilter(
+      std::make_shared<TlsExtensionDropper>(ssl_tls13_key_share_xtn));
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 TEST_F(TlsExtensionTest13Stream, WrongServerKeyShare) {
   const uint16_t wrong_group = ssl_grp_ec_secp384r1;
 
@@ -595,17 +599,17 @@ TEST_F(TlsExtensionTest13Stream, WrongSe
       wrong_group & 0xff,  // Group we didn't offer.
       0x00,
       0x02,  // length = 2
       0x01,
       0x02};
   DataBuffer buf(key_share, sizeof(key_share));
   EnsureTlsSetup();
   server_->SetPacketFilter(
-      new TlsExtensionReplacer(ssl_tls13_key_share_xtn, buf));
+      std::make_shared<TlsExtensionReplacer>(ssl_tls13_key_share_xtn, buf));
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_KEY_SHARE, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 // TODO(ekr@rtfm.com): This is the wrong error code. See bug 1307269.
 TEST_F(TlsExtensionTest13Stream, UnknownServerKeyShare) {
   const uint16_t wrong_group = 0xffff;
@@ -615,27 +619,27 @@ TEST_F(TlsExtensionTest13Stream, Unknown
       wrong_group & 0xff,  // Group we didn't offer.
       0x00,
       0x02,  // length = 2
       0x01,
       0x02};
   DataBuffer buf(key_share, sizeof(key_share));
   EnsureTlsSetup();
   server_->SetPacketFilter(
-      new TlsExtensionReplacer(ssl_tls13_key_share_xtn, buf));
+      std::make_shared<TlsExtensionReplacer>(ssl_tls13_key_share_xtn, buf));
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_MISSING_KEY_SHARE, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 TEST_F(TlsExtensionTest13Stream, AddServerSignatureAlgorithmsOnResumption) {
   SetupForResume();
   DataBuffer empty;
-  server_->SetPacketFilter(
-      new TlsExtensionInjector(ssl_signature_algorithms_xtn, empty));
+  server_->SetPacketFilter(std::make_shared<TlsExtensionInjector>(
+      ssl_signature_algorithms_xtn, empty));
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, client_->error_code());
   EXPECT_EQ(SSL_ERROR_BAD_MAC_READ, server_->error_code());
 }
 
 struct PskIdentity {
   DataBuffer identity;
   uint32_t obfuscated_ticket_age;
@@ -758,142 +762,143 @@ class TlsPreSharedKeyReplacer : public T
   }
 
   TlsPreSharedKeyReplacerFunc function_;
 };
 
 TEST_F(TlsExtensionTest13Stream, ResumeEmptyPskLabel) {
   SetupForResume();
 
-  client_->SetPacketFilter(new TlsPreSharedKeyReplacer([](
+  client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>([](
       TlsPreSharedKeyReplacer* r) { r->identities_[0].identity.Truncate(0); }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
 }
 
 // Flip the first byte of the binder.
 TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderValue) {
   SetupForResume();
 
   client_->SetPacketFilter(
-      new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+      std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->binders_[0].Write(0, r->binders_[0].data()[0] ^ 0xff, 1);
       }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 }
 
 // Extend the binder by one.
 TEST_F(TlsExtensionTest13Stream, ResumeIncorrectBinderLength) {
   SetupForResume();
 
   client_->SetPacketFilter(
-      new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+      std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->binders_[0].Write(r->binders_[0].len(), 0xff, 1);
       }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
 }
 
 // Binders must be at least 32 bytes.
 TEST_F(TlsExtensionTest13Stream, ResumeBinderTooShort) {
   SetupForResume();
 
-  client_->SetPacketFilter(new TlsPreSharedKeyReplacer(
+  client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>(
       [](TlsPreSharedKeyReplacer* r) { r->binders_[0].Truncate(31); }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
 }
 
 // Duplicate the identity and binder. This will fail with an error
 // processing the binder (because we extended the identity list.)
 TEST_F(TlsExtensionTest13Stream, ResumeTwoPsks) {
   SetupForResume();
 
   client_->SetPacketFilter(
-      new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+      std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->identities_.push_back(r->identities_[0]);
         r->binders_.push_back(r->binders_[0]);
       }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
   server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
 }
 
 // The next two tests have mismatches in the number of identities
 // and binders. This generates an illegal parameter alert.
 TEST_F(TlsExtensionTest13Stream, ResumeTwoIdentitiesOneBinder) {
   SetupForResume();
 
   client_->SetPacketFilter(
-      new TlsPreSharedKeyReplacer([](TlsPreSharedKeyReplacer* r) {
+      std::make_shared<TlsPreSharedKeyReplacer>([](TlsPreSharedKeyReplacer* r) {
         r->identities_.push_back(r->identities_[0]);
       }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
 }
 
 TEST_F(TlsExtensionTest13Stream, ResumeOneIdentityTwoBinders) {
   SetupForResume();
 
-  client_->SetPacketFilter(new TlsPreSharedKeyReplacer([](
+  client_->SetPacketFilter(std::make_shared<TlsPreSharedKeyReplacer>([](
       TlsPreSharedKeyReplacer* r) { r->binders_.push_back(r->binders_[0]); }));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
 }
 
 TEST_F(TlsExtensionTest13Stream, ResumePskExtensionNotLast) {
   SetupForResume();
 
   const uint8_t empty_buf[] = {0};
   DataBuffer empty(empty_buf, 0);
   client_->SetPacketFilter(
       // Inject an unused extension.
-      new TlsExtensionAppender(0xffff, empty));
+      std::make_shared<TlsExtensionAppender>(0xffff, empty));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
 }
 
 TEST_F(TlsExtensionTest13Stream, ResumeNoKeModes) {
   SetupForResume();
 
   DataBuffer empty;
-  client_->SetPacketFilter(
-      new TlsExtensionDropper(ssl_tls13_psk_key_exchange_modes_xtn));
+  client_->SetPacketFilter(std::make_shared<TlsExtensionDropper>(
+      ssl_tls13_psk_key_exchange_modes_xtn));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
   server_->CheckErrorCode(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES);
 }
 
 // The following test contains valid but unacceptable PreSharedKey
 // modes and therefore produces non-resumption followed by MAC
 // errors.
 TEST_F(TlsExtensionTest13Stream, ResumeBogusKeModes) {
   SetupForResume();
   const static uint8_t ke_modes[] = {1,  // Length
                                      kTls13PskKe};
 
   DataBuffer modes(ke_modes, sizeof(ke_modes));
-  client_->SetPacketFilter(
-      new TlsExtensionReplacer(ssl_tls13_psk_key_exchange_modes_xtn, modes));
+  client_->SetPacketFilter(std::make_shared<TlsExtensionReplacer>(
+      ssl_tls13_psk_key_exchange_modes_xtn, modes));
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
   server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
 }
 
 TEST_P(TlsExtensionTest13, NoKeModesIfResumptionOff) {
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
-  auto capture = new TlsExtensionCapture(ssl_tls13_psk_key_exchange_modes_xtn);
+  auto capture = std::make_shared<TlsExtensionCapture>(
+      ssl_tls13_psk_key_exchange_modes_xtn);
   client_->SetPacketFilter(capture);
   Connect();
   EXPECT_FALSE(capture->captured());
 }
 
 // In these tests, we downgrade to TLS 1.2, causing the
 // server to negotiate TLS 1.2.
 // 1. Both sides only support TLS 1.3, so we get a cipher version
--- a/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fragment_unittest.cc
@@ -138,20 +138,20 @@ class RecordFragmenter : public PacketFi
   }
 
  private:
   uint64_t sequence_number_;
   bool splitting_;
 };
 
 TEST_P(TlsConnectDatagram, FragmentClientPackets) {
-  client_->SetPacketFilter(new RecordFragmenter());
+  client_->SetPacketFilter(std::make_shared<RecordFragmenter>());
   Connect();
   SendReceive();
 }
 
 TEST_P(TlsConnectDatagram, FragmentServerPackets) {
-  server_->SetPacketFilter(new RecordFragmenter());
+  server_->SetPacketFilter(std::make_shared<RecordFragmenter>());
   Connect();
   SendReceive();
 }
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_fuzz_unittest.cc
@@ -126,18 +126,18 @@ FUZZ_P(TlsConnectGeneric, DeterministicT
   // Connect a few times and compare the transcripts byte-by-byte.
   DataBuffer last;
   for (size_t i = 0; i < 5; i++) {
     Reset();
     ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
     DisableECDHEServerKeyReuse();
 
     DataBuffer buffer;
-    client_->SetPacketFilter(new TlsConversationRecorder(buffer));
-    server_->SetPacketFilter(new TlsConversationRecorder(buffer));
+    client_->SetPacketFilter(std::make_shared<TlsConversationRecorder>(buffer));
+    server_->SetPacketFilter(std::make_shared<TlsConversationRecorder>(buffer));
 
     // Reset the RNG state.
     EXPECT_EQ(SECSuccess, RNG_ResetForFuzzing());
     Connect();
 
     // Ensure the filters go away before |buffer| does.
     client_->DeletePacketFilter();
     server_->DeletePacketFilter();
@@ -153,19 +153,19 @@ FUZZ_P(TlsConnectGeneric, DeterministicT
 // Check that we can establish and use a connection
 // with all supported TLS versions, STREAM and DGRAM.
 // Check that records are NOT encrypted.
 // Check that records don't have a MAC.
 FUZZ_P(TlsConnectGeneric, ConnectSendReceive_NullCipher) {
   EnsureTlsSetup();
 
   // Set up app data filters.
-  auto client_recorder = new TlsApplicationDataRecorder();
+  auto client_recorder = std::make_shared<TlsApplicationDataRecorder>();
   client_->SetPacketFilter(client_recorder);
-  auto server_recorder = new TlsApplicationDataRecorder();
+  auto server_recorder = std::make_shared<TlsApplicationDataRecorder>();
   server_->SetPacketFilter(server_recorder);
 
   Connect();
 
   // Construct the plaintext.
   DataBuffer buf;
   buf.Allocate(50);
   for (size_t i = 0; i < buf.len(); ++i) {
@@ -181,49 +181,49 @@ FUZZ_P(TlsConnectGeneric, ConnectSendRec
   EXPECT_EQ(buf, client_recorder->buffer());
   EXPECT_EQ(buf, server_recorder->buffer());
 }
 
 // Check that an invalid Finished message doesn't abort the connection.
 FUZZ_P(TlsConnectGeneric, BogusClientFinished) {
   EnsureTlsSetup();
 
-  auto i1 = new TlsInspectorReplaceHandshakeMessage(
+  auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
       kTlsHandshakeFinished,
       DataBuffer(kShortEmptyFinished, sizeof(kShortEmptyFinished)));
   client_->SetPacketFilter(i1);
   Connect();
   SendReceive();
 }
 
 // Check that an invalid Finished message doesn't abort the connection.
 FUZZ_P(TlsConnectGeneric, BogusServerFinished) {
   EnsureTlsSetup();
 
-  auto i1 = new TlsInspectorReplaceHandshakeMessage(
+  auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
       kTlsHandshakeFinished,
       DataBuffer(kLongEmptyFinished, sizeof(kLongEmptyFinished)));
   server_->SetPacketFilter(i1);
   Connect();
   SendReceive();
 }
 
 // Check that an invalid server auth signature doesn't abort the connection.
 FUZZ_P(TlsConnectGeneric, BogusServerAuthSignature) {
   EnsureTlsSetup();
   uint8_t msg_type = version_ == SSL_LIBRARY_VERSION_TLS_1_3
                          ? kTlsHandshakeCertificateVerify
                          : kTlsHandshakeServerKeyExchange;
-  server_->SetPacketFilter(new TlsSignatureDamager(msg_type));
+  server_->SetPacketFilter(std::make_shared<TlsSignatureDamager>(msg_type));
   Connect();
   SendReceive();
 }
 
 // Check that an invalid client auth signature doesn't abort the connection.
 FUZZ_P(TlsConnectGeneric, BogusClientAuthSignature) {
   EnsureTlsSetup();
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
   client_->SetPacketFilter(
-      new TlsSignatureDamager(kTlsHandshakeCertificateVerify));
+      std::make_shared<TlsSignatureDamager>(kTlsHandshakeCertificateVerify));
   Connect();
 }
 }
--- a/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_gather_unittest.cc
@@ -11,17 +11,17 @@ namespace nss_test {
 
 class GatherV2ClientHelloTest : public TlsConnectTestBase {
  public:
   GatherV2ClientHelloTest() : TlsConnectTestBase(STREAM, 0) {}
 
   void ConnectExpectMalformedClientHello(const DataBuffer &data) {
     EnsureTlsSetup();
 
-    auto alert_recorder = new TlsAlertRecorder();
+    auto alert_recorder = std::make_shared<TlsAlertRecorder>();
     server_->SetPacketFilter(alert_recorder);
 
     client_->SendDirect(data);
     server_->StartConnect();
     server_->Handshake();
     ASSERT_TRUE_WAIT(
         (server_->error_code() == SSL_ERROR_RX_MALFORMED_CLIENT_HELLO), 2000);
 
@@ -50,17 +50,17 @@ TEST_F(TlsConnectTest, GatherExcessiveV3
   DataBuffer buffer;
 
   size_t idx = 0;
   idx = buffer.Write(idx, 0x16, 1);                            // handshake
   idx = buffer.Write(idx, 0x0301, 2);                          // record_version
   (void)buffer.Write(idx, MAX_FRAGMENT_LENGTH + 2048 + 1, 2);  // length=max+1
 
   EnsureTlsSetup();
-  auto alert_recorder = new TlsAlertRecorder();
+  auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
   client_->SendDirect(buffer);
   server_->StartConnect();
   server_->Handshake();
   ASSERT_TRUE_WAIT((server_->error_code() == SSL_ERROR_RX_RECORD_TOO_LONG),
                    2000);
 
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
--- a/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_hrr_unittest.cc
@@ -29,37 +29,39 @@ TEST_P(TlsConnectTls13, HelloRetryReques
   static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
                                                     ssl_grp_ec_secp521r1};
   server_->ConfigNamedGroups(groups);
   client_->Set0RttEnabled(true);
   server_->Set0RttEnabled(true);
   ExpectResumption(RESUME_TICKET);
 
   // Send first ClientHello and send 0-RTT data
-  auto capture_early_data = new TlsExtensionCapture(ssl_tls13_early_data_xtn);
+  auto capture_early_data =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_early_data_xtn);
   client_->SetPacketFilter(capture_early_data);
   client_->Handshake();
   EXPECT_EQ(k0RttDataLen, PR_Write(client_->ssl_fd(), k0RttData,
                                    k0RttDataLen));  // 0-RTT write.
   EXPECT_TRUE(capture_early_data->captured());
 
   // Send the HelloRetryRequest
-  auto hrr_capture =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeHelloRetryRequest);
+  auto hrr_capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeHelloRetryRequest);
   server_->SetPacketFilter(hrr_capture);
   server_->Handshake();
   EXPECT_LT(0U, hrr_capture->buffer().len());
 
   // The server can't read
   std::vector<uint8_t> buf(k0RttDataLen);
   EXPECT_EQ(SECFailure, PR_Read(server_->ssl_fd(), buf.data(), k0RttDataLen));
   EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
 
   // Make a new capture for the early data.
-  capture_early_data = new TlsExtensionCapture(ssl_tls13_early_data_xtn);
+  capture_early_data =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_early_data_xtn);
   client_->SetPacketFilter(capture_early_data);
 
   // Complete the handshake successfully
   Handshake();
   ExpectEarlyDataAccepted(false);  // The server should reject 0-RTT
   CheckConnected();
   SendReceive();
   EXPECT_FALSE(capture_early_data->captured());
@@ -89,32 +91,32 @@ class KeyShareReplayer : public TlsExten
   DataBuffer data_;
 };
 
 // This forces a HelloRetryRequest by disabling P-256 on the server.  However,
 // the second ClientHello is modified so that it omits the requested share.  The
 // server should reject this.
 TEST_P(TlsConnectTls13, RetryWithSameKeyShare) {
   EnsureTlsSetup();
-  client_->SetPacketFilter(new KeyShareReplayer());
+  client_->SetPacketFilter(std::make_shared<KeyShareReplayer>());
   static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
                                                     ssl_grp_ec_secp521r1};
   server_->ConfigNamedGroups(groups);
   ConnectExpectFail();
   EXPECT_EQ(SSL_ERROR_BAD_2ND_CLIENT_HELLO, server_->error_code());
   EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, client_->error_code());
 }
 
 // This tests that the second attempt at sending a ClientHello (after receiving
 // a HelloRetryRequest) is correctly retransmitted.
 TEST_F(TlsConnectDatagram13, DropClientSecondFlightWithHelloRetry) {
   static const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
                                                     ssl_grp_ec_secp521r1};
   server_->ConfigNamedGroups(groups);
-  server_->SetPacketFilter(new SelectiveDropFilter(0x2));
+  server_->SetPacketFilter(std::make_shared<SelectiveDropFilter>(0x2));
   Connect();
 }
 
 class TlsKeyExchange13 : public TlsKeyExchangeTest {};
 
 // This should work, with an HRR, because the server prefers x25519 and the
 // client generates a share for P-384 on the initial ClientHello.
 TEST_P(TlsKeyExchange13, ConnectEcdhePreferenceMismatchHrr) {
@@ -164,21 +166,17 @@ TEST_F(TlsConnectTest, Select12AfterHell
   client_->StartConnect();
   server_->StartConnect();
 
   client_->Handshake();
   server_->Handshake();
 
   // Here we replace the TLS server with one that does TLS 1.2 only.
   // This will happily send the client a TLS 1.2 ServerHello.
-  TlsAgent* replacement_server =
-      new TlsAgent(server_->name(), TlsAgent::SERVER, mode_);
-  delete server_;
-  server_ = replacement_server;
-  server_->Init();
+  server_.reset(new TlsAgent(server_->name(), TlsAgent::SERVER, mode_));
   client_->SetPeer(server_);
   server_->SetPeer(client_);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   server_->StartConnect();
   Handshake();
   EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, server_->error_code());
   EXPECT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
@@ -260,17 +258,17 @@ TEST_P(HelloRetryRequestAgentTest, Handl
       5,  // length of cookie extension
       0,
       3,  // cookie value length
       0xc0,
       0x0c,
       0x13};
   DataBuffer hrr;
   MakeCannedHrr(canned_cookie_hrr, sizeof(canned_cookie_hrr), &hrr);
-  TlsExtensionCapture* capture = new TlsExtensionCapture(ssl_tls13_cookie_xtn);
+  auto capture = std::make_shared<TlsExtensionCapture>(ssl_tls13_cookie_xtn);
   agent_->SetPacketFilter(capture);
   ProcessMessage(hrr, TlsAgent::STATE_CONNECTING);
   const size_t cookie_pos = 2 + 2;  // cookie_xtn, extension len
   DataBuffer cookie(canned_cookie_hrr + cookie_pos,
                     sizeof(canned_cookie_hrr) - cookie_pos);
   EXPECT_EQ(cookie, capture->extension());
 }
 
--- a/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_loopback_unittest.cc
@@ -172,24 +172,24 @@ class TlsPreCCSHeaderInjector : public T
     TlsRecordHeader nhdr(record_header.version(), kTlsHandshakeType, 0);
     *offset = nhdr.Write(output, *offset, hhdr_buf);
     *offset = record_header.Write(output, *offset, input);
     return CHANGE;
   }
 };
 
 TEST_P(TlsConnectStreamPre13, ClientFinishedHeaderBeforeCCS) {
-  client_->SetPacketFilter(new TlsPreCCSHeaderInjector());
+  client_->SetPacketFilter(std::make_shared<TlsPreCCSHeaderInjector>());
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
   server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
 }
 
 TEST_P(TlsConnectStreamPre13, ServerFinishedHeaderBeforeCCS) {
-  server_->SetPacketFilter(new TlsPreCCSHeaderInjector());
+  server_->SetPacketFilter(std::make_shared<TlsPreCCSHeaderInjector>());
   client_->StartConnect();
   server_->StartConnect();
   Handshake();
   EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
   EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
 }
 
--- a/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_resumption_unittest.cc
@@ -241,28 +241,28 @@ TEST_P(TlsConnectGeneric, ServerSNICertT
   Connect();
   ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
   CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
   EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
 }
 
 // Prior to TLS 1.3, we were not fully ephemeral; though 1.3 fixes that
 TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceReuseKey) {
-  TlsInspectorRecordHandshakeMessage* i1 =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+  auto i1 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
   CheckKeys();
   TlsServerKeyExchangeEcdhe dhe1;
   EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
   Reset();
-  TlsInspectorRecordHandshakeMessage* i2 =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+  auto i2 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
   CheckKeys();
 
   TlsServerKeyExchangeEcdhe dhe2;
   EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
@@ -273,31 +273,31 @@ TEST_P(TlsConnectGenericPre13, ConnectEc
 }
 
 // This test parses the ServerKeyExchange, which isn't in 1.3
 TEST_P(TlsConnectGenericPre13, ConnectEcdheTwiceNewKey) {
   server_->EnsureTlsSetup();
   SECStatus rv =
       SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
-  TlsInspectorRecordHandshakeMessage* i1 =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+  auto i1 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i1);
   Connect();
   CheckKeys();
   TlsServerKeyExchangeEcdhe dhe1;
   EXPECT_TRUE(dhe1.Parse(i1->buffer()));
 
   // Restart
   Reset();
   server_->EnsureTlsSetup();
   rv = SSL_OptionSet(server_->ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
-  TlsInspectorRecordHandshakeMessage* i2 =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange);
+  auto i2 = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeServerKeyExchange);
   server_->SetPacketFilter(i2);
   ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
   Connect();
   CheckKeys();
 
   TlsServerKeyExchangeEcdhe dhe2;
   EXPECT_TRUE(dhe2.Parse(i2->buffer()));
 
@@ -352,17 +352,17 @@ TEST_P(TlsConnectGeneric, TestResumeClie
   ExpectResumption(RESUME_NONE);
   client_->EnableSingleCipher(ChooseAnotherCipher(version_));
   uint16_t ticket_extension;
   if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
     ticket_extension = ssl_tls13_pre_shared_key_xtn;
   } else {
     ticket_extension = ssl_session_ticket_xtn;
   }
-  auto ticket_capture = new TlsExtensionCapture(ticket_extension);
+  auto ticket_capture = std::make_shared<TlsExtensionCapture>(ticket_extension);
   client_->SetPacketFilter(ticket_capture);
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
   EXPECT_EQ(0U, ticket_capture->extension().len());
 }
 
 // Test that we don't resume when we can't negotiate the same cipher.
 TEST_P(TlsConnectGeneric, TestResumeServerDifferentCipher) {
@@ -416,18 +416,18 @@ TEST_P(TlsConnectStream, TestResumptionO
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   server_->EnableSingleCipher(ChooseOneCipher(version_));
   Connect();
   SendReceive();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
-  server_->SetPacketFilter(
-      new SelectedCipherSuiteReplacer(ChooseAnotherCipher(version_)));
+  server_->SetPacketFilter(std::make_shared<SelectedCipherSuiteReplacer>(
+      ChooseAnotherCipher(version_)));
 
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
     // The reason this test is stream only: the server is unable to decrypt
     // the alert that the client sends, see bug 1304603.
     server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
   } else {
@@ -488,17 +488,18 @@ TEST_P(TlsConnectGenericPre13, TestResum
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   // Enable the lower version on the client.
   client_->SetVersionRange(version_ - 1, version_);
   server_->EnableSingleCipher(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA);
-  server_->SetPacketFilter(new SelectedVersionReplacer(override_version));
+  server_->SetPacketFilter(
+      std::make_shared<SelectedVersionReplacer>(override_version));
 
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
 }
 
 // Test that two TLS resumptions work and produce the same ticket.
 // This will change after bug 1257047 is fixed.
@@ -511,36 +512,34 @@ TEST_F(TlsConnectTest, TestTls13Resumpti
   CheckKeys();
   uint16_t original_suite;
   EXPECT_TRUE(client_->cipher_suite(&original_suite));
 
   Reset();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
   ExpectResumption(RESUME_TICKET);
-  TlsExtensionCapture* c1 =
-      new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+  auto c1 = std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
   client_->SetPacketFilter(c1);
   Connect();
   SendReceive();
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
             ssl_sig_none);
   // The filter will go away when we reset, so save the captured extension.
   DataBuffer initialTicket(c1->extension());
   ASSERT_LT(0U, initialTicket.len());
 
   ScopedCERTCertificate cert1(SSL_PeerCertificate(client_->ssl_fd()));
   ASSERT_TRUE(!!cert1.get());
 
   Reset();
   ClearStats();
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
-  TlsExtensionCapture* c2 =
-      new TlsExtensionCapture(ssl_tls13_pre_shared_key_xtn);
+  auto c2 = std::make_shared<TlsExtensionCapture>(ssl_tls13_pre_shared_key_xtn);
   client_->SetPacketFilter(c2);
   ExpectResumption(RESUME_TICKET);
   Connect();
   SendReceive();
   CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
             ssl_sig_none);
   ASSERT_LT(0U, c2->extension().len());
 
@@ -623,20 +622,21 @@ TEST_F(TlsConnectTest, TestTls13Resumpti
   ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
   // Enable the lower version on the client.
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
 
   // Add filters that set downgrade SH.version to 1.2 and the cipher suite
   // to one that works with 1.2, so that we don't run into early sanity checks.
   // We will eventually fail the (sid.version == SH.version) check.
-  std::vector<PacketFilter*> filters;
-  filters.push_back(new SelectedCipherSuiteReplacer(
+  std::vector<std::shared_ptr<PacketFilter>> filters;
+  filters.push_back(std::make_shared<SelectedCipherSuiteReplacer>(
       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256));
-  filters.push_back(new SelectedVersionReplacer(SSL_LIBRARY_VERSION_TLS_1_2));
-  server_->SetPacketFilter(new ChainedPacketFilter(filters));
+  filters.push_back(
+      std::make_shared<SelectedVersionReplacer>(SSL_LIBRARY_VERSION_TLS_1_2));
+  server_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(filters));
 
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_HELLO);
   server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
 }
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_skip_unittest.cc
@@ -80,140 +80,153 @@ class TlsHandshakeSkipFilter : public Tl
 
 class TlsSkipTest
     : public TlsConnectTestBase,
       public ::testing::WithParamInterface<std::tuple<std::string, uint16_t>> {
  protected:
   TlsSkipTest()
       : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
 
-  void ServerSkipTest(PacketFilter* filter,
+  void ServerSkipTest(std::shared_ptr<PacketFilter> filter,
                       uint8_t alert = kTlsAlertUnexpectedMessage) {
-    auto alert_recorder = new TlsAlertRecorder();
+    auto alert_recorder = std::make_shared<TlsAlertRecorder>();
     client_->SetPacketFilter(alert_recorder);
-    if (filter) {
-      server_->SetPacketFilter(filter);
-    }
+    server_->SetPacketFilter(filter);
     ConnectExpectFail();
     EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
     EXPECT_EQ(alert, alert_recorder->description());
   }
 };
 
 class Tls13SkipTest : public TlsConnectTestBase,
                       public ::testing::WithParamInterface<std::string> {
  protected:
   Tls13SkipTest()
       : TlsConnectTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
 
-  void ServerSkipTest(TlsRecordFilter* filter, int32_t error) {
+  void ServerSkipTest(std::shared_ptr<TlsRecordFilter> filter, int32_t error) {
     EnsureTlsSetup();
-    server_->SetPacketFilter(filter);
+    server_->SetTlsRecordFilter(filter);
     filter->EnableDecryption();
     if (mode_ == STREAM) {
       ConnectExpectFail();
     } else {
       ConnectExpectFailOneSide(TlsAgent::CLIENT);
     }
     client_->CheckErrorCode(error);
     if (mode_ == STREAM) {
       server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
     } else {
       ASSERT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
     }
   }
 
-  void ClientSkipTest(TlsRecordFilter* filter, int32_t error) {
+  void ClientSkipTest(std::shared_ptr<TlsRecordFilter> filter, int32_t error) {
     EnsureTlsSetup();
-    client_->SetPacketFilter(filter);
+    client_->SetTlsRecordFilter(filter);
     filter->EnableDecryption();
     ConnectExpectFailOneSide(TlsAgent::SERVER);
 
     server_->CheckErrorCode(error);
     ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
   }
 };
 
 TEST_P(TlsSkipTest, SkipCertificateRsa) {
   EnableOnlyStaticRsaCiphers();
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
 }
 
 TEST_P(TlsSkipTest, SkipCertificateDhe) {
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
 }
 
 TEST_P(TlsSkipTest, SkipCertificateEcdhe) {
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
 }
 
 TEST_P(TlsSkipTest, SkipCertificateEcdsa) {
   Reset(TlsAgent::kServerEcdsa256);
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH);
 }
 
 TEST_P(TlsSkipTest, SkipServerKeyExchange) {
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
 }
 
 TEST_P(TlsSkipTest, SkipServerKeyExchangeEcdsa) {
   Reset(TlsAgent::kServerEcdsa256);
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
 }
 
 TEST_P(TlsSkipTest, SkipCertAndKeyExch) {
-  auto chain = new ChainedPacketFilter();
-  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
-  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  auto chain = std::make_shared<ChainedPacketFilter>();
+  chain->Add(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
+  chain->Add(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
   ServerSkipTest(chain);
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
 }
 
 TEST_P(TlsSkipTest, SkipCertAndKeyExchEcdsa) {
   Reset(TlsAgent::kServerEcdsa256);
-  auto chain = new ChainedPacketFilter();
-  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate));
-  chain->Add(new TlsHandshakeSkipFilter(kTlsHandshakeServerKeyExchange));
+  auto chain = std::make_shared<ChainedPacketFilter>();
+  chain->Add(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate));
+  chain->Add(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeServerKeyExchange));
   ServerSkipTest(chain);
   client_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
 }
 
 TEST_P(Tls13SkipTest, SkipEncryptedExtensions) {
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeEncryptedExtensions),
+  ServerSkipTest(std::make_shared<TlsHandshakeSkipFilter>(
+                     kTlsHandshakeEncryptedExtensions),
                  SSL_ERROR_RX_UNEXPECTED_CERTIFICATE);
 }
 
 TEST_P(Tls13SkipTest, SkipServerCertificate) {
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate),
-                 SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate),
+      SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
 }
 
 TEST_P(Tls13SkipTest, SkipServerCertificateVerify) {
-  ServerSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificateVerify),
-                 SSL_ERROR_RX_UNEXPECTED_FINISHED);
+  ServerSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificateVerify),
+      SSL_ERROR_RX_UNEXPECTED_FINISHED);
 }
 
 TEST_P(Tls13SkipTest, SkipClientCertificate) {
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
-  ClientSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificate),
-                 SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
+  ClientSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificate),
+      SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
 }
 
 TEST_P(Tls13SkipTest, SkipClientCertificateVerify) {
   client_->SetupClientAuth();
   server_->RequestClientAuth(true);
-  ClientSkipTest(new TlsHandshakeSkipFilter(kTlsHandshakeCertificateVerify),
-                 SSL_ERROR_RX_UNEXPECTED_FINISHED);
+  ClientSkipTest(
+      std::make_shared<TlsHandshakeSkipFilter>(kTlsHandshakeCertificateVerify),
+      SSL_ERROR_RX_UNEXPECTED_FINISHED);
 }
 
 INSTANTIATE_TEST_CASE_P(SkipTls10, TlsSkipTest,
                         ::testing::Combine(TlsConnectTestBase::kTlsModesStream,
                                            TlsConnectTestBase::kTlsV10));
 INSTANTIATE_TEST_CASE_P(SkipVariants, TlsSkipTest,
                         ::testing::Combine(TlsConnectTestBase::kTlsModesAll,
                                            TlsConnectTestBase::kTlsV11V12));
--- a/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_staticrsa_unittest.cc
@@ -43,81 +43,83 @@ TEST_P(TlsConnectGenericPre13, ConnectSt
   Connect();
   CheckKeys(ssl_kea_rsa, ssl_grp_none, ssl_auth_rsa_decrypt, ssl_sig_none);
 }
 
 // Test that a totally bogus EPMS is handled correctly.
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusCKE) {
   EnableOnlyStaticRsaCiphers();
-  TlsInspectorReplaceHandshakeMessage* i1 =
-      new TlsInspectorReplaceHandshakeMessage(
-          kTlsHandshakeClientKeyExchange,
-          DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
+  auto i1 = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
+      kTlsHandshakeClientKeyExchange,
+      DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
   client_->SetPacketFilter(i1);
-  auto alert_recorder = new TlsAlertRecorder();
+  auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // Test that a PMS with a bogus version number is handled correctly.
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectStaticRSABogusPMSVersionDetect) {
   EnableOnlyStaticRsaCiphers();
-  client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
-  auto alert_recorder = new TlsAlertRecorder();
+  client_->SetPacketFilter(
+      std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
+  auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // Test that a PMS with a bogus version number is ignored when
 // rollback detection is disabled. This is a positive control for
 // ConnectStaticRSABogusPMSVersionDetect.
 TEST_P(TlsConnectGenericPre13, ConnectStaticRSABogusPMSVersionIgnore) {
   EnableOnlyStaticRsaCiphers();
-  client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
+  client_->SetPacketFilter(
+      std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
   server_->DisableRollbackDetection();
   Connect();
 }
 
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13, ConnectExtendedMasterSecretStaticRSABogusCKE) {
   EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
-  TlsInspectorReplaceHandshakeMessage* inspect =
-      new TlsInspectorReplaceHandshakeMessage(
-          kTlsHandshakeClientKeyExchange,
-          DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
+  auto inspect = std::make_shared<TlsInspectorReplaceHandshakeMessage>(
+      kTlsHandshakeClientKeyExchange,
+      DataBuffer(kBogusClientKeyExchange, sizeof(kBogusClientKeyExchange)));
   client_->SetPacketFilter(inspect);
-  auto alert_recorder = new TlsAlertRecorder();
+  auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 // This test is stream so we can catch the bad_record_mac alert.
 TEST_P(TlsConnectStreamPre13,
        ConnectExtendedMasterSecretStaticRSABogusPMSVersionDetect) {
   EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
-  client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
-  auto alert_recorder = new TlsAlertRecorder();
+  client_->SetPacketFilter(
+      std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
+  auto alert_recorder = std::make_shared<TlsAlertRecorder>();
   server_->SetPacketFilter(alert_recorder);
   ConnectExpectFail();
   EXPECT_EQ(kTlsAlertFatal, alert_recorder->level());
   EXPECT_EQ(kTlsAlertBadRecordMac, alert_recorder->description());
 }
 
 TEST_P(TlsConnectStreamPre13,
        ConnectExtendedMasterSecretStaticRSABogusPMSVersionIgnore) {
   EnableOnlyStaticRsaCiphers();
   EnableExtendedMasterSecret();
-  client_->SetPacketFilter(new TlsInspectorClientHelloVersionChanger(server_));
+  client_->SetPacketFilter(
+      std::make_shared<TlsInspectorClientHelloVersionChanger>(server_));
   server_->DisableRollbackDetection();
   Connect();
 }
 
 }  // namespace nspr_test
--- a/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_v2_client_hello_unittest.cc
@@ -18,17 +18,17 @@ extern "C" {
 #include "tls_connect.h"
 #include "tls_filter.h"
 
 namespace nss_test {
 
 // Replaces the client hello with an SSLv2 version once.
 class SSLv2ClientHelloFilter : public PacketFilter {
  public:
-  SSLv2ClientHelloFilter(TlsAgent* client, uint16_t version)
+  SSLv2ClientHelloFilter(std::shared_ptr<TlsAgent>& client, uint16_t version)
       : replaced_(false),
         client_(client),
         version_(version),
         pad_len_(0),
         reported_pad_len_(0),
         client_random_len_(16),
         ciphers_(0),
         send_escape_(false) {}
@@ -116,26 +116,26 @@ class SSLv2ClientHelloFilter : public Pa
     // Add padding if any.
     if (pad_len_ > 0) {
       std::vector<uint8_t> pad(pad_len_);
       idx = output->Write(idx, pad.data(), pad.size());
     }
 
     // Update the client random so that the handshake succeeds.
     SECStatus rv = SSLInt_UpdateSSLv2ClientRandom(
-        client_->ssl_fd(), challenge.data(), challenge.size(),
+        client_.lock()->ssl_fd(), challenge.data(), challenge.size(),
         output->data() + hdr_len, output->len() - hdr_len);
     EXPECT_EQ(SECSuccess, rv);
 
     return CHANGE;
   }
 
  private:
   bool replaced_;
-  TlsAgent* client_;
+  std::weak_ptr<TlsAgent> client_;
   uint16_t version_;
   uint8_t pad_len_;
   uint8_t reported_pad_len_;
   uint16_t client_random_len_;
   std::vector<uint16_t> ciphers_;
   bool send_escape_;
 };
 
@@ -143,17 +143,17 @@ class SSLv2ClientHelloTestF : public Tls
  public:
   SSLv2ClientHelloTestF() : TlsConnectTestBase(STREAM, 0), filter_(nullptr) {}
 
   SSLv2ClientHelloTestF(Mode mode, uint16_t version)
       : TlsConnectTestBase(mode, version), filter_(nullptr) {}
 
   void SetUp() {
     TlsConnectTestBase::SetUp();
-    filter_ = new SSLv2ClientHelloFilter(client_, version_);
+    filter_ = std::make_shared<SSLv2ClientHelloFilter>(client_, version_);
     client_->SetPacketFilter(filter_);
   }
 
   void RequireSafeRenegotiation() {
     server_->EnsureTlsSetup();
     SECStatus rv =
         SSL_OptionSet(server_->ssl_fd(), SSL_REQUIRE_SAFE_NEGOTIATION, PR_TRUE);
     EXPECT_EQ(rv, SECSuccess);
@@ -180,17 +180,17 @@ class SSLv2ClientHelloTestF : public Tls
 
   void SetClientRandomLength(uint16_t client_random_len) {
     filter_->SetClientRandomLength(client_random_len);
   }
 
   void SetSendEscape(bool send_escape) { filter_->SetSendEscape(send_escape); }
 
  private:
-  SSLv2ClientHelloFilter* filter_;
+  std::shared_ptr<SSLv2ClientHelloFilter> filter_;
 };
 
 // Parameterized version of SSLv2ClientHelloTestF we can
 // use with TEST_P to test multiple TLS versions easily.
 class SSLv2ClientHelloTest : public SSLv2ClientHelloTestF,
                              public ::testing::WithParamInterface<uint16_t> {
  public:
   SSLv2ClientHelloTest() : SSLv2ClientHelloTestF(STREAM, GetParam()) {}
--- a/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_version_unittest.cc
@@ -52,50 +52,54 @@ TEST_P(TlsConnectGeneric, ServerNegotiat
 
 // Test the ServerRandom version hack from
 // [draft-ietf-tls-tls13-11 Section 6.3.1.1].
 // The first three tests test for active tampering. The next
 // two validate that we can also detect fallback using the
 // SSL_SetDowngradeCheckVersion() API.
 TEST_F(TlsConnectTest, TestDowngradeDetectionToTls11) {
   client_->SetPacketFilter(
-      new TlsInspectorClientHelloVersionSetter(SSL_LIBRARY_VERSION_TLS_1_1));
+      std::make_shared<TlsInspectorClientHelloVersionSetter>(
+          SSL_LIBRARY_VERSION_TLS_1_1));
   ConnectExpectFail();
   ASSERT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
 }
 
 /* Attempt to negotiate the bogus DTLS 1.1 version. */
 TEST_F(DtlsConnectTest, TestDtlsVersion11) {
   client_->SetPacketFilter(
-      new TlsInspectorClientHelloVersionSetter(((~0x0101) & 0xffff)));
+      std::make_shared<TlsInspectorClientHelloVersionSetter>(
+          ((~0x0101) & 0xffff)));
   ConnectExpectFail();
   // It's kind of surprising that SSL_ERROR_NO_CYPHER_OVERLAP is
   // what is returned here, but this is deliberate in ssl3_HandleAlert().
   EXPECT_EQ(SSL_ERROR_NO_CYPHER_OVERLAP, client_->error_code());
   EXPECT_EQ(SSL_ERROR_UNSUPPORTED_VERSION, server_->error_code());
 }
 
 // Disabled as long as we have draft version.
 TEST_F(TlsConnectTest, TestDowngradeDetectionToTls12) {
   EnsureTlsSetup();
   client_->SetPacketFilter(
-      new TlsInspectorClientHelloVersionSetter(SSL_LIBRARY_VERSION_TLS_1_2));
+      std::make_shared<TlsInspectorClientHelloVersionSetter>(
+          SSL_LIBRARY_VERSION_TLS_1_2));
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   ConnectExpectFail();
   ASSERT_EQ(SSL_ERROR_RX_MALFORMED_SERVER_HELLO, client_->error_code());
 }
 
 // TLS 1.1 clients do not check the random values, so we should
 // instead get a handshake failure alert from the server.
 TEST_F(TlsConnectTest, TestDowngradeDetectionToTls10) {
   client_->SetPacketFilter(
-      new TlsInspectorClientHelloVersionSetter(SSL_LIBRARY_VERSION_TLS_1_0));
+      std::make_shared<TlsInspectorClientHelloVersionSetter>(
+          SSL_LIBRARY_VERSION_TLS_1_0));
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
                            SSL_LIBRARY_VERSION_TLS_1_1);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_0,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   ConnectExpectFail();
   ASSERT_EQ(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE, server_->error_code());
   ASSERT_EQ(SSL_ERROR_DECRYPT_ERROR_ALERT, client_->error_code());
 }
@@ -253,19 +257,20 @@ TEST_P(TlsConnectGeneric, AlertBeforeSer
 
 class Tls13NoSupportedVersions : public TlsConnectStreamTls12 {
  protected:
   void Run(uint16_t overwritten_client_version, uint16_t max_server_version) {
     client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                              SSL_LIBRARY_VERSION_TLS_1_2);
     server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2, max_server_version);
     client_->SetPacketFilter(
-        new TlsInspectorClientHelloVersionSetter(overwritten_client_version));
-    auto capture =
-        new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerHello);
+        std::make_shared<TlsInspectorClientHelloVersionSetter>(
+            overwritten_client_version));
+    auto capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+        kTlsHandshakeServerHello);
     server_->SetPacketFilter(capture);
     ConnectExpectFail();
     client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
     server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
     const DataBuffer& server_hello = capture->buffer();
     ASSERT_GT(server_hello.len(), 2U);
     uint32_t ver;
     ASSERT_TRUE(server_hello.Read(0, 2, &ver));
@@ -288,20 +293,21 @@ TEST_F(Tls13NoSupportedVersions,
 TEST_F(Tls13NoSupportedVersions,
        Tls14ClientHelloWithoutSupportedVersionsServer13) {
   Run(SSL_LIBRARY_VERSION_TLS_1_3 + 1, SSL_LIBRARY_VERSION_TLS_1_3);
 }
 
 // Offer 1.3 but with ClientHello.legacy_version == TLS 1.4. This
 // causes a bad MAC error when we read EncryptedExtensions.
 TEST_F(TlsConnectStreamTls13, Tls14ClientHelloWithSupportedVersions) {
-  client_->SetPacketFilter(new TlsInspectorClientHelloVersionSetter(
-      SSL_LIBRARY_VERSION_TLS_1_3 + 1));
-  auto capture =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerHello);
+  client_->SetPacketFilter(
+      std::make_shared<TlsInspectorClientHelloVersionSetter>(
+          SSL_LIBRARY_VERSION_TLS_1_3 + 1));
+  auto capture = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeServerHello);
   server_->SetPacketFilter(capture);
   ConnectExpectFail();
   client_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
   server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
   const DataBuffer& server_hello = capture->buffer();
   ASSERT_GT(server_hello.len(), 2U);
   uint32_t ver;
   ASSERT_TRUE(server_hello.Read(0, 2, &ver));
--- a/security/nss/gtests/ssl_gtest/test_io.cc
+++ b/security/nss/gtests/ssl_gtest/test_io.cc
@@ -10,18 +10,16 @@
 #include <cassert>
 #include <iostream>
 #include <memory>
 
 #include "prerror.h"
 #include "prlog.h"
 #include "prthread.h"
 
-#include "databuffer.h"
-
 extern bool g_ssl_gtest_verbose;
 
 namespace nss_test {
 
 static PRDescIdentity test_fd_identity = PR_INVALID_IO_LAYER;
 
 #define UNIMPLEMENTED()                                                        \
   std::cerr << "Call to unimplemented function " << __FUNCTION__ << std::endl; \
@@ -29,38 +27,20 @@ static PRDescIdentity test_fd_identity =
   PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0)
 
 #define LOG(a) std::cerr << name_ << ": " << a << std::endl
 #define LOGV(a)                      \
   do {                               \
     if (g_ssl_gtest_verbose) LOG(a); \
   } while (false)
 
-class Packet : public DataBuffer {
- public:
-  Packet(const DataBuffer &buf) : DataBuffer(buf), offset_(0) {}
-
-  void Advance(size_t delta) {
-    PR_ASSERT(offset_ + delta <= len());
-    offset_ = std::min(len(), offset_ + delta);
-  }
-
-  size_t offset() const { return offset_; }
-  size_t remaining() const { return len() - offset_; }
-
- private:
-  size_t offset_;
-};
-
 // Implementation of NSPR methods
 static PRStatus DummyClose(PRFileDesc *f) {
-  DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
   f->secret = nullptr;
   f->dtor(f);
-  delete io;
   return PR_SUCCESS;
 }
 
 static int32_t DummyRead(PRFileDesc *f, void *buf, int32_t length) {
   DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
   return io->Read(buf, length);
 }
 
@@ -69,17 +49,17 @@ static int32_t DummyWrite(PRFileDesc *f,
   return io->Write(buf, length);
 }
 
 static int32_t DummyAvailable(PRFileDesc *f) {
   UNIMPLEMENTED();
   return -1;
 }
 
-int64_t DummyAvailable64(PRFileDesc *f) {
+static int64_t DummyAvailable64(PRFileDesc *f) {
   UNIMPLEMENTED();
   return -1;
 }
 
 static PRStatus DummySync(PRFileDesc *f) {
   UNIMPLEMENTED();
   return PR_FAILURE;
 }
@@ -127,21 +107,17 @@ static PRStatus DummyBind(PRFileDesc *f,
   return PR_FAILURE;
 }
 
 static PRStatus DummyListen(PRFileDesc *f, int32_t depth) {
   UNIMPLEMENTED();
   return PR_FAILURE;
 }
 
-static PRStatus DummyShutdown(PRFileDesc *f, int32_t how) {
-  DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
-  io->Reset();
-  return PR_SUCCESS;
-}
+static PRStatus DummyShutdown(PRFileDesc *f, int32_t how) { return PR_SUCCESS; }
 
 // This function does not support peek.
 static int32_t DummyRecv(PRFileDesc *f, void *buf, int32_t buflen,
                          int32_t flags, PRIntervalTime to) {
   PR_ASSERT(flags == 0);
   if (flags != 0) {
     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
     return -1;
@@ -253,38 +229,20 @@ static PRStatus DummyConnectContinue(PRF
   return PR_FAILURE;
 }
 
 static int32_t DummyReserved(PRFileDesc *f) {
   UNIMPLEMENTED();
   return -1;
 }
 
-DummyPrSocket::~DummyPrSocket() { Reset(); }
-
-void DummyPrSocket::SetPacketFilter(PacketFilter *filter) {
-  if (filter_) {
-    delete filter_;
-  }
+void DummyPrSocket::SetPacketFilter(std::shared_ptr<PacketFilter> filter) {
   filter_ = filter;
 }
 
-void DummyPrSocket::Reset() {
-  delete filter_;
-  if (peer_) {
-    peer_->SetPeer(nullptr);
-    peer_ = nullptr;
-  }
-  while (!input_.empty()) {
-    Packet *front = input_.front();
-    input_.pop();
-    delete front;
-  }
-}
-
 static const struct PRIOMethods DummyMethods = {
     PR_DESC_LAYERED,    DummyClose,
     DummyRead,          DummyWrite,
     DummyAvailable,     DummyAvailable64,
     DummySync,          DummySeek,
     DummySeek64,        DummyFileInfo,
     DummyFileInfo64,    DummyWritev,
     DummyConnect,       DummyAccept,
@@ -295,111 +253,104 @@ static const struct PRIOMethods DummyMet
     DummyAcceptRead,    DummyTransmitFile,
     DummyGetsockname,   DummyGetpeername,
     DummyReserved,      DummyReserved,
     DummyGetsockoption, DummySetsockoption,
     DummySendfile,      DummyConnectContinue,
     DummyReserved,      DummyReserved,
     DummyReserved,      DummyReserved};
 
-PRFileDesc *DummyPrSocket::CreateFD(const std::string &name, Mode mode) {
+ScopedPRFileDesc DummyPrSocket::CreateFD() {
   if (test_fd_identity == PR_INVALID_IO_LAYER) {
     test_fd_identity = PR_GetUniqueIdentity("testtransportadapter");
   }
 
-  PRFileDesc *fd = (PR_CreateIOLayerStub(test_fd_identity, &DummyMethods));
-  fd->secret = reinterpret_cast<PRFilePrivate *>(new DummyPrSocket(name, mode));
-
+  ScopedPRFileDesc fd(PR_CreateIOLayerStub(test_fd_identity, &DummyMethods));
+  fd->secret = reinterpret_cast<PRFilePrivate *>(this);
   return fd;
 }
 
-DummyPrSocket *DummyPrSocket::GetAdapter(PRFileDesc *fd) {
-  return reinterpret_cast<DummyPrSocket *>(fd->secret);
-}
-
 void DummyPrSocket::PacketReceived(const DataBuffer &packet) {
-  input_.push(new Packet(packet));
+  input_.push(Packet(packet));
 }
 
 int32_t DummyPrSocket::Read(void *data, int32_t len) {
   PR_ASSERT(mode_ == STREAM);
 
   if (mode_ != STREAM) {
     PR_SetError(PR_INVALID_METHOD_ERROR, 0);
     return -1;
   }
 
   if (input_.empty()) {
     LOGV("Read --> wouldblock " << len);
     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
     return -1;
   }
 
-  Packet *front = input_.front();
+  auto &front = input_.front();
   size_t to_read =
-      std::min(static_cast<size_t>(len), front->len() - front->offset());
-  memcpy(data, static_cast<const void *>(front->data() + front->offset()),
+      std::min(static_cast<size_t>(len), front.len() - front.offset());
+  memcpy(data, static_cast<const void *>(front.data() + front.offset()),
          to_read);
-  front->Advance(to_read);
+  front.Advance(to_read);
 
-  if (!front->remaining()) {
+  if (!front.remaining()) {
     input_.pop();
-    delete front;
   }
 
   return static_cast<int32_t>(to_read);
 }
 
 int32_t DummyPrSocket::Recv(void *buf, int32_t buflen) {
   if (input_.empty()) {
     PR_SetError(PR_WOULD_BLOCK_ERROR, 0);
     return -1;
   }
 
-  Packet *front = input_.front();
-  if (static_cast<size_t>(buflen) < front->len()) {
+  auto &front = input_.front();
+  if (static_cast<size_t>(buflen) < front.len()) {
     PR_ASSERT(false);
     PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
     return -1;
   }
 
-  size_t count = front->len();
-  memcpy(buf, front->data(), count);
+  size_t count = front.len();
+  memcpy(buf, front.data(), count);
 
   input_.pop();
-  delete front;
-
   return static_cast<int32_t>(count);
 }
 
 int32_t DummyPrSocket::Write(const void *buf, int32_t length) {
-  if (!peer_ || !writeable_) {
+  auto peer = peer_.lock();
+  if (!peer || !writeable_) {
     PR_SetError(PR_IO_ERROR, 0);
     return -1;
   }
 
   DataBuffer packet(static_cast<const uint8_t *>(buf),
                     static_cast<size_t>(length));
   DataBuffer filtered;
   PacketFilter::Action action = PacketFilter::KEEP;
   if (filter_) {
     action = filter_->Filter(packet, &filtered);
   }
   switch (action) {
     case PacketFilter::CHANGE:
       LOG("Original packet: " << packet);
       LOG("Filtered packet: " << filtered);
-      peer_->PacketReceived(filtered);
+      peer->PacketReceived(filtered);
       break;
     case PacketFilter::DROP:
       LOG("Droppped packet: " << packet);
       break;
     case PacketFilter::KEEP:
       LOGV("Packet: " << packet);
-      peer_->PacketReceived(packet);
+      peer->PacketReceived(packet);
       break;
   }
   // libssl can't handle it if this reports something other than the length
   // of what was passed in (or less, but we're not doing partial writes).
   return static_cast<int32_t>(packet.len());
 }
 
 Poller *Poller::instance;
@@ -410,95 +361,82 @@ Poller *Poller::Instance() {
   return instance;
 }
 
 void Poller::Shutdown() {
   delete instance;
   instance = nullptr;
 }
 
-Poller::~Poller() {
-  while (!timers_.empty()) {
-    Timer *timer = timers_.top();
-    timers_.pop();
-    delete timer;
-  }
-}
-
-void Poller::Wait(Event event, DummyPrSocket *adapter, PollTarget *target,
-                  PollCallback cb) {
-  auto it = waiters_.find(adapter);
-  Waiter *waiter;
-
-  if (it == waiters_.end()) {
-    waiter = new Waiter(adapter);
-  } else {
-    waiter = it->second;
-  }
-
+void Poller::Wait(Event event, std::shared_ptr<DummyPrSocket> &adapter,
+                  PollTarget *target, PollCallback cb) {
   assert(event < TIMER_EVENT);
   if (event >= TIMER_EVENT) return;
 
+  std::unique_ptr<Waiter> waiter;
+  auto it = waiters_.find(adapter);
+  if (it == waiters_.end()) {
+    waiter.reset(new Waiter(adapter));
+  } else {
+    waiter = std::move(it->second);
+  }
+
   waiter->targets_[event] = target;
   waiter->callbacks_[event] = cb;
-  waiters_[adapter] = waiter;
+  waiters_[adapter] = std::move(waiter);
 }
 
-void Poller::Cancel(Event event, DummyPrSocket *adapter) {
+void Poller::Cancel(Event event, std::shared_ptr<DummyPrSocket> &adapter) {
   auto it = waiters_.find(adapter);
-  Waiter *waiter;
-
   if (it == waiters_.end()) {
     return;
   }
 
-  waiter = it->second;
-
+  auto &waiter = it->second;
   waiter->targets_[event] = nullptr;
   waiter->callbacks_[event] = nullptr;
 
   // Clean up if there are no callbacks.
   for (size_t i = 0; i < TIMER_EVENT; ++i) {
     if (waiter->callbacks_[i]) return;
   }
 
-  delete waiter;
   waiters_.erase(adapter);
 }
 
 void Poller::SetTimer(uint32_t timer_ms, PollTarget *target, PollCallback cb,
-                      Timer **timer) {
-  Timer *t = new Timer(PR_Now() + timer_ms * 1000, target, cb);
+                      std::shared_ptr<Timer> *timer) {
+  auto t = std::make_shared<Timer>(PR_Now() + timer_ms * 1000, target, cb);
   timers_.push(t);
   if (timer) *timer = t;
 }
 
 bool Poller::Poll() {
   if (g_ssl_gtest_verbose) {
     std::cerr << "Poll() waiters = " << waiters_.size()
               << " timers = " << timers_.size() << std::endl;
   }
   PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
   PRTime now = PR_Now();
   bool fired = false;
 
   // Figure out the timer for the select.
   if (!timers_.empty()) {
-    Timer *first_timer = timers_.top();
+    auto first_timer = timers_.top();
     if (now >= first_timer->deadline_) {
       // Timer expired.
       timeout = PR_INTERVAL_NO_WAIT;
     } else {
       timeout =
           PR_MillisecondsToInterval((first_timer->deadline_ - now) / 1000);
     }
   }
 
   for (auto it = waiters_.begin(); it != waiters_.end(); ++it) {
-    Waiter *waiter = it->second;
+    auto &waiter = it->second;
 
     if (waiter->callbacks_[READABLE_EVENT]) {
       if (waiter->io_->readable()) {
         PollCallback callback = waiter->callbacks_[READABLE_EVENT];
         PollTarget *target = waiter->targets_[READABLE_EVENT];
         waiter->callbacks_[READABLE_EVENT] = nullptr;
         waiter->targets_[READABLE_EVENT] = nullptr;
         callback(target, READABLE_EVENT);
@@ -517,20 +455,19 @@ bool Poller::Poll() {
     PR_Sleep(timeout);
   }
 
   // Now process anything that timed out.
   now = PR_Now();
   while (!timers_.empty()) {
     if (now < timers_.top()->deadline_) break;
 
-    Timer *timer = timers_.top();
+    auto timer = timers_.top();
     timers_.pop();
     if (timer->callback_) {
       timer->callback_(timer->target_, TIMER_EVENT);
     }
-    delete timer;
   }
 
   return true;
 }
 
 }  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/test_io.h
+++ b/security/nss/gtests/ssl_gtest/test_io.h
@@ -9,22 +9,23 @@
 
 #include <string.h>
 #include <map>
 #include <memory>
 #include <ostream>
 #include <queue>
 #include <string>
 
+#include "databuffer.h"
 #include "prio.h"
+#include "scoped_ptrs.h"
 
 namespace nss_test {
 
 class DataBuffer;
-class Packet;
 class DummyPrSocket;  // Fwd decl.
 
 // Allow us to inspect a packet before it is written.
 class PacketFilter {
  public:
   enum Action {
     KEEP,    // keep the original packet unmodified
     CHANGE,  // change the packet to a different value
@@ -45,51 +46,66 @@ class PacketFilter {
 enum Mode { STREAM, DGRAM };
 
 inline std::ostream& operator<<(std::ostream& os, Mode m) {
   return os << ((m == STREAM) ? "TLS" : "DTLS");
 }
 
 class DummyPrSocket {
  public:
-  ~DummyPrSocket();
+  DummyPrSocket(const std::string& name, Mode mode)
+      : name_(name),
+        mode_(mode),
+        peer_(),
+        input_(),
+        filter_(nullptr),
+        writeable_(true) {}
+  virtual ~DummyPrSocket() {}
 
-  static PRFileDesc* CreateFD(const std::string& name,
-                              Mode mode);  // Returns an FD.
-  static DummyPrSocket* GetAdapter(PRFileDesc* fd);
+  // Create a file descriptor that will reference this object.  The fd must not
+  // live longer than this adapter; call PR_Close() before.
+  ScopedPRFileDesc CreateFD();
 
-  DummyPrSocket* peer() const { return peer_; }
-  void SetPeer(DummyPrSocket* peer) { peer_ = peer; }
-  void SetPacketFilter(PacketFilter* filter);
+  std::weak_ptr<DummyPrSocket>& peer() { return peer_; }
+  void SetPeer(const std::shared_ptr<DummyPrSocket>& peer) { peer_ = peer; }
+  void SetPacketFilter(std::shared_ptr<PacketFilter> filter);
   // Drops peer, packet filter and any outstanding packets.
   void Reset();
 
   void PacketReceived(const DataBuffer& data);
   int32_t Read(void* data, int32_t len);
   int32_t Recv(void* buf, int32_t buflen);
   int32_t Write(const void* buf, int32_t length);
   void CloseWrites() { writeable_ = false; }
 
   Mode mode() const { return mode_; }
   bool readable() const { return !input_.empty(); }
 
  private:
-  DummyPrSocket(const std::string& name, Mode mode)
-      : name_(name),
-        mode_(mode),
-        peer_(nullptr),
-        input_(),
-        filter_(nullptr),
-        writeable_(true) {}
+  class Packet : public DataBuffer {
+   public:
+    Packet(const DataBuffer& buf) : DataBuffer(buf), offset_(0) {}
+
+    void Advance(size_t delta) {
+      PR_ASSERT(offset_ + delta <= len());
+      offset_ = std::min(len(), offset_ + delta);
+    }
+
+    size_t offset() const { return offset_; }
+    size_t remaining() const { return len() - offset_; }
+
+   private:
+    size_t offset_;
+  };
 
   const std::string name_;
   Mode mode_;
-  DummyPrSocket* peer_;
-  std::queue<Packet*> input_;
-  PacketFilter* filter_;
+  std::weak_ptr<DummyPrSocket> peer_;
+  std::queue<Packet> input_;
+  std::shared_ptr<PacketFilter> filter_;
   bool writeable_;
 };
 
 // Marker interface.
 class PollTarget {};
 
 enum Event { READABLE_EVENT, TIMER_EVENT /* Must be last */ };
 
@@ -106,47 +122,50 @@ class Poller {
         : deadline_(deadline), target_(target), callback_(callback) {}
     void Cancel() { callback_ = nullptr; }
 
     PRTime deadline_;
     PollTarget* target_;
     PollCallback callback_;
   };
 
-  void Wait(Event event, DummyPrSocket* adapter, PollTarget* target,
-            PollCallback cb);
-  void Cancel(Event event, DummyPrSocket* adapter);
+  void Wait(Event event, std::shared_ptr<DummyPrSocket>& adapter,
+            PollTarget* target, PollCallback cb);
+  void Cancel(Event event, std::shared_ptr<DummyPrSocket>& adapter);
   void SetTimer(uint32_t timer_ms, PollTarget* target, PollCallback cb,
-                Timer** handle);
+                std::shared_ptr<Timer>* handle);
   bool Poll();
 
  private:
   Poller() : waiters_(), timers_() {}
-  ~Poller();
+  ~Poller() {}
 
   class Waiter {
    public:
-    Waiter(DummyPrSocket* io) : io_(io) {
+    Waiter(std::shared_ptr<DummyPrSocket> io) : io_(io) {
       memset(&callbacks_[0], 0, sizeof(callbacks_));
     }
 
     void WaitFor(Event event, PollCallback callback);
 
-    DummyPrSocket* io_;
+    std::shared_ptr<DummyPrSocket> io_;
     PollTarget* targets_[TIMER_EVENT];
     PollCallback callbacks_[TIMER_EVENT];
   };
 
   class TimerComparator {
    public:
-    bool operator()(const Timer* lhs, const Timer* rhs) {
+    bool operator()(const std::shared_ptr<Timer> lhs,
+                    const std::shared_ptr<Timer> rhs) {
       return lhs->deadline_ > rhs->deadline_;
     }
   };
 
   static Poller* instance;
-  std::map<DummyPrSocket*, Waiter*> waiters_;
-  std::priority_queue<Timer*, std::vector<Timer*>, TimerComparator> timers_;
+  std::map<std::shared_ptr<DummyPrSocket>, std::unique_ptr<Waiter>> waiters_;
+  std::priority_queue<std::shared_ptr<Timer>,
+                      std::vector<std::shared_ptr<Timer>>, TimerComparator>
+      timers_;
 };
 
 }  // end of namespace
 
 #endif
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -41,21 +41,20 @@ const std::string TlsAgent::kServerEcdsa
 const std::string TlsAgent::kServerEcdsa521 = "ecdsa521";
 const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
 const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
 const std::string TlsAgent::kServerDsa = "dsa";
 
 TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode)
     : name_(name),
       mode_(mode),
+      role_(role),
       server_key_bits_(0),
-      pr_fd_(nullptr),
-      adapter_(nullptr),
+      adapter_(new DummyPrSocket(role_str(), mode)),
       ssl_fd_(nullptr),
-      role_(role),
       state_(STATE_INIT),
       timer_handle_(nullptr),
       falsestart_enabled_(false),
       expected_version_(0),
       expected_cipher_suite_(0),
       expect_resumption_(false),
       expect_client_auth_(false),
       can_falsestart_hook_called_(false),
@@ -73,30 +72,22 @@ TlsAgent::TlsAgent(const std::string& na
   memset(&info_, 0, sizeof(info_));
   memset(&csinfo_, 0, sizeof(csinfo_));
   SECStatus rv = SSL_VersionRangeGetDefault(
       mode_ == STREAM ? ssl_variant_stream : ssl_variant_datagram, &vrange_);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 TlsAgent::~TlsAgent() {
-  if (adapter_) {
-    Poller::Instance()->Cancel(READABLE_EVENT, adapter_);
-    // The adapter is closed when the FD closes.
-  }
   if (timer_handle_) {
     timer_handle_->Cancel();
   }
 
-  if (pr_fd_) {
-    PR_Close(pr_fd_);
-  }
-
-  if (ssl_fd_) {
-    PR_Close(ssl_fd_);
+  if (adapter_) {
+    Poller::Instance()->Cancel(READABLE_EVENT, adapter_);
   }
 }
 
 void TlsAgent::SetState(State state) {
   if (state_ == state) return;
 
   LOG("Changing state from " << state_ << " to " << state);
   state_ = state;
@@ -127,74 +118,81 @@ bool TlsAgent::ConfigServerCert(const st
   if (updateKeyBits) {
     ScopedSECKEYPublicKey pub(CERT_ExtractPublicKey(cert.get()));
     EXPECT_NE(nullptr, pub.get());
     if (!pub.get()) return false;
     server_key_bits_ = SECKEY_PublicKeyStrengthInBits(pub.get());
   }
 
   SECStatus rv =
-      SSL_ConfigSecureServer(ssl_fd_, nullptr, nullptr, ssl_kea_null);
+      SSL_ConfigSecureServer(ssl_fd(), nullptr, nullptr, ssl_kea_null);
   EXPECT_EQ(SECFailure, rv);
-  rv = SSL_ConfigServerCert(ssl_fd_, cert.get(), priv.get(), serverCertData,
+  rv = SSL_ConfigServerCert(ssl_fd(), cert.get(), priv.get(), serverCertData,
                             serverCertData ? sizeof(*serverCertData) : 0);
   return rv == SECSuccess;
 }
 
 bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
   // Don't set up twice
   if (ssl_fd_) return true;
 
+  ScopedPRFileDesc dummy_fd(adapter_->CreateFD());
+  EXPECT_NE(nullptr, dummy_fd);
+  if (!dummy_fd) {
+    return false;
+  }
   if (adapter_->mode() == STREAM) {
-    ssl_fd_ = SSL_ImportFD(modelSocket, pr_fd_);
+    ssl_fd_.reset(SSL_ImportFD(modelSocket, dummy_fd.get()));
   } else {
-    ssl_fd_ = DTLS_ImportFD(modelSocket, pr_fd_);
+    ssl_fd_.reset(DTLS_ImportFD(modelSocket, dummy_fd.get()));
   }
 
   EXPECT_NE(nullptr, ssl_fd_);
-  if (!ssl_fd_) return false;
-  pr_fd_ = nullptr;
+  if (!ssl_fd_) {
+    return false;
+  }
+  dummy_fd.release();  // Now subsumed by ssl_fd_.
 
-  SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
+  SECStatus rv = SSL_VersionRangeSet(ssl_fd(), &vrange_);
   EXPECT_EQ(SECSuccess, rv);
   if (rv != SECSuccess) return false;
 
   if (role_ == SERVER) {
     EXPECT_TRUE(ConfigServerCert(name_, true));
 
-    rv = SSL_SNISocketConfigHook(ssl_fd_, SniHook, this);
+    rv = SSL_SNISocketConfigHook(ssl_fd(), SniHook, this);
     EXPECT_EQ(SECSuccess, rv);
     if (rv != SECSuccess) return false;
 
     ScopedCERTCertList anchors(CERT_NewCertList());
-    rv = SSL_SetTrustAnchors(ssl_fd_, anchors.get());
+    rv = SSL_SetTrustAnchors(ssl_fd(), anchors.get());
     if (rv != SECSuccess) return false;
   } else {
-    rv = SSL_SetURL(ssl_fd_, "server");
+    rv = SSL_SetURL(ssl_fd(), "server");
     EXPECT_EQ(SECSuccess, rv);
     if (rv != SECSuccess) return false;
   }
 
-  rv = SSL_AuthCertificateHook(ssl_fd_, AuthCertificateHook, this);
+  rv = SSL_AuthCertificateHook(ssl_fd(), AuthCertificateHook, this);
   EXPECT_EQ(SECSuccess, rv);
   if (rv != SECSuccess) return false;
 
-  rv = SSL_HandshakeCallback(ssl_fd_, HandshakeCallback, this);
+  rv = SSL_HandshakeCallback(ssl_fd(), HandshakeCallback, this);
   EXPECT_EQ(SECSuccess, rv);
   if (rv != SECSuccess) return false;
 
   return true;
 }
 
 void TlsAgent::SetupClientAuth() {
   EXPECT_TRUE(EnsureTlsSetup());
   ASSERT_EQ(CLIENT, role_);
 
   EXPECT_EQ(SECSuccess,
-            SSL_GetClientAuthDataHook(ssl_fd_, GetClientAuthDataHook,
+            SSL_GetClientAuthDataHook(ssl_fd(), GetClientAuthDataHook,
                                       reinterpret_cast<void*>(this)));
 }
 
 SECStatus TlsAgent::GetClientAuthDataHook(void* self, PRFileDesc* fd,
                                           CERTDistNames* caNames,
                                           CERTCertificate** clientCert,
                                           SECKEYPrivateKey** clientKey) {
   TlsAgent* agent = reinterpret_cast<TlsAgent*>(self);
@@ -208,17 +206,17 @@ SECStatus TlsAgent::GetClientAuthDataHoo
   }
 
   *clientCert = cert.release();
   *clientKey = priv.release();
   return SECSuccess;
 }
 
 bool TlsAgent::GetPeerChainLength(size_t* count) {
-  CERTCertList* chain = SSL_PeerCertificateChain(ssl_fd_);
+  CERTCertList* chain = SSL_PeerCertificateChain(ssl_fd());
   if (!chain) return false;
   *count = 0;
 
   for (PRCList* cursor = PR_NEXT_LINK(&chain->list); cursor != &chain->list;
        cursor = PR_NEXT_LINK(cursor)) {
     CERTCertListNode* node = (CERTCertListNode*)cursor;
     std::cerr << node->cert->subjectName << std::endl;
     ++(*count);
@@ -229,38 +227,38 @@ bool TlsAgent::GetPeerChainLength(size_t
   return true;
 }
 
 void TlsAgent::RequestClientAuth(bool requireAuth) {
   EXPECT_TRUE(EnsureTlsSetup());
   ASSERT_EQ(SERVER, role_);
 
   EXPECT_EQ(SECSuccess,
-            SSL_OptionSet(ssl_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE));
-  EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd_, SSL_REQUIRE_CERTIFICATE,
+            SSL_OptionSet(ssl_fd(), SSL_REQUEST_CERTIFICATE, PR_TRUE));
+  EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd(), SSL_REQUIRE_CERTIFICATE,
                                       requireAuth ? PR_TRUE : PR_FALSE));
 
   EXPECT_EQ(SECSuccess, SSL_AuthCertificateHook(
-                            ssl_fd_, &TlsAgent::ClientAuthenticated, this));
+                            ssl_fd(), &TlsAgent::ClientAuthenticated, this));
   expect_client_auth_ = true;
 }
 
 void TlsAgent::StartConnect(PRFileDesc* model) {
   EXPECT_TRUE(EnsureTlsSetup(model));
 
   SECStatus rv;
-  rv = SSL_ResetHandshake(ssl_fd_, role_ == SERVER ? PR_TRUE : PR_FALSE);
+  rv = SSL_ResetHandshake(ssl_fd(), role_ == SERVER ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
   SetState(STATE_CONNECTING);
 }
 
 void TlsAgent::DisableAllCiphers() {
   for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
     SECStatus rv =
-        SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_FALSE);
+        SSL_CipherPrefSet(ssl_fd(), SSL_ImplementedCiphers[i], PR_FALSE);
     EXPECT_EQ(SECSuccess, rv);
   }
 }
 
 // Not actually all groups, just the onece that we are actually willing
 // to use.
 const std::vector<SSLNamedGroup> kAllDHEGroups = {
     ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
@@ -287,17 +285,17 @@ void TlsAgent::EnableCiphersByKeyExchang
     SSLCipherSuiteInfo csinfo;
 
     SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i], &csinfo,
                                           sizeof(csinfo));
     ASSERT_EQ(SECSuccess, rv);
     EXPECT_EQ(sizeof(csinfo), csinfo.length);
 
     if ((csinfo.keaType == kea) || (csinfo.keaType == ssl_kea_tls13_any)) {
-      rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
+      rv = SSL_CipherPrefSet(ssl_fd(), SSL_ImplementedCiphers[i], PR_TRUE);
       EXPECT_EQ(SECSuccess, rv);
     }
   }
 }
 
 void TlsAgent::EnableGroupsByKeyExchange(SSLKEAType kea) {
   switch (kea) {
     case ssl_kea_dh:
@@ -325,78 +323,78 @@ void TlsAgent::EnableCiphersByAuthType(S
     SSLCipherSuiteInfo csinfo;
 
     SECStatus rv = SSL_GetCipherSuiteInfo(SSL_ImplementedCiphers[i], &csinfo,
                                           sizeof(csinfo));
     ASSERT_EQ(SECSuccess, rv);
 
     if ((csinfo.authType == authType) ||
         (csinfo.keaType == ssl_kea_tls13_any)) {
-      rv = SSL_CipherPrefSet(ssl_fd_, SSL_ImplementedCiphers[i], PR_TRUE);
+      rv = SSL_CipherPrefSet(ssl_fd(), SSL_ImplementedCiphers[i], PR_TRUE);
       EXPECT_EQ(SECSuccess, rv);
     }
   }
 }
 
 void TlsAgent::EnableSingleCipher(uint16_t cipher) {
   DisableAllCiphers();
-  SECStatus rv = SSL_CipherPrefSet(ssl_fd_, cipher, PR_TRUE);
+  SECStatus rv = SSL_CipherPrefSet(ssl_fd(), cipher, PR_TRUE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups) {
   EXPECT_TRUE(EnsureTlsSetup());
-  SECStatus rv = SSL_NamedGroupConfig(ssl_fd_, &groups[0], groups.size());
+  SECStatus rv = SSL_NamedGroupConfig(ssl_fd(), &groups[0], groups.size());
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetSessionTicketsEnabled(bool en) {
   EXPECT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
+  SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_SESSION_TICKETS,
                                en ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetSessionCacheEnabled(bool en) {
   EXPECT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE, en ? PR_FALSE : PR_TRUE);
+  SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_NO_CACHE, en ? PR_FALSE : PR_TRUE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::Set0RttEnabled(bool en) {
   EXPECT_TRUE(EnsureTlsSetup());
 
   SECStatus rv =
-      SSL_OptionSet(ssl_fd_, SSL_ENABLE_0RTT_DATA, en ? PR_TRUE : PR_FALSE);
+      SSL_OptionSet(ssl_fd(), SSL_ENABLE_0RTT_DATA, en ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetFallbackSCSVEnabled(bool en) {
   EXPECT_TRUE(role_ == CLIENT && EnsureTlsSetup());
 
-  SECStatus rv =
-      SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALLBACK_SCSV, en ? PR_TRUE : PR_FALSE);
+  SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_FALLBACK_SCSV,
+                               en ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetShortHeadersEnabled() {
   EXPECT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSLInt_EnableShortHeaders(ssl_fd_);
+  SECStatus rv = SSLInt_EnableShortHeaders(ssl_fd());
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
   vrange_.min = minver;
   vrange_.max = maxver;
 
-  if (ssl_fd_) {
-    SECStatus rv = SSL_VersionRangeSet(ssl_fd_, &vrange_);
+  if (ssl_fd()) {
+    SECStatus rv = SSL_VersionRangeSet(ssl_fd(), &vrange_);
     EXPECT_EQ(SECSuccess, rv);
   }
 }
 
 void TlsAgent::GetVersionRange(uint16_t* minver, uint16_t* maxver) {
   *minver = vrange_.min;
   *maxver = vrange_.max;
 }
@@ -411,37 +409,37 @@ void TlsAgent::ExpectReadWriteError() { 
 
 void TlsAgent::ExpectShortHeaders() { expect_short_headers_ = true; }
 
 void TlsAgent::SetSignatureSchemes(const SSLSignatureScheme* schemes,
                                    size_t count) {
   EXPECT_TRUE(EnsureTlsSetup());
   EXPECT_LE(count, SSL_SignatureMaxCount());
   EXPECT_EQ(SECSuccess,
-            SSL_SignatureSchemePrefSet(ssl_fd_, schemes,
+            SSL_SignatureSchemePrefSet(ssl_fd(), schemes,
                                        static_cast<unsigned int>(count)));
-  EXPECT_EQ(SECFailure, SSL_SignatureSchemePrefSet(ssl_fd_, schemes, 0))
+  EXPECT_EQ(SECFailure, SSL_SignatureSchemePrefSet(ssl_fd(), schemes, 0))
       << "setting no schemes should fail and do nothing";
 
   std::vector<SSLSignatureScheme> configuredSchemes(count);
   unsigned int configuredCount;
   EXPECT_EQ(SECFailure,
-            SSL_SignatureSchemePrefGet(ssl_fd_, nullptr, &configuredCount, 1))
+            SSL_SignatureSchemePrefGet(ssl_fd(), nullptr, &configuredCount, 1))
       << "get schemes, schemes is nullptr";
   EXPECT_EQ(SECFailure,
-            SSL_SignatureSchemePrefGet(ssl_fd_, &configuredSchemes[0],
+            SSL_SignatureSchemePrefGet(ssl_fd(), &configuredSchemes[0],
                                        &configuredCount, 0))
       << "get schemes, too little space";
   EXPECT_EQ(SECFailure,
-            SSL_SignatureSchemePrefGet(ssl_fd_, &configuredSchemes[0], nullptr,
+            SSL_SignatureSchemePrefGet(ssl_fd(), &configuredSchemes[0], nullptr,
                                        configuredSchemes.size()))
       << "get schemes, countOut is nullptr";
 
   EXPECT_EQ(SECSuccess, SSL_SignatureSchemePrefGet(
-                            ssl_fd_, &configuredSchemes[0], &configuredCount,
+                            ssl_fd(), &configuredSchemes[0], &configuredCount,
                             configuredSchemes.size()));
   // SignatureSchemePrefSet drops unsupported algorithms silently, so the
   // number that are configured might be fewer.
   EXPECT_LE(configuredCount, count);
   unsigned int i = 0;
   for (unsigned int j = 0; j < count && i < configuredCount; ++j) {
     if (i < configuredCount && schemes[j] == configuredSchemes[i]) {
       ++i;
@@ -532,37 +530,37 @@ void TlsAgent::CheckAuthType(SSLAuthType
       break;
   }
 }
 
 void TlsAgent::EnableFalseStart() {
   EXPECT_TRUE(EnsureTlsSetup());
 
   falsestart_enabled_ = true;
+  EXPECT_EQ(SECSuccess, SSL_SetCanFalseStartCallback(
+                            ssl_fd(), CanFalseStartCallback, this));
   EXPECT_EQ(SECSuccess,
-            SSL_SetCanFalseStartCallback(ssl_fd_, CanFalseStartCallback, this));
-  EXPECT_EQ(SECSuccess,
-            SSL_OptionSet(ssl_fd_, SSL_ENABLE_FALSE_START, PR_TRUE));
+            SSL_OptionSet(ssl_fd(), SSL_ENABLE_FALSE_START, PR_TRUE));
 }
 
 void TlsAgent::ExpectResumption() { expect_resumption_ = true; }
 
 void TlsAgent::EnableAlpn(const uint8_t* val, size_t len) {
   EXPECT_TRUE(EnsureTlsSetup());
 
-  EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd_, SSL_ENABLE_ALPN, PR_TRUE));
-  EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd_, val, len));
+  EXPECT_EQ(SECSuccess, SSL_OptionSet(ssl_fd(), SSL_ENABLE_ALPN, PR_TRUE));
+  EXPECT_EQ(SECSuccess, SSL_SetNextProtoNego(ssl_fd(), val, len));
 }
 
 void TlsAgent::CheckAlpn(SSLNextProtoState expected_state,
                          const std::string& expected) const {
   SSLNextProtoState state;
   char chosen[10];
   unsigned int chosen_len;
-  SECStatus rv = SSL_GetNextProto(ssl_fd_, &state,
+  SECStatus rv = SSL_GetNextProto(ssl_fd(), &state,
                                   reinterpret_cast<unsigned char*>(chosen),
                                   &chosen_len, sizeof(chosen));
   EXPECT_EQ(SECSuccess, rv);
   EXPECT_EQ(expected_state, state);
   if (state == SSL_NEXT_PROTO_NO_SUPPORT) {
     EXPECT_EQ("", expected);
   } else {
     EXPECT_NE("", expected);
@@ -570,22 +568,22 @@ void TlsAgent::CheckAlpn(SSLNextProtoSta
   }
 }
 
 void TlsAgent::EnableSrtp() {
   EXPECT_TRUE(EnsureTlsSetup());
   const uint16_t ciphers[] = {SRTP_AES128_CM_HMAC_SHA1_80,
                               SRTP_AES128_CM_HMAC_SHA1_32};
   EXPECT_EQ(SECSuccess,
-            SSL_SetSRTPCiphers(ssl_fd_, ciphers, PR_ARRAY_SIZE(ciphers)));
+            SSL_SetSRTPCiphers(ssl_fd(), ciphers, PR_ARRAY_SIZE(ciphers)));
 }
 
 void TlsAgent::CheckSrtp() const {
   uint16_t actual;
-  EXPECT_EQ(SECSuccess, SSL_GetSRTPCipher(ssl_fd_, &actual));
+  EXPECT_EQ(SECSuccess, SSL_GetSRTPCipher(ssl_fd(), &actual));
   EXPECT_EQ(SRTP_AES128_CM_HMAC_SHA1_80, actual);
 }
 
 void TlsAgent::CheckErrorCode(int32_t expected) const {
   EXPECT_EQ(STATE_ERROR, state_);
   EXPECT_EQ(expected, error_code_)
       << "Got error code " << PORT_ErrorToName(error_code_) << " expecting "
       << PORT_ErrorToName(expected) << std::endl;
@@ -597,17 +595,17 @@ void TlsAgent::WaitForErrorCode(int32_t 
   EXPECT_EQ(expected, error_code_)
       << "Got error code " << PORT_ErrorToName(error_code_) << " expecting "
       << PORT_ErrorToName(expected) << std::endl;
 }
 
 void TlsAgent::CheckPreliminaryInfo() {
   SSLPreliminaryChannelInfo info;
   EXPECT_EQ(SECSuccess,
-            SSL_GetPreliminaryChannelInfo(ssl_fd_, &info, sizeof(info)));
+            SSL_GetPreliminaryChannelInfo(ssl_fd(), &info, sizeof(info)));
   EXPECT_EQ(sizeof(info), info.length);
   EXPECT_TRUE(info.valuesSet & ssl_preinfo_version);
   EXPECT_TRUE(info.valuesSet & ssl_preinfo_cipher_suite);
 
   // A version of 0 is invalid and indicates no expectation.  This value is
   // initialized to 0 so that tests that don't explicitly set an expected
   // version can negotiate a version.
   if (!expected_version_) {
@@ -627,17 +625,17 @@ void TlsAgent::CheckCallbacks() const {
   // If false start happens, the handshake is reported as being complete at the
   // point that false start happens.
   if (expect_resumption_ || !falsestart_enabled_) {
     EXPECT_TRUE(handshake_callback_called_);
   }
 
   // These callbacks shouldn't fire if we are resuming, except on TLS 1.3.
   if (role_ == SERVER) {
-    PRBool have_sni = SSLInt_ExtensionNegotiated(ssl_fd_, ssl_server_name_xtn);
+    PRBool have_sni = SSLInt_ExtensionNegotiated(ssl_fd(), ssl_server_name_xtn);
     EXPECT_EQ(((!expect_resumption_ && have_sni) ||
                expected_version_ >= SSL_LIBRARY_VERSION_TLS_1_3),
               sni_hook_called_);
   } else {
     EXPECT_EQ(!expect_resumption_, auth_certificate_hook_called_);
     // Note that this isn't unconditionally called, even with false start on.
     // But the callback is only skipped if a cipher that is ridiculously weak
     // (80 bits) is chosen.  Don't test that: plan to remove bad ciphers.
@@ -651,53 +649,53 @@ void TlsAgent::ResetPreliminaryInfo() {
   expected_cipher_suite_ = 0;
 }
 
 void TlsAgent::Connected() {
   LOG("Handshake success");
   CheckPreliminaryInfo();
   CheckCallbacks();
 
-  SECStatus rv = SSL_GetChannelInfo(ssl_fd_, &info_, sizeof(info_));
+  SECStatus rv = SSL_GetChannelInfo(ssl_fd(), &info_, sizeof(info_));
   EXPECT_EQ(SECSuccess, rv);
   EXPECT_EQ(sizeof(info_), info_.length);
 
   // Preliminary values are exposed through callbacks during the handshake.
   // If either expected values were set or the callbacks were called, check
   // that the final values are correct.
   EXPECT_EQ(expected_version_, info_.protocolVersion);
   EXPECT_EQ(expected_cipher_suite_, info_.cipherSuite);
 
   rv = SSL_GetCipherSuiteInfo(info_.cipherSuite, &csinfo_, sizeof(csinfo_));
   EXPECT_EQ(SECSuccess, rv);
   EXPECT_EQ(sizeof(csinfo_), csinfo_.length);
 
   if (expected_version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
-    PRInt32 cipherSuites = SSLInt_CountTls13CipherSpecs(ssl_fd_);
+    PRInt32 cipherSuites = SSLInt_CountTls13CipherSpecs(ssl_fd());
     // We use one ciphersuite in each direction, plus one that's kept around
     // by DTLS for retransmission.
     PRInt32 expected = ((mode_ == DGRAM) && (role_ == CLIENT)) ? 3 : 2;
     EXPECT_EQ(expected, cipherSuites);
     if (expected != cipherSuites) {
-      SSLInt_PrintTls13CipherSpecs(ssl_fd_);
+      SSLInt_PrintTls13CipherSpecs(ssl_fd());
     }
   }
 
   PRBool short_headers;
-  rv = SSLInt_UsingShortHeaders(ssl_fd_, &short_headers);
+  rv = SSLInt_UsingShortHeaders(ssl_fd(), &short_headers);
   EXPECT_EQ(SECSuccess, rv);
   EXPECT_EQ((PRBool)expect_short_headers_, short_headers);
   SetState(STATE_CONNECTED);
 }
 
 void TlsAgent::EnableExtendedMasterSecret() {
   ASSERT_TRUE(EnsureTlsSetup());
 
   SECStatus rv =
-      SSL_OptionSet(ssl_fd_, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
+      SSL_OptionSet(ssl_fd(), SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
 
   ASSERT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::CheckExtendedMasterSecret(bool expected) {
   if (version() >= SSL_LIBRARY_VERSION_TLS_1_3) {
     expected = PR_TRUE;
   }
@@ -709,44 +707,44 @@ void TlsAgent::CheckEarlyDataAccepted(bo
   if (version() < SSL_LIBRARY_VERSION_TLS_1_3) {
     expected = false;
   }
   ASSERT_EQ(expected, info_.earlyDataAccepted != PR_FALSE)
       << "unexpected early data state for " << name_;
 }
 
 void TlsAgent::CheckSecretsDestroyed() {
-  ASSERT_EQ(PR_TRUE, SSLInt_CheckSecretsDestroyed(ssl_fd_));
+  ASSERT_EQ(PR_TRUE, SSLInt_CheckSecretsDestroyed(ssl_fd()));
 }
 
 void TlsAgent::DisableRollbackDetection() {
   ASSERT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ROLLBACK_DETECTION, PR_FALSE);
+  SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ROLLBACK_DETECTION, PR_FALSE);
 
   ASSERT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::EnableCompression() {
   ASSERT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_DEFLATE, PR_TRUE);
+  SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_DEFLATE, PR_TRUE);
   ASSERT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SetDowngradeCheckVersion(uint16_t version) {
   ASSERT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSL_SetDowngradeCheckVersion(ssl_fd_, version);
+  SECStatus rv = SSL_SetDowngradeCheckVersion(ssl_fd(), version);
   ASSERT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::Handshake() {
   LOGV("Handshake");
-  SECStatus rv = SSL_ForceHandshake(ssl_fd_);
+  SECStatus rv = SSL_ForceHandshake(ssl_fd());
   if (rv == SECSuccess) {
     if (!falsestart_enabled_) {
       EXPECT_EQ(STATE_CONNECTED, state_)
           << "the handshake callback should have been called already";
     }
 
     Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
                              &TlsAgent::ReadableCallback);
@@ -758,17 +756,17 @@ void TlsAgent::Handshake() {
     LOGV("Would have blocked");
     if (mode_ == DGRAM) {
       if (timer_handle_) {
         timer_handle_->Cancel();
         timer_handle_ = nullptr;
       }
 
       PRIntervalTime timeout;
-      rv = DTLS_GetHandshakeTimeout(ssl_fd_, &timeout);
+      rv = DTLS_GetHandshakeTimeout(ssl_fd(), &timeout);
       if (rv == SECSuccess) {
         Poller::Instance()->SetTimer(
             timeout + 1, this, &TlsAgent::ReadableCallback, &timer_handle_);
       }
     }
     Poller::Instance()->Wait(READABLE_EVENT, adapter_, this,
                              &TlsAgent::ReadableCallback);
     return;
@@ -784,23 +782,28 @@ void TlsAgent::PrepareForRenegotiate() {
   EXPECT_EQ(STATE_CONNECTED, state_);
 
   SetState(STATE_CONNECTING);
 }
 
 void TlsAgent::StartRenegotiate() {
   PrepareForRenegotiate();
 
-  SECStatus rv = SSL_ReHandshake(ssl_fd_, PR_TRUE);
+  SECStatus rv = SSL_ReHandshake(ssl_fd(), PR_TRUE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::SendDirect(const DataBuffer& buf) {
   LOG("Send Direct " << buf);
-  adapter_->peer()->PacketReceived(buf);
+  auto peer = adapter_->peer().lock();
+  if (peer) {
+    peer->PacketReceived(buf);
+  } else {
+    LOG("Send Direct peer absent");
+  }
 }
 
 static bool ErrorIsNonFatal(PRErrorCode code) {
   return code == PR_WOULD_BLOCK_ERROR || code == SSL_ERROR_RX_SHORT_DTLS_READ;
 }
 
 void TlsAgent::SendData(size_t bytes, size_t blocksize) {
   uint8_t block[4096];
@@ -817,31 +820,31 @@ void TlsAgent::SendData(size_t bytes, si
 
     SendBuffer(DataBuffer(block, tosend));
     bytes -= tosend;
   }
 }
 
 void TlsAgent::SendBuffer(const DataBuffer& buf) {
   LOGV("Writing " << buf.len() << " bytes");
-  int32_t rv = PR_Write(ssl_fd_, buf.data(), buf.len());
+  int32_t rv = PR_Write(ssl_fd(), buf.data(), buf.len());
   if (expect_readwrite_error_) {
     EXPECT_GT(0, rv);
     EXPECT_NE(PR_WOULD_BLOCK_ERROR, error_code_);
     error_code_ = PR_GetError();
     expect_readwrite_error_ = false;
   } else {
     ASSERT_EQ(buf.len(), static_cast<size_t>(rv));
   }
 }
 
 void TlsAgent::ReadBytes() {
   uint8_t block[1024];
 
-  int32_t rv = PR_Read(ssl_fd_, block, sizeof(block));
+  int32_t rv = PR_Read(ssl_fd(), block, sizeof(block));
   LOGV("ReadBytes " << rv);
   int32_t err;
 
   if (rv >= 0) {
     size_t count = static_cast<size_t>(rv);
     for (size_t i = 0; i < count; ++i) {
       ASSERT_EQ(recv_ctr_ & 0xff, block[i]);
       recv_ctr_++;
@@ -864,64 +867,57 @@ void TlsAgent::ReadBytes() {
   }
 }
 
 void TlsAgent::ResetSentBytes() { send_ctr_ = 0; }
 
 void TlsAgent::ConfigureSessionCache(SessionResumptionMode mode) {
   EXPECT_TRUE(EnsureTlsSetup());
 
-  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_NO_CACHE,
+  SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_NO_CACHE,
                                mode & RESUME_SESSIONID ? PR_FALSE : PR_TRUE);
   EXPECT_EQ(SECSuccess, rv);
 
-  rv = SSL_OptionSet(ssl_fd_, SSL_ENABLE_SESSION_TICKETS,
+  rv = SSL_OptionSet(ssl_fd(), SSL_ENABLE_SESSION_TICKETS,
                      mode & RESUME_TICKET ? PR_TRUE : PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 void TlsAgent::DisableECDHEServerKeyReuse() {
   ASSERT_TRUE(EnsureTlsSetup());
   ASSERT_EQ(TlsAgent::SERVER, role_);
-  SECStatus rv = SSL_OptionSet(ssl_fd_, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
+  SECStatus rv = SSL_OptionSet(ssl_fd(), SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE);
   EXPECT_EQ(SECSuccess, rv);
 }
 
 static const std::string kTlsRolesAllArr[] = {"CLIENT", "SERVER"};
 ::testing::internal::ParamGenerator<std::string>
     TlsAgentTestBase::kTlsRolesAll = ::testing::ValuesIn(kTlsRolesAllArr);
 
 void TlsAgentTestBase::SetUp() {
   SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
 }
 
 void TlsAgentTestBase::TearDown() {
-  delete agent_;
+  agent_ = nullptr;
   SSL_ClearSessionCache();
   SSL_ShutdownServerSessionIDCache();
 }
 
 void TlsAgentTestBase::Reset(const std::string& server_name) {
-  delete agent_;
-  Init(server_name);
-}
-
-void TlsAgentTestBase::Init(const std::string& server_name) {
-  agent_ =
+  agent_.reset(
       new TlsAgent(role_ == TlsAgent::CLIENT ? TlsAgent::kClient : server_name,
-                   role_, mode_);
-  agent_->Init();
-  fd_ = DummyPrSocket::CreateFD(agent_->role_str(), mode_);
-  agent_->adapter()->SetPeer(DummyPrSocket::GetAdapter(fd_));
+                   role_, mode_));
+  agent_->adapter()->SetPeer(sink_adapter_);
   agent_->StartConnect();
 }
 
 void TlsAgentTestBase::EnsureInit() {
   if (!agent_) {
-    Init();
+    Reset();
   }
   const std::vector<SSLNamedGroup> groups = {
       ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
       ssl_grp_ffdhe_2048};
   agent_->ConfigNamedGroups(groups);
 }
 
 void TlsAgentTestBase::ProcessMessage(const DataBuffer& buffer,
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -39,16 +39,18 @@ enum SessionResumptionMode {
 
 class TlsAgent;
 
 const extern std::vector<SSLNamedGroup> kAllDHEGroups;
 const extern std::vector<SSLNamedGroup> kECDHEGroups;
 const extern std::vector<SSLNamedGroup> kFFDHEGroups;
 const extern std::vector<SSLNamedGroup> kFasterDHEGroups;
 
+// These functions are called from callbacks.  They use bare pointers because
+// TlsAgent sets up the callback and it doesn't know who owns it.
 typedef std::function<SECStatus(TlsAgent* agent, bool checksig, bool isServer)>
     AuthCertificateCallbackFunction;
 
 typedef std::function<void(TlsAgent* agent)> HandshakeCallbackFunction;
 
 typedef std::function<int32_t(TlsAgent* agent, const SECItem* srvNameArr,
                               PRUint32 srvNameArrSize)>
     SniCallbackFunction;
@@ -70,34 +72,26 @@ class TlsAgent : public PollTarget {
   static const std::string kServerEcdsa521;
   static const std::string kServerEcdhEcdsa;
   static const std::string kServerEcdhRsa;
   static const std::string kServerDsa;
 
   TlsAgent(const std::string& name, Role role, Mode mode);
   virtual ~TlsAgent();
 
-  bool Init() {
-    pr_fd_ = DummyPrSocket::CreateFD(role_str(), mode_);
-    if (!pr_fd_) return false;
-
-    adapter_ = DummyPrSocket::GetAdapter(pr_fd_);
-    if (!adapter_) return false;
-
-    return true;
+  void SetPeer(std::shared_ptr<TlsAgent>& peer) {
+    adapter_->SetPeer(peer->adapter_);
   }
 
-  void SetPeer(TlsAgent* peer) { adapter_->SetPeer(peer->adapter_); }
-
-  void SetPacketFilter(TlsRecordFilter* filter) {
+  void SetTlsRecordFilter(std::shared_ptr<TlsRecordFilter> filter) {
     filter->SetAgent(this);
     adapter_->SetPacketFilter(filter);
   }
 
-  void SetPacketFilter(PacketFilter* filter) {
+  void SetPacketFilter(std::shared_ptr<PacketFilter> filter) {
     adapter_->SetPacketFilter(filter);
   }
 
   void DeletePacketFilter() { adapter_->SetPacketFilter(nullptr); }
 
   void StartConnect(PRFileDesc* model = nullptr);
   void CheckKEA(SSLKEAType kea_type, SSLNamedGroup group,
                 size_t kea_size = 0) const;
@@ -172,25 +166,25 @@ class TlsAgent : public PollTarget {
   const std::string& name() const { return name_; }
 
   Role role() const { return role_; }
   std::string role_str() const { return role_ == SERVER ? "server" : "client"; }
 
   State state() const { return state_; }
 
   const CERTCertificate* peer_cert() const {
-    return SSL_PeerCertificate(ssl_fd_);
+    return SSL_PeerCertificate(ssl_fd_.get());
   }
 
   const char* state_str() const { return state_str(state()); }
 
   static const char* state_str(State state) { return states[state]; }
 
-  PRFileDesc* ssl_fd() const { return ssl_fd_; }
-  DummyPrSocket* adapter() { return adapter_; }
+  PRFileDesc* ssl_fd() const { return ssl_fd_.get(); }
+  std::shared_ptr<DummyPrSocket>& adapter() { return adapter_; }
 
   bool is_compressed() const {
     return info_.compressionMethod != ssl_compression_null;
   }
   uint16_t server_key_bits() const { return server_key_bits_; }
   uint16_t min_version() const { return vrange_.min; }
   uint16_t max_version() const { return vrange_.max; }
   uint16_t version() const {
@@ -343,23 +337,22 @@ class TlsAgent : public PollTarget {
   void DisableLameGroups();
   void ConfigStrongECGroups(bool en);
   void ConfigAllDHGroups(bool en);
   void CheckCallbacks() const;
   void Connected();
 
   const std::string name_;
   Mode mode_;
+  Role role_;
   uint16_t server_key_bits_;
-  PRFileDesc* pr_fd_;
-  DummyPrSocket* adapter_;
-  PRFileDesc* ssl_fd_;
-  Role role_;
+  std::shared_ptr<DummyPrSocket> adapter_;
+  ScopedPRFileDesc ssl_fd_;
   State state_;
-  Poller::Timer* timer_handle_;
+  std::shared_ptr<Poller::Timer> timer_handle_;
   bool falsestart_enabled_;
   uint16_t expected_version_;
   uint16_t expected_cipher_suite_;
   bool expect_resumption_;
   bool expect_client_auth_;
   bool can_falsestart_hook_called_;
   bool sni_hook_called_;
   bool auth_certificate_hook_called_;
@@ -382,22 +375,21 @@ inline std::ostream& operator<<(std::ost
   return stream << TlsAgent::state_str(state);
 }
 
 class TlsAgentTestBase : public ::testing::Test {
  public:
   static ::testing::internal::ParamGenerator<std::string> kTlsRolesAll;
 
   TlsAgentTestBase(TlsAgent::Role role, Mode mode)
-      : agent_(nullptr), fd_(nullptr), role_(role), mode_(mode) {}
-  ~TlsAgentTestBase() {
-    if (fd_) {
-      PR_Close(fd_);
-    }
-  }
+      : agent_(nullptr),
+        role_(role),
+        mode_(mode),
+        sink_adapter_(new DummyPrSocket("sink", mode)) {}
+  virtual ~TlsAgentTestBase() {}
 
   void SetUp();
   void TearDown();
 
   static void MakeRecord(Mode mode, uint8_t type, uint16_t version,
                          const uint8_t* buf, size_t len, DataBuffer* out,
                          uint64_t seq_num = 0);
   void MakeRecord(uint8_t type, uint16_t version, const uint8_t* buf,
@@ -421,20 +413,21 @@ class TlsAgentTestBase : public ::testin
   void Init(const std::string& server_name = TlsAgent::kServerRsa);
   void Reset(const std::string& server_name = TlsAgent::kServerRsa);
 
  protected:
   void EnsureInit();
   void ProcessMessage(const DataBuffer& buffer, TlsAgent::State expected_state,
                       int32_t error_code = 0);
 
-  TlsAgent* agent_;
-  PRFileDesc* fd_;
+  std::unique_ptr<TlsAgent> agent_;
   TlsAgent::Role role_;
   Mode mode_;
+  // This adapter is here just to accept packets from this agent.
+  std::shared_ptr<DummyPrSocket> sink_adapter_;
 };
 
 class TlsAgentTest : public TlsAgentTestBase,
                      public ::testing::WithParamInterface<
                          std::tuple<std::string, std::string>> {
  public:
   TlsAgentTest()
       : TlsAgentTestBase(ToRole(std::get<0>(GetParam())),
--- a/security/nss/gtests/ssl_gtest/tls_connect.cc
+++ b/security/nss/gtests/ssl_gtest/tls_connect.cc
@@ -174,33 +174,25 @@ void TlsConnectTestBase::ClearServerCach
 void TlsConnectTestBase::SetUp() {
   SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str());
   SSLInt_ClearSessionTicketKey();
   ClearStats();
   Init();
 }
 
 void TlsConnectTestBase::TearDown() {
-  delete client_;
-  delete server_;
-  if (client_model_) {
-    ASSERT_NE(server_model_, nullptr);
-    delete client_model_;
-    delete server_model_;
-  }
+  client_ = nullptr;
+  server_ = nullptr;
 
   SSL_ClearSessionCache();
   SSLInt_ClearSessionTicketKey();
   SSL_ShutdownServerSessionIDCache();
 }
 
 void TlsConnectTestBase::Init() {
-  EXPECT_TRUE(client_->Init());
-  EXPECT_TRUE(server_->Init());
-
   client_->SetPeer(server_);
   server_->SetPeer(client_);
 
   if (version_) {
     ConfigureVersion(version_);
   }
 }
 
@@ -208,21 +200,18 @@ void TlsConnectTestBase::Reset() {
   // Take a copy of the names because they are about to disappear.
   std::string server_name = server_->name();
   std::string client_name = client_->name();
   Reset(server_name, client_name);
 }
 
 void TlsConnectTestBase::Reset(const std::string& server_name,
                                const std::string& client_name) {
-  delete client_;
-  delete server_;
-
-  client_ = new TlsAgent(client_name, TlsAgent::CLIENT, mode_);
-  server_ = new TlsAgent(server_name, TlsAgent::SERVER, mode_);
+  client_.reset(new TlsAgent(client_name, TlsAgent::CLIENT, mode_));
+  server_.reset(new TlsAgent(server_name, TlsAgent::SERVER, mode_));
 
   Init();
 }
 
 void TlsConnectTestBase::ExpectResumption(SessionResumptionMode expected) {
   expected_resumption_mode_ = expected;
   if (expected != RESUME_NONE) {
     client_->ExpectResumption();
@@ -382,24 +371,22 @@ void TlsConnectTestBase::ConnectExpectFa
 }
 
 void TlsConnectTestBase::ConnectExpectFailOneSide(TlsAgent::Role failing_side) {
   server_->StartConnect();
   client_->StartConnect();
   client_->SetServerKeyBits(server_->server_key_bits());
   client_->Handshake();
   server_->Handshake();
-  TlsAgent* fail_agent;
 
+  auto failing_agent = server_;
   if (failing_side == TlsAgent::CLIENT) {
-    fail_agent = client_;
-  } else {
-    fail_agent = server_;
+    failing_agent = client_;
   }
-  ASSERT_TRUE_WAIT(fail_agent->state() == TlsAgent::STATE_ERROR, 5000);
+  ASSERT_TRUE_WAIT(failing_agent->state() == TlsAgent::STATE_ERROR, 5000);
 }
 
 void TlsConnectTestBase::ConfigureVersion(uint16_t version) {
   version_ = version;
   client_->SetVersionRange(version, version);
   server_->SetVersionRange(version, version);
 }
 
@@ -498,23 +485,21 @@ void TlsConnectTestBase::EnableAlpn(cons
   client_->EnableAlpn(val, len);
   server_->EnableAlpn(val, len);
 }
 
 void TlsConnectTestBase::EnsureModelSockets() {
   // Make sure models agents are available.
   if (!client_model_) {
     ASSERT_EQ(server_model_, nullptr);
-    client_model_ = new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, mode_);
-    server_model_ = new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, mode_);
+    client_model_.reset(
+        new TlsAgent(TlsAgent::kClient, TlsAgent::CLIENT, mode_));
+    server_model_.reset(
+        new TlsAgent(TlsAgent::kServerRsa, TlsAgent::SERVER, mode_));
   }
-
-  // Initialise agents.
-  ASSERT_TRUE(client_model_->Init());
-  ASSERT_TRUE(server_model_->Init());
 }
 
 void TlsConnectTestBase::CheckAlpn(const std::string& val) {
   client_->CheckAlpn(SSL_NEXT_PROTO_SELECTED, val);
   server_->CheckAlpn(SSL_NEXT_PROTO_NEGOTIATED, val);
 }
 
 void TlsConnectTestBase::EnableSrtp() {
@@ -642,26 +627,27 @@ TlsConnectTls12::TlsConnectTls12()
 TlsConnectTls12Plus::TlsConnectTls12Plus()
     : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
 
 TlsConnectTls13::TlsConnectTls13()
     : TlsConnectTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
 
 void TlsKeyExchangeTest::EnsureKeyShareSetup() {
   EnsureTlsSetup();
-  groups_capture_ = new TlsExtensionCapture(ssl_supported_groups_xtn);
-  shares_capture_ = new TlsExtensionCapture(ssl_tls13_key_share_xtn);
-  shares_capture2_ = new TlsExtensionCapture(ssl_tls13_key_share_xtn, true);
-  std::vector<PacketFilter*> captures;
-  captures.push_back(groups_capture_);
-  captures.push_back(shares_capture_);
-  captures.push_back(shares_capture2_);
-  client_->SetPacketFilter(new ChainedPacketFilter(captures));
-  capture_hrr_ =
-      new TlsInspectorRecordHandshakeMessage(kTlsHandshakeHelloRetryRequest);
+  groups_capture_ =
+      std::make_shared<TlsExtensionCapture>(ssl_supported_groups_xtn);
+  shares_capture_ =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn);
+  shares_capture2_ =
+      std::make_shared<TlsExtensionCapture>(ssl_tls13_key_share_xtn, true);
+  std::vector<std::shared_ptr<PacketFilter>> captures = {
+      groups_capture_, shares_capture_, shares_capture2_};
+  client_->SetPacketFilter(std::make_shared<ChainedPacketFilter>(captures));
+  capture_hrr_ = std::make_shared<TlsInspectorRecordHandshakeMessage>(
+      kTlsHandshakeHelloRetryRequest);
   server_->SetPacketFilter(capture_hrr_);
 }
 
 void TlsKeyExchangeTest::ConfigNamedGroups(
     const std::vector<SSLNamedGroup>& groups) {
   client_->ConfigNamedGroups(groups);
   server_->ConfigNamedGroups(groups);
 }
--- a/security/nss/gtests/ssl_gtest/tls_connect.h
+++ b/security/nss/gtests/ssl_gtest/tls_connect.h
@@ -107,20 +107,20 @@ class TlsConnectTestBase : public ::test
       std::function<bool()> post_clienthello_check = nullptr);
   void Receive(size_t amount);
   void ExpectExtendedMasterSecret(bool expected);
   void ExpectEarlyDataAccepted(bool expected);
   void DisableECDHEServerKeyReuse();
 
  protected:
   Mode mode_;
-  TlsAgent* client_;
-  TlsAgent* server_;
-  TlsAgent* client_model_;
-  TlsAgent* server_model_;
+  std::shared_ptr<TlsAgent> client_;
+  std::shared_ptr<TlsAgent> server_;
+  std::unique_ptr<TlsAgent> client_model_;
+  std::unique_ptr<TlsAgent> server_model_;
   uint16_t version_;
   SessionResumptionMode expected_resumption_mode_;
   std::vector<std::vector<uint8_t>> session_ids_;
 
   // A simple value of "a", "b".  Note that the preferred value of "a" is placed
   // at the end, because the NSS API follows the now defunct NPN specification,
   // which places the preferred (and default) entry at the end of the list.
   // NSS will move this final entry to the front when used with ALPN.
@@ -241,20 +241,20 @@ class TlsConnectDatagram13 : public TlsC
       : TlsConnectTestBase(DGRAM, SSL_LIBRARY_VERSION_TLS_1_3) {}
 };
 
 // A variant that is used only with Pre13.
 class TlsConnectGenericPre13 : public TlsConnectGeneric {};
 
 class TlsKeyExchangeTest : public TlsConnectGeneric {
  protected:
-  TlsExtensionCapture* groups_capture_;
-  TlsExtensionCapture* shares_capture_;
-  TlsExtensionCapture* shares_capture2_;
-  TlsInspectorRecordHandshakeMessage* capture_hrr_;
+  std::shared_ptr<TlsExtensionCapture> groups_capture_;
+  std::shared_ptr<TlsExtensionCapture> shares_capture_;
+  std::shared_ptr<TlsExtensionCapture> shares_capture2_;
+  std::shared_ptr<TlsInspectorRecordHandshakeMessage> capture_hrr_;
 
   void EnsureKeyShareSetup();
   void ConfigNamedGroups(const std::vector<SSLNamedGroup>& groups);
   std::vector<SSLNamedGroup> GetGroupDetails(const DataBuffer& ext);
   std::vector<SSLNamedGroup> GetShareDetails(const DataBuffer& ext);
   void CheckKEXDetails(const std::vector<SSLNamedGroup>& expectedGroups,
                        const std::vector<SSLNamedGroup>& expectedShares);
   void CheckKEXDetails(const std::vector<SSLNamedGroup>& expectedGroups,
--- a/security/nss/gtests/ssl_gtest/tls_filter.cc
+++ b/security/nss/gtests/ssl_gtest/tls_filter.cc
@@ -389,22 +389,16 @@ PacketFilter::Action TlsAlertRecorder::F
   if (lvl == kTlsAlertWarning) {  // not strong enough
     return KEEP;
   }
   level_ = lvl;
   (void)parser.Read(&description_);
   return KEEP;
 }
 
-ChainedPacketFilter::~ChainedPacketFilter() {
-  for (auto it = filters_.begin(); it != filters_.end(); ++it) {
-    delete *it;
-  }
-}
-
 PacketFilter::Action ChainedPacketFilter::Filter(const DataBuffer& input,
                                                  DataBuffer* output) {
   DataBuffer in(input);
   bool changed = false;
   for (auto it = filters_.begin(); it != filters_.end(); ++it) {
     PacketFilter::Action action = (*it)->Filter(in, output);
     if (action == DROP) {
       return DROP;
@@ -577,31 +571,31 @@ PacketFilter::Action TlsExtensionDropper
 }
 
 PacketFilter::Action AfterRecordN::FilterRecord(const TlsRecordHeader& header,
                                                 const DataBuffer& body,
                                                 DataBuffer* out) {
   if (counter_++ == record_) {
     DataBuffer buf;
     header.Write(&buf, 0, body);
-    src_->SendDirect(buf);
-    dest_->Handshake();
+    src_.lock()->SendDirect(buf);
+    dest_.lock()->Handshake();
     func_();
     return DROP;
   }
 
   return KEEP;
 }
 
 PacketFilter::Action TlsInspectorClientHelloVersionChanger::FilterHandshake(
     const HandshakeHeader& header, const DataBuffer& input,
     DataBuffer* output) {
   if (header.handshake_type() == kTlsHandshakeClientKeyExchange) {
     EXPECT_EQ(SECSuccess,
-              SSLInt_IncrementClientHandshakeVersion(server_->ssl_fd()));
+              SSLInt_IncrementClientHandshakeVersion(server_.lock()->ssl_fd()));
   }
   return KEEP;
 }
 
 PacketFilter::Action SelectiveDropFilter::Filter(const DataBuffer& input,
                                                  DataBuffer* output) {
   if (counter_ >= 32) {
     return KEEP;
--- a/security/nss/gtests/ssl_gtest/tls_filter.h
+++ b/security/nss/gtests/ssl_gtest/tls_filter.h
@@ -249,28 +249,28 @@ class TlsAlertRecorder : public TlsRecor
   uint8_t level_;
   uint8_t description_;
 };
 
 // Runs multiple packet filters in series.
 class ChainedPacketFilter : public PacketFilter {
  public:
   ChainedPacketFilter() {}
-  ChainedPacketFilter(const std::vector<PacketFilter*> filters)
+  ChainedPacketFilter(const std::vector<std::shared_ptr<PacketFilter>> filters)
       : filters_(filters.begin(), filters.end()) {}
-  virtual ~ChainedPacketFilter();
+  virtual ~ChainedPacketFilter() {}
 
   virtual PacketFilter::Action Filter(const DataBuffer& input,
                                       DataBuffer* output);
 
   // Takes ownership of the filter.
-  void Add(PacketFilter* filter) { filters_.push_back(filter); }
+  void Add(std::shared_ptr<PacketFilter> filter) { filters_.push_back(filter); }
 
  private:
-  std::vector<PacketFilter*> filters_;
+  std::vector<std::shared_ptr<PacketFilter>> filters_;
 };
 
 class TlsExtensionFilter : public TlsHandshakeFilter {
  protected:
   PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
                                        const DataBuffer& input,
                                        DataBuffer* output) override;
 
@@ -332,44 +332,45 @@ class TlsExtensionDropper : public TlsEx
   uint16_t extension_;
 };
 
 class TlsAgent;
 typedef std::function<void(void)> VoidFunction;
 
 class AfterRecordN : public TlsRecordFilter {
  public:
-  AfterRecordN(TlsAgent* src, TlsAgent* dest, unsigned int record,
-               VoidFunction func)
+  AfterRecordN(std::shared_ptr<TlsAgent>& src, std::shared_ptr<TlsAgent>& dest,
+               unsigned int record, VoidFunction func)
       : src_(src), dest_(dest), record_(record), func_(func), counter_(0) {}
 
   virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
                                             const DataBuffer& body,
                                             DataBuffer* out) override;
 
  private:
-  TlsAgent* src_;
-  TlsAgent* dest_;
+  std::weak_ptr<TlsAgent> src_;
+  std::weak_ptr<TlsAgent> dest_;
   unsigned int record_;
   VoidFunction func_;
   unsigned int counter_;
 };
 
 // When we see the ClientKeyExchange from |client|, increment the
 // ClientHelloVersion on |server|.
 class TlsInspectorClientHelloVersionChanger : public TlsHandshakeFilter {
  public:
-  TlsInspectorClientHelloVersionChanger(TlsAgent* server) : server_(server) {}
+  TlsInspectorClientHelloVersionChanger(std::shared_ptr<TlsAgent>& server)
+      : server_(server) {}
 
   virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
                                                const DataBuffer& input,
                                                DataBuffer* output);
 
  private:
-  TlsAgent* server_;
+  std::weak_ptr<TlsAgent> server_;
 };
 
 // This class selectively drops complete writes.  This relies on the fact that
 // writes in libssl are on record boundaries.
 class SelectiveDropFilter : public PacketFilter {
  public:
   SelectiveDropFilter(uint32_t pattern) : pattern_(pattern), counter_(0) {}
 
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -5,23 +5,25 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = [ "LoginManagerContent",
                           "LoginFormFactory",
                           "UserAutoCompleteResult" ];
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 const PASSWORD_INPUT_ADDED_COALESCING_THRESHOLD_MS = 1;
+const AUTOCOMPLETE_AFTER_CONTEXTMENU_THRESHOLD_MS = 250;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Cu.import("resource://gre/modules/InsecurePasswordUtils.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FormLikeFactory",
                                   "resource://gre/modules/FormLikeFactory.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LoginRecipesContent",
                                   "resource://gre/modules/LoginRecipes.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
                                   "resource://gre/modules/LoginHelper.jsm");
@@ -34,21 +36,23 @@ XPCOMUtils.defineLazyServiceGetter(this,
 
 XPCOMUtils.defineLazyGetter(this, "log", () => {
   let logger = LoginHelper.createLogger("LoginManagerContent");
   return logger.log.bind(logger);
 });
 
 // These mirror signon.* prefs.
 var gEnabled, gAutofillForms, gStoreWhenAutocompleteOff;
+var gLastContextMenuEventTimeStamp = Number.NEGATIVE_INFINITY;
 
 var observer = {
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIObserver,
                                           Ci.nsIFormSubmitObserver,
                                           Ci.nsIWebProgressListener,
+                                          Ci.nsIDOMEventListener,
                                           Ci.nsISupportsWeakReference]),
 
   // nsIFormSubmitObserver
   notify(formElement, aWindow, actionURI) {
     log("observer notified for form submission.");
 
     // We're invoked before the content's |onsubmit| handlers, so we
     // can grab form data before it might be modified (see bug 257781).
@@ -103,16 +107,43 @@ var observer = {
     if (!(aWebProgress.loadType & Ci.nsIDocShell.LOAD_CMD_NORMAL)) {
       log("onStateChange: loadType isn't LOAD_CMD_NORMAL:", aWebProgress.loadType);
       return;
     }
 
     log("onStateChange handled:", channel);
     LoginManagerContent._onNavigation(aWebProgress.DOMWindow.document);
   },
+
+  handleEvent(aEvent) {
+    if (!aEvent.isTrusted) {
+      return;
+    }
+
+    if (!gEnabled) {
+      return;
+    }
+
+    switch (aEvent.type) {
+      // Only used for username fields.
+      case "focus": {
+        LoginManagerContent._onUsernameFocus(aEvent);
+        break;
+      }
+
+      case "contextmenu": {
+        gLastContextMenuEventTimeStamp = aEvent.timeStamp;
+        break;
+      }
+
+      default: {
+        throw new Error("Unexpected event");
+      }
+    }
+  },
 };
 
 Services.obs.addObserver(observer, "earlyformsubmit", false);
 var prefBranch = Services.prefs.getBranch("signon.");
 prefBranch.addObserver("", observer.onPrefChange, false);
 
 observer.onPrefChange(); // read initial values
 
@@ -427,16 +458,20 @@ var LoginManagerContent = {
   /**
    * Retrieves a reference to the state object associated with the given
    * document. This is initialized to an object with default values.
    */
   stateForDocument(document) {
     let loginFormState = this.loginFormStateByDocument.get(document);
     if (!loginFormState) {
       loginFormState = {
+        /**
+         * Keeps track of filled fields and values.
+         */
+        fillsByRootElement: new WeakMap(),
         loginFormRootElements: new Set(),
       };
       this.loginFormStateByDocument.set(document, loginFormState);
     }
     return loginFormState;
   },
 
   /**
@@ -517,19 +552,58 @@ var LoginManagerContent = {
 
   loginsFound({ form, loginsFound, recipes }) {
     let doc = form.ownerDocument;
     let autofillForm = gAutofillForms && !PrivateBrowsingUtils.isContentWindowPrivate(doc.defaultView);
 
     this._fillForm(form, autofillForm, false, false, false, loginsFound, recipes);
   },
 
-  /*
-   * onUsernameInput
-   *
+  /**
+   * Focus event handler for username fields to decide whether to show autocomplete.
+   * @param {FocusEvent} event
+   */
+  _onUsernameFocus(event) {
+    let focusedField = event.target;
+    if (!focusedField.mozIsTextField(true) || focusedField.readOnly) {
+      return;
+    }
+
+    if (this._isLoginAlreadyFilled(focusedField)) {
+      log("_onUsernameFocus: Already filled");
+      return;
+    }
+
+    /*
+     * A `focus` event is fired before a `contextmenu` event if a user right-clicks into an
+     * unfocused field. In that case we don't want to show both autocomplete and a context menu
+     * overlapping so we spin the event loop to see if a `contextmenu` event is coming next. If no
+     * `contextmenu` event was seen and the focused field is still focused by the form fill
+     * controller then show the autocomplete popup.
+     */
+    setTimeout(function maybeOpenAutocompleteAfterFocus() {
+      // Even though the `focus` event happens first, its .timeStamp is greater in
+      // testing and I don't want to rely on that so the absolute value is used.
+      let timeDiff = Math.abs(gLastContextMenuEventTimeStamp - event.timeStamp);
+      if (timeDiff < AUTOCOMPLETE_AFTER_CONTEXTMENU_THRESHOLD_MS) {
+        log("Not opening autocomplete after focus since a context menu was opened within",
+            timeDiff, "ms");
+        return;
+      }
+
+      if (this._formFillService.focusedInput == focusedField) {
+        log("maybeOpenAutocompleteAfterFocus: Opening the autocomplete popup");
+        this._formFillService.showPopup();
+      } else {
+        log("maybeOpenAutocompleteAfterFocus: FormFillController has a different focused input");
+      }
+    }.bind(this), 0);
+  },
+
+  /**
    * Listens for DOMAutoComplete and blur events on an input field.
    */
   onUsernameInput(event) {
     if (!event.isTrusted)
       return;
 
     if (!gEnabled)
       return;
@@ -897,67 +971,64 @@ var LoginManagerContent = {
                                       oldPasswordField: mockOldPassword },
                                     { openerTopWindow });
   },
 
   /**
    * Attempt to find the username and password fields in a form, and fill them
    * in using the provided logins and recipes.
    *
-   * @param {HTMLFormElement} form
+   * @param {LoginForm} form
    * @param {bool} autofillForm denotes if we should fill the form in automatically
    * @param {bool} clobberUsername controls if an existing username can be overwritten.
    *                               If this is false and an inputElement of type password
    *                               is also passed, the username field will be ignored.
    *                               If this is false and no inputElement is passed, if the username
    *                               field value is not found in foundLogins, it will not fill the password.
    * @param {bool} clobberPassword controls if an existing password value can be
    *                               overwritten
    * @param {bool} userTriggered is an indication of whether this filling was triggered by
    *                             the user
    * @param {nsILoginInfo[]} foundLogins is an array of nsILoginInfo that could be used for the form
    * @param {Set} recipes that could be used to affect how the form is filled
    * @param {Object} [options = {}] is a list of options for this method.
             - [inputElement] is an optional target input element we want to fill
    */
   _fillForm(form, autofillForm, clobberUsername, clobberPassword,
-                        userTriggered, foundLogins, recipes, {inputElement} = {}) {
+            userTriggered, foundLogins, recipes, {inputElement} = {}) {
+    if (form instanceof Ci.nsIDOMHTMLFormElement) {
+      throw new Error("_fillForm should only be called with FormLike objects");
+    }
+
     log("_fillForm", form.elements);
     let ignoreAutocomplete = true;
+    // Will be set to one of AUTOFILL_RESULT in the `try` block.
+    let autofillResult = -1;
     const AUTOFILL_RESULT = {
       FILLED: 0,
       NO_PASSWORD_FIELD: 1,
       PASSWORD_DISABLED_READONLY: 2,
       NO_LOGINS_FIT: 3,
       NO_SAVED_LOGINS: 4,
       EXISTING_PASSWORD: 5,
       EXISTING_USERNAME: 6,
       MULTIPLE_LOGINS: 7,
       NO_AUTOFILL_FORMS: 8,
       AUTOCOMPLETE_OFF: 9,
       INSECURE: 10,
     };
 
-    function recordAutofillResult(result) {
-      if (userTriggered) {
-        // Ignore fills as a result of user action.
-        return;
-      }
-      const autofillResultHist = Services.telemetry.getHistogramById("PWMGR_FORM_AUTOFILL_RESULT");
-      autofillResultHist.add(result);
-    }
-
     try {
       // Nothing to do if we have no matching logins available,
       // and there isn't a need to show the insecure form warning.
       if (foundLogins.length == 0 &&
           (InsecurePasswordUtils.isFormSecure(form) ||
           !LoginHelper.showInsecureFieldWarning)) {
         // We don't log() here since this is a very common case.
-        recordAutofillResult(AUTOFILL_RESULT.NO_SAVED_LOGINS);
+        autofillResult = AUTOFILL_RESULT.NO_SAVED_LOGINS;
         return;
       }
 
       // Heuristically determine what the user/pass fields are
       // We do this before checking to see if logins are stored,
       // so that the user isn't prompted for a master password
       // without need.
       var [usernameField, passwordField, ignored] =
@@ -977,26 +1048,24 @@ var LoginManagerContent = {
         } else {
           throw new Error("Unexpected input element type.");
         }
       }
 
       // Need a valid password field to do anything.
       if (passwordField == null) {
         log("not filling form, no password field found");
-        recordAutofillResult(AUTOFILL_RESULT.NO_PASSWORD_FIELD);
+        autofillResult = AUTOFILL_RESULT.NO_PASSWORD_FIELD;
         return;
       }
 
-      this._formFillService.markAsLoginManagerField(passwordField);
-
       // If the password field is disabled or read-only, there's nothing to do.
       if (passwordField.disabled || passwordField.readOnly) {
         log("not filling form, password field disabled or read-only");
-        recordAutofillResult(AUTOFILL_RESULT.PASSWORD_DISABLED_READONLY);
+        autofillResult = AUTOFILL_RESULT.PASSWORD_DISABLED_READONLY;
         return;
       }
 
       // Attach autocomplete stuff to the username field, if we have
       // one. This is normally used to select from multiple accounts,
       // but even with one account we should refill if the user edits.
       // We would also need this attached to show the insecure login
       // warning, regardless of saved login.
@@ -1004,25 +1073,25 @@ var LoginManagerContent = {
         this._formFillService.markAsLoginManagerField(usernameField);
       }
 
       // Nothing to do if we have no matching logins available.
       // Only insecure pages reach this block and logs the same
       // telemetry flag.
       if (foundLogins.length == 0) {
         // We don't log() here since this is a very common case.
-        recordAutofillResult(AUTOFILL_RESULT.NO_SAVED_LOGINS);
+        autofillResult = AUTOFILL_RESULT.NO_SAVED_LOGINS;
         return;
       }
 
       // Prevent autofilling insecure forms.
       if (!userTriggered && !LoginHelper.insecureAutofill &&
           !InsecurePasswordUtils.isFormSecure(form)) {
         log("not filling form since it's insecure");
-        recordAutofillResult(AUTOFILL_RESULT.INSECURE);
+        autofillResult = AUTOFILL_RESULT.INSECURE;
         return;
       }
 
       var isAutocompleteOff = false;
       if (this._isAutocompleteDisabled(form) ||
           this._isAutocompleteDisabled(usernameField) ||
           this._isAutocompleteDisabled(passwordField)) {
         isAutocompleteOff = true;
@@ -1047,41 +1116,41 @@ var LoginManagerContent = {
         if (!fit)
           log("Ignored", l.username, "login: won't fit");
 
         return fit;
       }, this);
 
       if (logins.length == 0) {
         log("form not filled, none of the logins fit in the field");
-        recordAutofillResult(AUTOFILL_RESULT.NO_LOGINS_FIT);
+        autofillResult = AUTOFILL_RESULT.NO_LOGINS_FIT;
         return;
       }
 
       // Don't clobber an existing password.
       if (passwordField.value && !clobberPassword) {
         log("form not filled, the password field was already filled");
-        recordAutofillResult(AUTOFILL_RESULT.EXISTING_PASSWORD);
+        autofillResult = AUTOFILL_RESULT.EXISTING_PASSWORD;
         return;
       }
 
       // Select a login to use for filling in the form.
       var selectedLogin;
       if (!clobberUsername && usernameField && (usernameField.value ||
                                                 usernameField.disabled ||
                                                 usernameField.readOnly)) {
         // If username was specified in the field, it's disabled or it's readOnly, only fill in the
         // password if we find a matching login.
         var username = usernameField.value.toLowerCase();
 
         let matchingLogins = logins.filter(l =>
                                            l.username.toLowerCase() == username);
         if (matchingLogins.length == 0) {
           log("Password not filled. None of the stored logins match the username already present.");
-          recordAutofillResult(AUTOFILL_RESULT.EXISTING_USERNAME);
+          autofillResult = AUTOFILL_RESULT.EXISTING_USERNAME;
           return;
         }
 
         // If there are multiple, and one matches case, use it
         for (let l of matchingLogins) {
           if (l.username == usernameField.value) {
             selectedLogin = l;
           }
@@ -1100,34 +1169,34 @@ var LoginManagerContent = {
         let matchingLogins;
         if (usernameField)
           matchingLogins = logins.filter(l => l.username);
         else
           matchingLogins = logins.filter(l => !l.username);
 
         if (matchingLogins.length != 1) {
           log("Multiple logins for form, so not filling any.");
-          recordAutofillResult(AUTOFILL_RESULT.MULTIPLE_LOGINS);
+          autofillResult = AUTOFILL_RESULT.MULTIPLE_LOGINS;
           return;
         }
 
         selectedLogin = matchingLogins[0];
       }
 
       // We will always have a selectedLogin at this point.
 
       if (!autofillForm) {
         log("autofillForms=false but form can be filled");
-        recordAutofillResult(AUTOFILL_RESULT.NO_AUTOFILL_FORMS);
+        autofillResult = AUTOFILL_RESULT.NO_AUTOFILL_FORMS;
         return;
       }
 
       if (isAutocompleteOff && !ignoreAutocomplete) {
         log("Not filling the login because we're respecting autocomplete=off");
-        recordAutofillResult(AUTOFILL_RESULT.AUTOCOMPLETE_OFF);
+        autofillResult = AUTOFILL_RESULT.AUTOCOMPLETE_OFF;
         return;
       }
 
       // Fill the form
 
       if (usernameField) {
       // Don't modify the username field if it's disabled or readOnly so we preserve its case.
         let disabledOrReadOnly = usernameField.disabled || usernameField.readOnly;
@@ -1138,32 +1207,114 @@ var LoginManagerContent = {
         // is desired.
         let userEnteredDifferentCase = userTriggered && userNameDiffers &&
                usernameField.value.toLowerCase() == selectedLogin.username.toLowerCase();
 
         if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) {
           usernameField.setUserInput(selectedLogin.username);
         }
       }
+
+      let doc = form.ownerDocument;
       if (passwordField.value != selectedLogin.password) {
         passwordField.setUserInput(selectedLogin.password);
+        let autoFilledLogin = {
+          guid: selectedLogin.QueryInterface(Ci.nsILoginMetaInfo).guid,
+          username: selectedLogin.username,
+          usernameField: usernameField ? Cu.getWeakReference(usernameField) : null,
+          password: selectedLogin.password,
+          passwordField: Cu.getWeakReference(passwordField),
+        };
+        log("Saving autoFilledLogin", autoFilledLogin.guid, "for", form.rootElement);
+        this.stateForDocument(doc).fillsByRootElement.set(form.rootElement, autoFilledLogin);
       }
 
       log("_fillForm succeeded");
-      recordAutofillResult(AUTOFILL_RESULT.FILLED);
-      let doc = form.ownerDocument;
+      autofillResult = AUTOFILL_RESULT.FILLED;
+
       let win = doc.defaultView;
       let messageManager = messageManagerFromWindow(win);
       messageManager.sendAsyncMessage("LoginStats:LoginFillSuccessful");
     } finally {
+      if (autofillResult == -1) {
+        // eslint-disable-next-line no-unsafe-finally
+        throw new Error("_fillForm: autofillResult must be specified");
+      }
+
+      if (!userTriggered) {
+        // Ignore fills as a result of user action for this probe.
+        Services.telemetry.getHistogramById("PWMGR_FORM_AUTOFILL_RESULT").add(autofillResult);
+
+        if (usernameField) {
+          let focusedElement = this._formFillService.focusedInput;
+          if (usernameField == focusedElement &&
+              autofillResult !== AUTOFILL_RESULT.FILLED) {
+            log("_fillForm: Opening username autocomplete popup since the form wasn't autofilled");
+            this._formFillService.showPopup();
+          }
+        }
+      }
+
+      if (usernameField) {
+        log("_fillForm: Attaching event listeners to usernameField");
+        usernameField.addEventListener("focus", observer);
+        usernameField.addEventListener("contextmenu", observer);
+      }
+
       Services.obs.notifyObservers(form.rootElement, "passwordmgr-processed-form", null);
     }
   },
 
   /**
+   * Given a field, determine whether that field was last filled as a username
+   * field AND whether the username is still filled in with the username AND
+   * whether the associated password field has the matching password.
+   *
+   * @note This could possibly be unified with getFieldContext but they have
+   * slightly different use cases. getFieldContext looks up recipes whereas this
+   * method doesn't need to since it's only returning a boolean based upon the
+   * recipes used for the last fill (in _fillForm).
+   *
+   * @param {HTMLInputElement} aUsernameField element contained in a FormLike
+   *                                          cached in _formLikeByRootElement.
+   * @returns {Boolean} whether the username and password fields still have the
+   *                    last-filled values, if previously filled.
+   */
+  _isLoginAlreadyFilled(aUsernameField) {
+    let formLikeRoot = FormLikeFactory.findRootForField(aUsernameField);
+    // Look for the existing FormLike.
+    let existingFormLike = this._formLikeByRootElement.get(formLikeRoot);
+    if (!existingFormLike) {
+      throw new Error("_isLoginAlreadyFilled called with a username field with " +
+                      "no rootElement FormLike");
+    }
+
+    log("_isLoginAlreadyFilled: existingFormLike", existingFormLike);
+    let filledLogin = this.stateForDocument(aUsernameField.ownerDocument).fillsByRootElement.get(formLikeRoot);
+    if (!filledLogin) {
+      return false;
+    }
+
+    // Unpack the weak references.
+    let autoFilledUsernameField = filledLogin.usernameField ? filledLogin.usernameField.get() : null;
+    let autoFilledPasswordField = filledLogin.passwordField.get();
+
+    // Check username and password values match what was filled.
+    if (!autoFilledUsernameField ||
+        autoFilledUsernameField != aUsernameField ||
+        autoFilledUsernameField.value != filledLogin.username ||
+        !autoFilledPasswordField ||
+        autoFilledPasswordField.value != filledLogin.password) {
+      return false;
+    }
+
+    return true;
+  },
+
+  /**
    * Verify if a field is a valid login form field and
    * returns some information about it's FormLike.
    *
    * @param {Element} aField
    *                  A form field we want to verify.
    *
    * @returns {Object} an object with information about the
    *                   FormLike username and password field
--- a/toolkit/components/passwordmgr/test/browser/browser.ini
+++ b/toolkit/components/passwordmgr/test/browser/browser.ini
@@ -33,16 +33,17 @@ support-files =
 [browser_capture_doorhanger_httpsUpgrade.js]
 support-files =
   subtst_notifications_1.html
   subtst_notifications_8.html
 [browser_capture_doorhanger_window_open.js]
 support-files =
   subtst_notifications_11.html
   subtst_notifications_11_popup.html
+[browser_context_menu_autocomplete_interaction.js]
 [browser_username_select_dialog.js]
 support-files =
   subtst_notifications_change_p.html
 [browser_DOMFormHasPassword.js]
 [browser_DOMInputPasswordAdded.js]
 [browser_exceptions_dialog.js]
 [browser_formless_submit_chrome.js]
 [browser_hasInsecureLoginForms.js]
--- a/toolkit/components/passwordmgr/test/browser/browser_autocomplete_insecure_warning.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_autocomplete_insecure_warning.js
@@ -10,16 +10,19 @@ add_task(function* test_clickInsecureFie
     gBrowser,
     url,
   }, function*(browser) {
     let popup = document.getElementById("PopupAutoComplete");
     ok(popup, "Got popup");
 
     let promiseShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
 
+    yield SimpleTest.promiseFocus(browser);
+    info("content window focused");
+
     // Focus the username field to open the popup.
     yield ContentTask.spawn(browser, null, function openAutocomplete() {
       content.document.getElementById("form-basic-username").focus();
     });
 
     yield promiseShown;
     ok(promiseShown, "autocomplete shown");
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_context_menu_autocomplete_interaction.js
@@ -0,0 +1,99 @@
+/*
+ * Test the password manager context menu interaction with autocomplete.
+ */
+
+"use strict";
+
+const TEST_HOSTNAME = "https://example.com";
+const BASIC_FORM_PAGE_PATH = DIRECTORY_PATH + "form_basic.html";
+
+var gUnexpectedIsTODO = false;
+
+/**
+ * Initialize logins needed for the tests and disable autofill
+ * for login forms for easier testing of manual fill.
+ */
+add_task(function* test_initialize() {
+  let autocompletePopup = document.getElementById("PopupAutoComplete");
+  Services.prefs.setBoolPref("signon.autofillForms", false);
+  registerCleanupFunction(() => {
+    Services.prefs.clearUserPref("signon.autofillForms");
+    autocompletePopup.removeEventListener("popupshowing", autocompleteUnexpectedPopupShowing);
+  });
+  for (let login of loginList()) {
+    Services.logins.addLogin(login);
+  }
+  autocompletePopup.addEventListener("popupshowing", autocompleteUnexpectedPopupShowing);
+});
+
+add_task(function* test_context_menu_username() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: TEST_HOSTNAME + BASIC_FORM_PAGE_PATH,
+  }, function* (browser) {
+    yield openContextMenu(browser, "#form-basic-username");
+
+    let contextMenu = document.getElementById("contentAreaContextMenu");
+    Assert.equal(contextMenu.state, "open", "Context menu opened");
+    contextMenu.hidePopup();
+  });
+});
+
+add_task(function* test_context_menu_password() {
+  gUnexpectedIsTODO = true;
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: TEST_HOSTNAME + BASIC_FORM_PAGE_PATH,
+  }, function* (browser) {
+    yield openContextMenu(browser, "#form-basic-password");
+
+    let contextMenu = document.getElementById("contentAreaContextMenu");
+    Assert.equal(contextMenu.state, "open", "Context menu opened");
+    contextMenu.hidePopup();
+  });
+});
+
+function autocompleteUnexpectedPopupShowing(event) {
+  if (gUnexpectedIsTODO) {
+    todo(false, "Autocomplete shouldn't appear");
+  } else {
+    Assert.ok(false, "Autocomplete shouldn't appear");
+  }
+  event.target.hidePopup();
+}
+
+/**
+ * Synthesize mouse clicks to open the context menu popup
+ * for a target login input element.
+ */
+function* openContextMenu(browser, loginInput) {
+  // First synthesize a mousedown. We need this to get the focus event with the "contextmenu" event.
+  let eventDetails1 = {type: "mousedown", button: 2};
+  BrowserTestUtils.synthesizeMouseAtCenter(loginInput, eventDetails1, browser);
+
+  // Then synthesize the contextmenu click over the input element.
+  let contextMenuShownPromise = BrowserTestUtils.waitForEvent(window, "popupshown");
+  let eventDetails = {type: "contextmenu", button: 2};
+  BrowserTestUtils.synthesizeMouseAtCenter(loginInput, eventDetails, browser);
+  yield contextMenuShownPromise;
+
+  // Wait to see which popups are shown.
+  yield new Promise(resolve => setTimeout(resolve, 1000));
+}
+
+function loginList() {
+  return [
+    LoginTestUtils.testData.formLogin({
+      hostname: "https://example.com",
+      formSubmitURL: "https://example.com",
+      username: "username",
+      password: "password",
+    }),
+    LoginTestUtils.testData.formLogin({
+      hostname: "https://example.com",
+      formSubmitURL: "https://example.com",
+      username: "username2",
+      password: "password2",
+    }),
+  ];
+}
--- a/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
+++ b/toolkit/components/passwordmgr/test/mochitest/mochitest.ini
@@ -59,9 +59,11 @@ skip-if = os == "linux" || toolkit == 'a
 skip-if = os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_prompt_noWindow.html]
 skip-if = e10s || toolkit == 'android' # Tests desktop prompts. e10s: bug 1217876
 [test_prompt_promptAuth.html]
 skip-if = os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_prompt_promptAuth_proxy.html]
 skip-if = e10s || os == "linux" || toolkit == 'android' # Tests desktop prompts
 [test_recipe_login_fields.html]
+[test_username_focus.html]
+skip-if = toolkit == 'android' # android:autocomplete.
 [test_xhr_2.html]
--- a/toolkit/components/passwordmgr/test/mochitest/test_autofocus_js.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_autofocus_js.html
@@ -51,38 +51,64 @@ let iframeDoc;
 add_task(function* setup() {
   yield new Promise(resolve => {
     iframe.addEventListener("load", function() {
       resolve();
     }, {once: true});
   });
 
   iframeDoc = iframe.contentDocument;
+
+  SimpleTest.requestFlakyTimeout("Giving a chance for the unexpected popupshown to occur");
 });
 
 add_task(function* test_initial_focus() {
   let results = yield notifyMenuChanged(2, "name");
   checkArrayValues(results, ["name", "name1"], "Two results");
   doKey("down");
   doKey("return");
   yield promiseFormsProcessed();
   is(iframeDoc.getElementById("form-basic-password").value, "pass", "Check first password filled");
   let popupState = yield getPopupState();
   is(popupState.open, false, "Check popup is now closed");
 });
 
+// This depends on the filling from the previous test.
+add_task(function* test_not_reopened_if_filled() {
+  listenForUnexpectedPopupShown();
+  let usernameField = iframeDoc.getElementById("form-basic-username");
+  usernameField.focus();
+  info("Waiting to see if a popupshown occurs");
+  yield new Promise(resolve => setTimeout(resolve, 1000));
+
+  // cleanup
+  gPopupShownExpected = true;
+  iframeDoc.getElementById("form-basic-submit").focus();
+});
+
+add_task(function* test_reopened_after_edit_not_matching_saved() {
+  let usernameField = iframeDoc.getElementById("form-basic-username");
+  usernameField.value = "nam";
+  let shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+  iframeDoc.getElementById("form-basic-submit").focus();
+});
+
 add_task(function* test_not_reopened_after_selecting() {
   let formFillController = SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].
                            getService(SpecialPowers.Ci.nsIFormFillController);
-let usernameField = iframeDoc.getElementById("form-basic-username");
+  let usernameField = iframeDoc.getElementById("form-basic-username");
+  usernameField.value = "";
+  iframeDoc.getElementById("form-basic-password").value = "";
   listenForUnexpectedPopupShown();
   formFillController.markAsLoginManagerField(usernameField);
-  SimpleTest.requestFlakyTimeout("Giving a chance for the unexpected popupshown to occur");
+  info("Waiting to see if a popupshown occurs");
   yield new Promise(resolve => setTimeout(resolve, 1000));
 
-  // cleanup
+  // Cleanup
   gPopupShownExpected = true;
 });
 
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/passwordmgr/test/mochitest/test_basic_form_autocomplete.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_basic_form_autocomplete.html
@@ -828,16 +828,19 @@ add_task(function* test_form12_formless(
 });
 
 add_task(function* test_form12_open_on_trusted_focus() {
   uname = $_(12, "uname");
   pword = $_(12, "pword");
   uname.value = "";
   pword.value = "";
 
+  // Move focus to the password field so we can test the first click on the
+  // username field.
+  pword.focus();
   checkACForm("", "");
   const firePrivEventPromise = new Promise((resolve) => {
     uname.addEventListener("click", (e) => {
       ok(e.isTrusted, "Ensure event is trusted");
       resolve();
     });
   });
   const shownPromise = promiseACShown();
--- a/toolkit/components/passwordmgr/test/mochitest/test_insecure_form_field_autocomplete.html
+++ b/toolkit/components/passwordmgr/test/mochitest/test_insecure_form_field_autocomplete.html
@@ -1,22 +1,21 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
-  <title>Test basic login autocomplete</title>
+  <title>Test insecure form field autocomplete</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
   <script type="text/javascript" src="satchel_common.js"></script>
   <script type="text/javascript" src="pwmgr_common.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
-Login Manager test: multiple login autocomplete
 
 <script>
 var chromeScript = runChecksAfterCommonInit();
 
 var setupScript = runInParent(function setup() {
   const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
   Cu.import("resource://gre/modules/Services.jsm");
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/mochitest/test_username_focus.html
@@ -0,0 +1,263 @@
+
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test interaction between autocomplete and focus on username fields</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="satchel_common.js"></script>
+  <script type="text/javascript" src="pwmgr_common.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script>
+let pwmgrCommonScript = runInParent(SimpleTest.getTestFileURL("pwmgr_common.js"));
+
+let readyPromise = registerRunTests();
+let chromeScript = runInParent(function chromeSetup() {
+  const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
+  let pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
+
+  let login1A  = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                 createInstance(Ci.nsILoginInfo);
+  let login1B  = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                 createInstance(Ci.nsILoginInfo);
+  let login2A  = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                 createInstance(Ci.nsILoginInfo);
+  let login2B  = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                 createInstance(Ci.nsILoginInfo);
+  let login2C  = Cc["@mozilla.org/login-manager/loginInfo;1"].
+                 createInstance(Ci.nsILoginInfo);
+
+  login1A.init("http://mochi.test:8888", "http://username-focus-1", null,
+               "testuser1A", "testpass1A", "", "");
+
+  login2A.init("http://mochi.test:8888", "http://username-focus-2", null,
+               "testuser2A", "testpass2A", "", "");
+  login2B.init("http://mochi.test:8888", "http://username-focus-2", null,
+               "testuser2B", "testpass2B", "", "");
+
+  pwmgr.addLogin(login1A);
+  pwmgr.addLogin(login2A);
+  pwmgr.addLogin(login2B);
+});
+</script>
+
+<p id="display"></p>
+<div id="content">
+  <!-- first 3 forms have a matching user+pass login -->
+
+  <!-- user+pass form. -->
+  <form id="form-autofilled" action="http://username-focus-1">
+    <input  type="text"     name="uname">
+    <input  type="password" name="pword">
+    <button type="submit" name="submit">Submit</button>
+  </form>
+
+  <!-- user+pass form, username prefilled -->
+  <form id="form-autofilled-prefilled-un" action="http://username-focus-1">
+    <input  type="text"     name="uname" value="testuser1A">
+    <input  type="password" name="pword">
+    <button type="submit">Submit</button>
+  </form>
+
+  <!-- user+pass form. -->
+  <form id="form-autofilled-focused-dynamic" action="http://username-focus-1">
+    <input  type="text"             name="uname">
+    <input  type="not-yet-password" name="pword">
+    <button type="submit">Submit</button>
+  </form>
+
+
+  <!-- next 5 forms have matching user+pass (2x) logins -->
+
+  <!-- user+pass form. -->
+  <form id="form-multiple" action="http://username-focus-2">
+    <input  type="text"     name="uname">
+    <input  type="password" name="pword">
+    <button type="submit">Submit</button>
+  </form>
+
+  <!-- user+pass form dynamic with existing focus -->
+  <form id="form-multiple-dynamic" action="http://username-focus-2">
+    <input  type="text"             name="uname">
+    <input  type="not-yet-password" name="pword">
+    <button type="submit">Submit</button>
+  </form>
+
+  <!-- user+pass form, username prefilled -->
+  <form id="form-multiple-prefilled-un1" action="http://username-focus-2">
+    <input  type="text"     name="uname" value="testuser2A">
+    <input  type="password" name="pword">
+    <button type="submit">Submit</button>
+  </form>
+
+  <!-- user+pass form, different username prefilled -->
+  <form id="form-multiple-prefilled-un2" action="http://username-focus-2">
+    <input  type="text"     name="uname" value="testuser2B">
+    <input  type="password" name="pword">
+    <button type="submit">Submit</button>
+  </form>
+
+  <!-- user+pass form, username prefilled with existing focus -->
+  <form id="form-multiple-prefilled-focused-dynamic" action="http://username-focus-2">
+    <input  type="text"             name="uname" value="testuser2B">
+    <input  type="not-yet-password" name="pword">
+    <button type="submit">Submit</button>
+  </form>
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function removeFocus() {
+  $_("-autofilled", "submit").focus();
+}
+
+add_task(function* setup() {
+  yield SpecialPowers.pushPrefEnv({"set": [
+    ["security.insecure_field_warning.contextual.enabled", false],
+  ]});
+
+  ok(readyPromise, "check promise is available");
+  yield readyPromise;
+});
+
+add_task(function* test_autofilled() {
+  let usernameField = $_("-autofilled", "uname");
+  info("Username and password already filled so don't show autocomplete");
+  let noPopupPromise = promiseNoUnexpectedPopupShown();
+  usernameField.focus();
+  yield noPopupPromise;
+
+  removeFocus();
+  usernameField.value = "testuser";
+  info("Focus when we don't have an exact match");
+  shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+});
+
+add_task(function* test_autofilled_prefilled_un() {
+  let usernameField = $_("-autofilled-prefilled-un", "uname");
+  info("Username and password already filled so don't show autocomplete");
+  let noPopupPromise = promiseNoUnexpectedPopupShown();
+  usernameField.focus();
+  yield noPopupPromise;
+
+  removeFocus();
+  usernameField.value = "testuser";
+  info("Focus when we don't have an exact match");
+  shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+});
+
+add_task(function* test_autofilled_focused_dynamic() {
+  let usernameField = $_("-autofilled-focused-dynamic", "uname");
+  let passwordField = $_("-autofilled-focused-dynamic", "pword");
+  info("Username and password will be filled while username focused");
+  let noPopupPromise = promiseNoUnexpectedPopupShown();
+  usernameField.focus();
+  yield noPopupPromise;
+  info("triggering autofill");
+  noPopupPromise = promiseNoUnexpectedPopupShown();
+  passwordField.type = "password";
+  yield noPopupPromise;
+
+  let popupState = yield getPopupState();
+  is(popupState.open, false, "Check popup is closed");
+
+  removeFocus();
+  passwordField.value = "test";
+  info("Focus when we don't have an exact match");
+  shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+});
+
+// Begin testing forms that have multiple saved logins
+
+add_task(function* test_multiple() {
+  let usernameField = $_("-multiple", "uname");
+  info("Fields not filled due to multiple so autocomplete upon focus");
+  shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+});
+
+add_task(function* test_multiple_dynamic() {
+  let usernameField = $_("-multiple-dynamic", "uname");
+  let passwordField = $_("-multiple-dynamic", "pword");
+  info("Fields not filled but username is focused upon marking so open");
+  let noPopupPromise = promiseNoUnexpectedPopupShown();
+  usernameField.focus();
+  yield noPopupPromise;
+
+  info("triggering _fillForm code");
+  let shownPromise = promiseACShown();
+  passwordField.type = "password";
+  yield shownPromise;
+});
+
+add_task(function* test_multiple_prefilled_un1() {
+  let usernameField = $_("-multiple-prefilled-un1", "uname");
+  info("Username and password already filled so don't show autocomplete");
+  let noPopupPromise = promiseNoUnexpectedPopupShown();
+  usernameField.focus();
+  yield noPopupPromise;
+
+  removeFocus();
+  usernameField.value = "testuser";
+  info("Focus when we don't have an exact match");
+  shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+});
+
+add_task(function* test_multiple_prefilled_un2() {
+  let usernameField = $_("-multiple-prefilled-un2", "uname");
+  info("Username and password already filled so don't show autocomplete");
+  let noPopupPromise = promiseNoUnexpectedPopupShown();
+  usernameField.focus();
+  yield noPopupPromise;
+
+  removeFocus();
+  usernameField.value = "testuser";
+  info("Focus when we don't have an exact match");
+  shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+});
+
+add_task(function* test_multiple_prefilled_focused_dynamic() {
+  let usernameField = $_("-multiple-prefilled-focused-dynamic", "uname");
+  let passwordField = $_("-multiple-prefilled-focused-dynamic", "pword");
+  info("Username and password will be filled while username focused");
+  let noPopupPromise = promiseNoUnexpectedPopupShown();
+  usernameField.focus();
+  yield noPopupPromise;
+  info("triggering autofill");
+  noPopupPromise = promiseNoUnexpectedPopupShown();
+  passwordField.type = "password";
+  yield noPopupPromise;
+
+  let popupState = yield getPopupState();
+  is(popupState.open, false, "Check popup is closed");
+
+  removeFocus();
+  passwordField.value = "test";
+  info("Focus when we don't have an exact match");
+  shownPromise = promiseACShown();
+  usernameField.focus();
+  yield shownPromise;
+});
+
+add_task(function* cleanup() {
+  removeFocus();
+});
+</script>
+</pre>
+</body>
+</html>
--- a/toolkit/components/passwordmgr/test/pwmgr_common.js
+++ b/toolkit/components/passwordmgr/test/pwmgr_common.js
@@ -161,45 +161,48 @@ function commonInit(selfFilling) {
   if (this.sendAsyncMessage) {
     sendAsyncMessage("registerRunTests");
   } else {
     registerRunTests();
   }
 }
 
 function registerRunTests() {
-  // We provide a general mechanism for our tests to know when they can
-  // safely run: we add a final form that we know will be filled in, wait
-  // for the login manager to tell us that it's filled in and then continue
-  // with the rest of the tests.
-  window.addEventListener("DOMContentLoaded", (event) => {
-    var form = document.createElement("form");
-    form.id = "observerforcer";
-    var username = document.createElement("input");
-    username.name = "testuser";
-    form.appendChild(username);
-    var password = document.createElement("input");
-    password.name = "testpass";
-    password.type = "password";
-    form.appendChild(password);
+  return new Promise(resolve => {
+    // We provide a general mechanism for our tests to know when they can
+    // safely run: we add a final form that we know will be filled in, wait
+    // for the login manager to tell us that it's filled in and then continue
+    // with the rest of the tests.
+    window.addEventListener("DOMContentLoaded", (event) => {
+      var form = document.createElement("form");
+      form.id = "observerforcer";
+      var username = document.createElement("input");
+      username.name = "testuser";
+      form.appendChild(username);
+      var password = document.createElement("input");
+      password.name = "testpass";
+      password.type = "password";
+      form.appendChild(password);
 
-    var observer = SpecialPowers.wrapCallback(function(subject, topic, data) {
-      var formLikeRoot = subject.QueryInterface(SpecialPowers.Ci.nsIDOMNode);
-      if (formLikeRoot.id !== "observerforcer")
-        return;
-      SpecialPowers.removeObserver(observer, "passwordmgr-processed-form");
-      formLikeRoot.remove();
-      SimpleTest.executeSoon(() => {
-        var runTestEvent = new Event("runTests");
-        window.dispatchEvent(runTestEvent);
+      var observer = SpecialPowers.wrapCallback(function(subject, topic, data) {
+        var formLikeRoot = subject.QueryInterface(SpecialPowers.Ci.nsIDOMNode);
+        if (formLikeRoot.id !== "observerforcer")
+          return;
+        SpecialPowers.removeObserver(observer, "passwordmgr-processed-form");
+        formLikeRoot.remove();
+        SimpleTest.executeSoon(() => {
+          var runTestEvent = new Event("runTests");
+          window.dispatchEvent(runTestEvent);
+          resolve();
+        });
       });
+      SpecialPowers.addObserver(observer, "passwordmgr-processed-form", false);
+
+      document.body.appendChild(form);
     });
-    SpecialPowers.addObserver(observer, "passwordmgr-processed-form", false);
-
-    document.body.appendChild(form);
   });
 }
 
 const masterPassword = "omgsecret!";
 
 function enableMasterPassword() {
   setMasterPassword(true);
 }
--- a/toolkit/components/satchel/nsFormFillController.cpp
+++ b/toolkit/components/satchel/nsFormFillController.cpp
@@ -286,17 +286,16 @@ nsFormFillController::MarkAsLoginManager
   nsFocusManager *fm = nsFocusManager::GetFocusManager();
   if (fm) {
     nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
     if (SameCOMIdentity(focusedContent, node)) {
       nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(node);
       if (!mFocusedInput) {
         MaybeStartControllingInput(input);
       }
-      ShowPopup();
     }
   }
 
   if (!mLoginManager)
     mLoginManager = do_GetService("@mozilla.org/login-manager;1");
 
   return NS_OK;
 }
@@ -312,21 +311,19 @@ nsFormFillController::MarkAsAutofillFiel
   NS_ENSURE_STATE(node);
   mAutofillInputs.Put(node, true);
   node->AddMutationObserverUnlessExists(this);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFormFillController::GetFocusedInput(nsIDOMHTMLInputElement** aRetVal) {
-  if (!aRetVal) {
-    return NS_ERROR_INVALID_POINTER;
-  }
-  *aRetVal = mFocusedInput;
+nsFormFillController::GetFocusedInput(nsIDOMHTMLInputElement **aInput) {
+  *aInput = mFocusedInput;
+  NS_IF_ADDREF(*aInput);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////
 //// nsIAutoCompleteInput
 
 NS_IMETHODIMP
 nsFormFillController::GetPopup(nsIAutoCompletePopup **aPopup)
@@ -701,25 +698,30 @@ NS_IMETHODIMP
 nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAString &aSearchParam,
                                   nsIAutoCompleteResult *aPreviousResult, nsIAutoCompleteObserver *aListener)
 {
   nsresult rv;
   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(mFocusedInputNode);
 
   // If the login manager has indicated it's responsible for this field, let it
   // handle the autocomplete. Otherwise, handle with form history.
+  // This method is sometimes called in unit tests and from XUL without a focused node.
   if (mFocusedInputNode && (mPwmgrInputs.Get(mFocusedInputNode) ||
                             formControl->GetType() == NS_FORM_INPUT_PASSWORD)) {
 
     // Handle the case where a password field is focused but
     // MarkAsLoginManagerField wasn't called because password manager is disabled.
     if (!mLoginManager) {
       mLoginManager = do_GetService("@mozilla.org/login-manager;1");
     }
 
+    if (NS_WARN_IF(!mLoginManager)) {
+      return NS_ERROR_FAILURE;
+    }
+
     // XXX aPreviousResult shouldn't ever be a historyResult type, since we're not letting
     // satchel manage the field?
     mLastListener = aListener;
     rv = mLoginManager->AutoCompleteSearchAsync(aSearchString,
                                                 aPreviousResult,
                                                 mFocusedInput,
                                                 this);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -987,18 +989,20 @@ nsFormFillController::MaybeStartControll
 
   bool autocomplete = nsContentUtils::IsAutocompleteEnabled(aInput);
 
   nsCOMPtr<nsIDOMHTMLElement> datalist;
   aInput->GetList(getter_AddRefs(datalist));
   bool hasList = datalist != nullptr;
 
   bool isPwmgrInput = false;
-  if (mPwmgrInputs.Get(inputNode))
-      isPwmgrInput = true;
+  if (mPwmgrInputs.Get(inputNode) ||
+      formControl->GetType() == NS_FORM_INPUT_PASSWORD) {
+    isPwmgrInput = true;
+  }
 
   if (isPwmgrInput || hasList || autocomplete) {
     StartControllingInput(aInput);
   }
 }
 
 nsresult
 nsFormFillController::Focus(nsIDOMEvent* aEvent)
@@ -1008,29 +1012,27 @@ nsFormFillController::Focus(nsIDOMEvent*
   MaybeStartControllingInput(input);
 
   // Bail if we didn't start controlling the input.
   if (!mFocusedInputNode) {
     mContextMenuFiredBeforeFocus = false;
     return NS_OK;
   }
 
+#ifndef ANDROID
   nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(mFocusedInputNode);
   MOZ_ASSERT(formControl);
 
   // If this focus doesn't immediately follow a contextmenu event then show
-  // the autocomplete popup
-  if (!mContextMenuFiredBeforeFocus &&
-      (mPwmgrInputs.Get(mFocusedInputNode)
-#ifndef ANDROID
-       || formControl->GetType() == NS_FORM_INPUT_PASSWORD
-#endif
-       )) {
+  // the autocomplete popup for all password fields.
+  if (!mContextMenuFiredBeforeFocus
+      && formControl->GetType() == NS_FORM_INPUT_PASSWORD) {
     ShowPopup();
   }
+#endif
 
   mContextMenuFiredBeforeFocus = false;
   return NS_OK;
 }
 
 nsresult
 nsFormFillController::KeyPress(nsIDOMEvent* aEvent)
 {
@@ -1158,17 +1160,17 @@ nsFormFillController::MouseDown(nsIDOMEv
   int16_t button;
   mouseEvent->GetButton(&button);
   if (button != 0)
     return NS_OK;
 
   return ShowPopup();
 }
 
-nsresult
+NS_IMETHODIMP
 nsFormFillController::ShowPopup()
 {
   bool isOpen = false;
   GetPopupOpen(&isOpen);
   if (isOpen) {
     return SetPopupOpen(false);
   }
 
--- a/toolkit/components/satchel/nsFormFillController.h
+++ b/toolkit/components/satchel/nsFormFillController.h
@@ -72,17 +72,16 @@ protected:
    */
   void MaybeStartControllingInput(nsIDOMHTMLInputElement* aElement);
 
   nsresult PerformInputListAutoComplete(const nsAString& aSearch,
                                         nsIAutoCompleteResult** aResult);
 
   void RevalidateDataList();
   bool RowMatch(nsFormHistory *aHistory, uint32_t aIndex, const nsAString &aInputName, const nsAString &aInputValue);
-  nsresult ShowPopup();
 
   inline nsIDocShell *GetDocShellForInput(nsIDOMHTMLInputElement *aInput);
   inline nsPIDOMWindowOuter *GetWindowForDocShell(nsIDocShell *aDocShell);
   inline int32_t GetIndexOfDocShell(nsIDocShell *aDocShell);
 
   void MaybeRemoveMutationObserver(nsINode* aNode);
 
   void RemoveForDocument(nsIDocument* aDoc);
--- a/toolkit/components/satchel/nsIFormFillController.idl
+++ b/toolkit/components/satchel/nsIFormFillController.idl
@@ -16,16 +16,21 @@ interface nsIDOMHTMLInputElement;
  * is focused.  When this happens, the input will be bound to the
  * global nsIAutoCompleteController service.
  */
 
 [scriptable, uuid(07f0a0dc-f6e9-4cdd-a55f-56d770523a4c)]
 interface nsIFormFillController : nsISupports
 {
   /*
+   * The input element the form fill controller is currently bound to.
+   */
+  readonly attribute nsIDOMHTMLInputElement focusedInput;
+
+  /*
    * Start controlling form fill behavior for the given browser
    *
    * @param docShell - The docShell to attach to
    * @param popup - The popup to show when autocomplete results are available
    */
   void attachToBrowser(in nsIDocShell docShell, in nsIAutoCompletePopup popup);
 
   /*
@@ -47,15 +52,13 @@ interface nsIFormFillController : nsISup
   /*
    * Mark the specified <input> element as being managed by a form autofill component.
    * Autocomplete requests will be handed off to the autofill component.
    *
    * @param aInput - The HTML <input> element to mark
    */
   void markAsAutofillField(in nsIDOMHTMLInputElement aInput);
 
-  /**
-   * Return the focused input which is cached in form fill controller.
-   *
-   * @returns The focused input.
+  /*
+   * Open the autocomplete popup, if possible.
    */
-  nsIDOMHTMLInputElement getFocusedInput();
+  void showPopup();
 };
--- a/toolkit/components/satchel/test/satchel_common.js
+++ b/toolkit/components/satchel/test/satchel_common.js
@@ -224,44 +224,51 @@ function getPopupState(then = null) {
         then(state);
       }
       resolve(state);
     });
   });
 }
 
 function listenForUnexpectedPopupShown() {
-  gChromeScript.addMessageListener("onpopupshown", function onPopupShown() {
+  gPopupShownListener = function onPopupShown() {
     if (!gPopupShownExpected) {
       ok(false, "Unexpected autocomplete popupshown event");
     }
-  });
+  };
+}
+
+function* promiseNoUnexpectedPopupShown() {
+  gPopupShownExpected = false;
+  listenForUnexpectedPopupShown();
+  SimpleTest.requestFlakyTimeout("Giving a chance for an unexpected popupshown to occur");
+  yield new Promise(resolve => setTimeout(resolve, 1000));
 }
 
 /**
  * Resolve at the next popupshown event for the autocomplete popup
  * @return {Promise} with the results
  */
 function promiseACShown() {
   gPopupShownExpected = true;
   return new Promise(resolve => {
-    gChromeScript.addMessageListener("onpopupshown", ({ results }) => {
+    gPopupShownListener = ({ results }) => {
       gPopupShownExpected = false;
       resolve(results);
-    });
+    };
   });
 }
 
 function satchelCommonSetup() {
   var chromeURL = SimpleTest.getTestFileURL("parent_utils.js");
   gChromeScript = SpecialPowers.loadChromeScript(chromeURL);
   gChromeScript.addMessageListener("onpopupshown", ({ results }) => {
     gLastAutoCompleteResults = results;
     if (gPopupShownListener)
-      gPopupShownListener();
+      gPopupShownListener({results});
   });
 
   SimpleTest.registerCleanupFunction(() => {
     gChromeScript.sendAsyncMessage("cleanup");
     gChromeScript.destroy();
   });
 }
 
--- a/toolkit/components/telemetry/docs/collection/scalars.rst
+++ b/toolkit/components/telemetry/docs/collection/scalars.rst
@@ -145,14 +145,91 @@ to an array of ``ScalarInfo`` structures
 
 gen-scalar-enum.py
 ------------------
 This script is called by the build system to generate the ``TelemetryScalarEnums.h`` C++ header
 file out of the scalar definitions.
 This header file contains an enum class with all the scalar identifiers used to access them
 from code through the C++ API.
 
+Adding a new probe
+==================
+Making a scalar measurement is a two step process:
+
+1. add the probe definition to the scalar registry;
+2. record into the scalar using the API.
+
+Registering the scalar
+----------------------
+Let's start by registering two probes in the `Scalars.yaml <https://dxr.mozilla.org/mozilla-central/source/toolkit/components/telemetry/Scalars.yaml>`_ definition file: a simple boolean scalar and a keyed unsigned scalar.
+
+.. code-block:: yaml
+
+    # The following section contains the demo scalars.
+    profile:
+      was_reset:
+        bug_numbers:
+          - 1301364
+        description: True if the profile was reset.
+        expires: "60"
+        kind: boolean
+        notification_emails:
+          - change-me@allizom.com
+        release_channel_collection: opt-out
+        record_in_processes:
+          - 'main'
+
+    ui:
+      download_button_activated:
+        bug_numbers:
+          - 1301364
+        description: >
+          The number of times the download button was activated, per
+          input type (e.g. 'mouse_click', 'touchscreen', ...).
+        expires: "60"
+        kind: uint
+        keyed: true
+        notification_emails:
+          - change-me@allizom.com
+        release_channel_collection: opt-in
+        record_in_processes:
+          - 'main'
+
+These two scalars have different collection policies and are both constrained to recording only in the main process.
+For example, the ``ui.download_button_activated`` can be recorded only by users who opted into the extended Telemetry collection.
+
+Using the JS API
+----------------
+Changing the demo scalars from privileged JavaScript code is straightforward:
+
+.. code-block:: js
+
+  // Set the scalar value: trying to use a non-boolean value doesn't throw
+  // but rather prints a warning to the browser console
+  Services.telemetry.scalarSet("profile.was_reset", true);
+
+  // This call increments the value stored in "mouse_click" within the
+  // "ui.download_button_activated" scalar, by 1.
+  Services.telemetry.keyedScalarAdd("ui.download_button_activated", "mouse_click", 1);
+
+More usage examples can be found in the tests covering the `JS Scalars API <https://dxr.mozilla.org/mozilla-central/source/toolkit/components/telemetry/tests/unit/test_TelemetryScalars.js>`_ and `child processes scalars <https://dxr.mozilla.org/mozilla-central/source/toolkit/components/telemetry/tests/unit/test_ChildScalars.js>`_.
+
+Using the C++ API
+-----------------
+Native code can take advantage of Scalars as well, by including the ``Telemetry.h`` header file.
+
+.. code-block:: cpp
+
+    Telemetry::ScalarSet(Telemetry::ScalarID::PROFILE_WAS_RESET, false);
+
+    Telemetry::ScalarAdd(Telemetry::ScalarID::UI_DOWNLOAD_BUTTON_ACTIVATED,
+                         NS_LITERAL_STRING("touchscreen"), 1);
+
+The ``ScalarID`` enum is automatically generated by the build process, with an example being available `here <https://dxr.mozilla.org/mozilla-central/search?q=path%3ATelemetryScalarEnums.h&redirect=false>`_ .
+
+Other examples can be found in the `test coverage <https://dxr.mozilla.org/mozilla-central/source/toolkit/components/telemetry/tests/gtest/TestScalars.cpp>`_ for the scalars C++ API.
+
 Version History
 ===============
 
 - Firefox 50: Initial scalar support (`bug 1276195 <https://bugzilla.mozilla.org/show_bug.cgi?id=1276195>`_).
 - Firefox 51: Added keyed scalars (`bug 1277806 <https://bugzilla.mozilla.org/show_bug.cgi?id=1277806>`_).
 - Firefox 53: Added child process scalars (`bug 1278556 <https://bugzilla.mozilla.org/show_bug.cgi?id=1278556>`_).
--- a/toolkit/content/license.html
+++ b/toolkit/content/license.html
@@ -126,16 +126,19 @@
       <li><a href="about:license#microformatsshiv">MIT license — microformat-shiv</a></li>
       <li><a href="about:license#myspell">MySpell License</a></li>
       <li><a href="about:license#nicer">nICEr License</a></li>
       <li><a href="about:license#node-md5">node-md5 License</a></li>
       <li><a href="about:license#node-properties">node-properties License</a></li>
       <li><a href="about:license#nrappkit">nrappkit License</a></li>
       <li><a href="about:license#openaes">OpenAES License</a></li>
       <li><a href="about:license#openvision">OpenVision License</a></li>
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
+      <li><a href="about:license#openvr">OpenVR License</a></li>
+#endif
       <li><a href="about:license#pbkdf2-sha256">pbkdf2_sha256 License</a></li>
 #ifdef MOZ_WEBSPEECH_POCKETSPHINX
       <li><a href="about:license#pocketsphinx">Pocketsphinx License</a></li>
 #endif
       <li><a href="about:license#praton">praton License</a></li>
       <li><a href="about:license#qcms">qcms License</a></li>
       <li><a href="about:license#qrcode-generator">QR Code Generator License</a></li>
       <li><a href="about:license#react">React License</a></li>
@@ -150,19 +153,16 @@
       <li><a href="about:license#snappy">Snappy License</a></li>
       <li><a href="about:license#sprintf.js">sprintf.js License</a></li>
       <li><a href="about:license#sunsoft">SunSoft License</a></li>
       <li><a href="about:license#superfasthash">SuperFastHash License</a></li>
       <li><a href="about:license#unicode">Unicode License</a></li>
       <li><a href="about:license#ucal">University of California License</a></li>
       <li><a href="about:license#hunspell-en-US">US English Spellchecking Dictionary Licenses</a></li>
       <li><a href="about:license#v8">V8 License</a></li>
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
-      <li><a href="about:license#valve">Valve BSD License</a></li>
-#endif
       <li><a href="about:license#vtune">VTune License</a></li>
       <li><a href="about:license#webrtc">WebRTC License</a></li>
       <li><a href="about:license#x264">x264 License</a></li>
       <li><a href="about:license#xiph">Xiph.org Foundation License</a></li>
     </ul>
 
 <br>
 
@@ -4332,16 +4332,56 @@ OPENVISION DISCLAIMS ALL WARRANTIES WITH
 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 PERFORMANCE OF THIS SOFTWARE.
 </pre>
 
+#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
+
+    <hr>
+
+    <h1><a id="openvr"></a>OpenVR License</h1>
+
+    <p>This license applies to certain files in the directory
+    <span class="path">gfx/vr/openvr</span>.</p>
+<pre>
+Copyright (c) 2015, Valve Corporation
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation and/or
+other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 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.
+</pre>
+
+#endif
+
 <hr>
 
     <h1><a id="node-md5"></a>node-md5 License</h1>
 
     <p>This license applies to some of the code in
     <span class="path">devtools/client/debugger/new/debugger.js</span>.</p>
 
 <pre>
@@ -5814,58 +5854,18 @@ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 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.
 </pre>
 
-
-#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX)
-
     <hr>
 
-    <h1><a id="valve"></a>Valve BSD License</h1>
-
-    <p>This license applies to certain files in the directory
-    <span class="path">gfx/vr/openvr</span>.</p>
-<pre>
-Copyright (c) 2015, Valve Corporation
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its contributors
-may be used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 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.
-</pre>
-
-#endif
-
-    <hr>
 
     <h1><a id="vtune"></a>VTune License</h1>
 
     <p>This license applies to certain files in the directory
     <span class="path">js/src/vtune</span>.</p>
 <pre>
 Copyright (c) 2005-2012 Intel Corporation. All rights reserved.
 All rights reserved.
--- a/toolkit/modules/FormLikeFactory.jsm
+++ b/toolkit/modules/FormLikeFactory.jsm
@@ -63,42 +63,61 @@ let FormLikeFactory = {
    * @throws Error if aField isn't a password or username field in a document
    */
   createFromField(aField) {
     if (!(aField instanceof Ci.nsIDOMHTMLInputElement) ||
         !aField.ownerDocument) {
       throw new Error("createFromField requires a field in a document");
     }
 
-    if (aField.form) {
-      return this.createFromForm(aField.form);
+    let rootElement = this.findRootForField(aField);
+    if (rootElement instanceof Ci.nsIDOMHTMLFormElement) {
+      return this.createFromForm(rootElement);
     }
 
     let doc = aField.ownerDocument;
     let elements = [];
-    for (let el of doc.documentElement.querySelectorAll("input")) {
+    for (let el of rootElement.querySelectorAll("input")) {
+      // Exclude elements inside the rootElement that are already in a <form> as
+      // they will be handled by their own FormLike.
       if (!el.form) {
         elements.push(el);
       }
     }
     let formLike = {
       action: doc.baseURI,
       autocomplete: "on",
-      // Exclude elements inside the rootElement that are already in a <form> as
-      // they will be handled by their own FormLike.
       elements,
       ownerDocument: doc,
-      rootElement: doc.documentElement,
+      rootElement,
     };
 
     this._addToJSONProperty(formLike);
     return formLike;
   },
 
   /**
+   * Determine the Element that encapsulates the related fields. For example, if
+   * a page contains a login form and a checkout form which are "submitted"
+   * separately, and the username field is passed in, ideally this would return
+   * an ancestor Element of the username and password fields which doesn't
+   * include any of the checkout fields.
+   *
+   * @param {HTMLInputElement} aField - a field in a document
+   * @return {HTMLElement} - the root element surrounding related fields
+   */
+  findRootForField(aField) {
+    if (aField.form) {
+      return aField.form;
+    }
+
+    return aField.ownerDocument.documentElement;
+  },
+
+  /**
    * Add a `toJSON` property to a FormLike so logging which ends up going
    * through dump doesn't include usless garbage from DOM objects.
    */
   _addToJSONProperty(aFormLike) {
     function prettyElementOutput(aElement) {
       let idText = aElement.id ? "#" + aElement.id : "";
       let classText = "";
       for (let className of aElement.classList) {
--- a/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in
+++ b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in
@@ -13,29 +13,27 @@ include $(topsrcdir)/config/rules.mk
 ifndef MOZ_WINCONSOLE
 ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
 
-ifdef COMPILE_ENVIRONMENT
 tools::
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 	# Copy for xpcshell tests
 	$(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app
 	rsync -a -C --exclude '*.in' $(srcdir)/../macbuild/Contents $(XPCSHELLTESTROOT)/data/updater-xpcshell.app
 	sed -e 's/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/' $(srcdir)/../macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
 	  iconv -f UTF-8 -t UTF-16 > $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings
-	$(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS/updater-xpcshell
+	$(NSINSTALL) -D $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS
 	$(NSINSTALL) $(FINAL_TARGET)/updater-xpcshell $(XPCSHELLTESTROOT)/data/updater-xpcshell.app/Contents/MacOS
 	rm -Rf $(XPCSHELLTESTROOT)/data/updater.app
 	mv $(XPCSHELLTESTROOT)/data/updater-xpcshell.app $(XPCSHELLTESTROOT)/data/updater.app
 	mv $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/updater-xpcshell $(XPCSHELLTESTROOT)/data/updater.app/Contents/MacOS/org.mozilla.updater
 
 	# Copy for mochitest chrome tests
 	rsync -a -C $(XPCSHELLTESTROOT)/data/updater.app $(MOCHITESTROOT)/data/
 else
 	cp $(FINAL_TARGET)/updater-xpcshell$(BIN_SUFFIX) $(XPCSHELLTESTROOT)/data/updater$(BIN_SUFFIX)
 	cp $(FINAL_TARGET)/updater-xpcshell$(BIN_SUFFIX) $(MOCHITESTROOT)/data/updater$(BIN_SUFFIX)
 endif
-endif # COMPILE_ENVIRONMENT
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/index.js
@@ -10,16 +10,17 @@
 
 //------------------------------------------------------------------------------
 // Plugin Definition
 //------------------------------------------------------------------------------
 
 module.exports = {
   processors: {
     ".xml": require("../lib/processors/xbl-bindings"),
+    ".js": require("../lib/processors/self-hosted"),
   },
   rules: {
     "avoid-removeChild": require("../lib/rules/avoid-removeChild"),
     "balanced-listeners": require("../lib/rules/balanced-listeners"),
     "import-browserjs-globals": require("../lib/rules/import-browserjs-globals"),
     "import-globals": require("../lib/rules/import-globals"),
     "import-headjs-globals": require("../lib/rules/import-headjs-globals"),
     "import-test-globals": require("../lib/rules/import-test-globals"),
new file mode 100644
--- /dev/null
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/processors/self-hosted.js
@@ -0,0 +1,44 @@
+/**
+ * @fileoverview Remove macros from SpiderMonkey's self-hosted JS.
+ *
+ * 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/.
+ */
+
+"use strict";
+
+const selfHostedRegex = /js\/src\/builtin\/.*?\.js$/;
+const macroRegex = /\s*\#(if|ifdef|else|elif|endif|include|define|undef).*/;
+
+module.exports = {
+  preprocess: function(text, filename) {
+    if (!selfHostedRegex.test(filename)) {
+      return [text];
+    }
+
+    let lines = text.split(/\n/);
+    for (let i = 0; i < lines.length; i++) {
+      if (!macroRegex.test(lines[i])) {
+        // No macro here, nothing to do.
+        continue;
+      }
+
+      for (; i < lines.length; i++) {
+        lines[i] = "// " + lines[i];
+
+        // If the line ends with a backslash (\), the next line
+        // is also part of part of the macro.
+        if (!lines[i].endsWith("\\")) {
+          break;
+        }
+      }
+    }
+
+    return [lines.join("\n")];
+  },
+
+  postprocess: function(messages, filename) {
+    return Array.prototype.concat.apply([], messages);
+  }
+}
--- a/tools/lint/eslint/eslint-plugin-mozilla/package.json
+++ b/tools/lint/eslint/eslint-plugin-mozilla/package.json
@@ -1,11 +1,11 @@
 {
   "name": "eslint-plugin-mozilla",
-  "version": "0.2.18",
+  "version": "0.2.19",
   "description": "A collection of rules that help enforce JavaScript coding standard in the Mozilla project.",
   "keywords": [
     "eslint",
     "eslintplugin",
     "eslint-plugin",
     "mozilla",
     "firefox"
   ],
--- a/tools/profiler/core/ProfileBuffer.cpp
+++ b/tools/profiler/core/ProfileBuffer.cpp
@@ -54,16 +54,29 @@ void ProfileBuffer::deleteExpiredStoredM
   }
 }
 
 void ProfileBuffer::reset() {
   mGeneration += 2;
   mReadPos = mWritePos = 0;
 }
 
+size_t
+ProfileBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += aMallocSizeOf(mEntries.get());
+
+  // Measurement of the following members may be added later if DMD finds it
+  // is worthwhile:
+  // - mStoredMarkers
+
+  return n;
+}
+
 #define DYNAMIC_MAX_STRING 8192
 
 char* ProfileBuffer::processDynamicTag(int readPos,
                                        int* tagsConsumed, char* tagBuff)
 {
   int readAheadPos = (readPos + 1) % mEntrySize;
   int tagBuffPos = 0;
 
--- a/tools/profiler/core/ProfileBuffer.h
+++ b/tools/profiler/core/ProfileBuffer.h
@@ -28,16 +28,18 @@ public:
   void DuplicateLastSample(int aThreadId);
 
   void addStoredMarker(ProfilerMarker* aStoredMarker);
 
   // The following two methods are not signal safe! They delete markers.
   void deleteExpiredStoredMarkers();
   void reset();
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
 protected:
   char* processDynamicTag(int readPos, int* tagsConsumed, char* tagBuff);
   int FindLastSampleOfThread(int aThreadId);
 
 public:
   // Circular buffer 'Keep One Slot Open' implementation for simplicity
   mozilla::UniquePtr<ProfileEntry[]> mEntries;
 
--- a/tools/profiler/core/Sampler.cpp
+++ b/tools/profiler/core/Sampler.cpp
@@ -1451,8 +1451,33 @@ Sampler::RegisterThread(ThreadInfo* aInf
 
   if (!ThreadSelected(aInfo->Name(), mThreadNameFilters)) {
     return;
   }
 
   aInfo->SetProfile(mBuffer);
 }
 
+size_t
+Sampler::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mBuffer->SizeOfIncludingThis(aMallocSizeOf);
+
+  {
+    StaticMutexAutoLock lock(sRegisteredThreadsMutex);
+
+    for (uint32_t i = 0; i < sRegisteredThreads->size(); i++) {
+      ThreadInfo* info = sRegisteredThreads->at(i);
+
+      n += info->SizeOfIncludingThis(aMallocSizeOf);
+    }
+  }
+
+  // Measurement of the following members may be added later if DMD finds it
+  // is worthwhile:
+  // - memory pointed to by the elements within mBuffer
+  // - sRegisteredThreads
+  // - mThreadNameFilters
+  // - mFeatures
+
+  return n;
+}
--- a/tools/profiler/core/ThreadInfo.cpp
+++ b/tools/profiler/core/ThreadInfo.cpp
@@ -256,8 +256,30 @@ ThreadInfo::GetMutex()
 }
 
 void
 ThreadInfo::DuplicateLastSample()
 {
   mBuffer->DuplicateLastSample(mThreadId);
 }
 
+size_t
+ThreadInfo::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  n += aMallocSizeOf(mName.get());
+  n += mPseudoStack->SizeOfIncludingThis(aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it
+  // is worthwhile:
+  // - mPlatformData
+  // - mSavedStreamedSamples
+  // - mSavedStreamedMarkers
+  // - mUniqueStacks
+  // - mMutex
+  //
+  // The following members are not measured:
+  // - mThread: because it is non-owning
+
+  return n;
+}
+
--- a/tools/profiler/core/ThreadInfo.h
+++ b/tools/profiler/core/ThreadInfo.h
@@ -29,16 +29,18 @@ class ThreadInfo {
   PlatformData* GetPlatformData() const { return mPlatformData.get(); }
   void* StackTop() const { return mStackTop; }
 
   virtual void SetPendingDelete();
   bool IsPendingDelete() const { return mPendingDelete; }
 
   bool CanInvokeJS() const;
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
  private:
   mozilla::UniqueFreePtr<char> mName;
   int mThreadId;
   const bool mIsMainThread;
   PseudoStack* mPseudoStack;
   Sampler::UniquePlatformData mPlatformData;
   void* mStackTop;
 
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -395,16 +395,45 @@ profiler_log(const char* fmt, va_list ar
       delete[] heapBuf;
     }
   }
 }
 
 ////////////////////////////////////////////////////////////////////////
 // BEGIN externally visible functions
 
+MOZ_DEFINE_MALLOC_SIZE_OF(GeckoProfilerMallocSizeOf);
+
+NS_IMETHODIMP
+GeckoProfilerReporter::CollectReports(nsIHandleReportCallback* aHandleReport,
+                                      nsISupports* aData, bool aAnonymize)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  if (gSampler) {
+    size_t n = gSampler->SizeOfIncludingThis(GeckoProfilerMallocSizeOf);
+    MOZ_COLLECT_REPORT(
+      "explicit/profiler/sampler", KIND_HEAP, UNITS_BYTES, n,
+      "Memory used by the Gecko Profiler's Sampler object.");
+  }
+
+#if defined(USE_LUL_STACKWALK)
+  {
+    size_t n = sLUL ? sLUL->SizeOfIncludingThis(GeckoProfilerMallocSizeOf) : 0;
+    MOZ_COLLECT_REPORT(
+      "explicit/profiler/lul", KIND_HEAP, UNITS_BYTES, n,
+      "Memory used by LUL, a stack unwinder used by the Gecko Profiler.");
+  }
+#endif
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(GeckoProfilerReporter, nsIMemoryReporter)
+
 void
 profiler_init(void* stackTop)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
   sInitCount++;
 
   if (stack_key_initialized)
--- a/tools/profiler/core/platform.h
+++ b/tools/profiler/core/platform.h
@@ -346,16 +346,18 @@ public:
                        mozilla::dom::Promise* aPromise = 0);
   void ToFileAsync(const nsACString& aFileName, double aSinceTime = 0);
   void StreamMetaJSCustomObject(SpliceableJSONWriter& aWriter);
   void StreamTaskTracer(SpliceableJSONWriter& aWriter);
   void FlushOnJSShutdown(JSContext* aContext);
 
   void GetBufferInfo(uint32_t *aCurrentPosition, uint32_t *aTotalSize, uint32_t *aGeneration);
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
 private:
   // Not implemented on platforms which do not support backtracing
   void doNativeBacktrace(ThreadInfo& aInfo, TickSample* aSample);
 
   void StreamJSON(SpliceableJSONWriter& aWriter, double aSinceTime);
 
   // Called within a signal. This function must be reentrant
   void InplaceTick(TickSample* sample);
--- a/tools/profiler/lul/LulMain.cpp
+++ b/tools/profiler/lul/LulMain.cpp
@@ -32,16 +32,17 @@
 
 namespace lul {
 
 using std::string;
 using std::vector;
 using std::pair;
 using mozilla::CheckedInt;
 using mozilla::DebugOnly;
+using mozilla::MallocSizeOf;
 
 
 // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
 //
 // Some functions in this file are marked RUNS IN NO-MALLOC CONTEXT.
 // Any such function -- and, hence, the transitive closure of those
 // reachable from it -- must not do any dynamic memory allocation.
 // Doing so risks deadlock.  There is exactly one root function for
@@ -366,16 +367,28 @@ SecMap::PrepareRuleSets(uintptr_t aStart
     mLog("\n");
   }
 }
 
 bool SecMap::IsEmpty() {
   return mRuleSets.empty();
 }
 
+size_t
+SecMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+
+  // It's conceivable that these calls would be unsafe with some
+  // implementations of std::vector, but it seems to be working for now...
+  n += aMallocSizeOf(mRuleSets.data());
+  n += aMallocSizeOf(mPfxInstrs.data());
+
+  return n;
+}
 
 ////////////////////////////////////////////////////////////////
 // SegArray                                                   //
 ////////////////////////////////////////////////////////////////
 
 // A SegArray holds a set of address ranges that together exactly
 // cover an address range, with no overlaps or holes.  Each range has
 // an associated value, which in this case has been specialised to be
@@ -781,16 +794,30 @@ class PriMap {
 #else
 # error "Unsupported arch"
 #endif
 
     // Not an insn we recognise.
     return false;
   }
 
+  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
+    size_t n = aMallocSizeOf(this);
+
+    // It's conceivable that this call would be unsafe with some
+    // implementations of std::vector, but it seems to be working for now...
+    n += aMallocSizeOf(mSecMaps.data());
+
+    for (size_t i = 0; i < mSecMaps.size(); i++) {
+      n += mSecMaps[i]->SizeOfIncludingThis(aMallocSizeOf);
+    }
+
+    return n;
+  }
+
  private:
   // RUNS IN NO-MALLOC CONTEXT
   SecMap* FindSecMap(uintptr_t ia) {
     // Binary search mSecMaps to find one that brackets |ia|.
     // lo and hi need to be signed, else the loop termination tests
     // don't work properly.
     long int lo = 0;
     long int hi = (long int)mSecMaps.size() - 1;
@@ -877,16 +904,31 @@ LUL::MaybeShowStats()
                    "    CTX %4u    CFI %4u    SCAN %4u",
                    n_new, n_new_Context, n_new_CFI, n_new_Scanned);
     buf[sizeof(buf)-1] = 0;
     mLog(buf);
   }
 }
 
 
+size_t
+LUL::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+  size_t n = aMallocSizeOf(this);
+  n += mPriMap->SizeOfIncludingThis(aMallocSizeOf);
+
+  // Measurement of the following members may be added later if DMD finds it
+  // is worthwhile:
+  // - mSegArray
+  // - mUSU
+
+  return n;
+}
+
+
 void
 LUL::EnableUnwinding()
 {
   LUL_LOG("LUL::EnableUnwinding");
   // Don't assert for Admin mode here.  That is, tolerate a call here
   // if we are already in Unwinding mode.
   MOZ_ASSERT(gettid() == mAdminThreadId);
 
--- a/tools/profiler/lul/LulMain.h
+++ b/tools/profiler/lul/LulMain.h
@@ -4,16 +4,17 @@
  * 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 LulMain_h
 #define LulMain_h
 
 #include "LulPlatformMacros.h"
 #include "mozilla/Atomics.h"
+#include "mozilla/MemoryReporting.h"
 
 // LUL: A Lightweight Unwind Library.
 // This file provides the end-user (external) interface for LUL.
 
 // Some comments about naming in the implementation.  These are safe
 // to ignore if you are merely using LUL, but are important if you
 // hack on its internals.
 //
@@ -348,16 +349,18 @@ public:
   // Statistics relating to unwinding.  These have to be atomic since
   // unwinding can occur on different threads simultaneously.
   LULStats<mozilla::Atomic<uint32_t>> mStats;
 
   // Possibly show the statistics.  This may not be called from any
   // registered sampling thread, since it involves I/O.
   void MaybeShowStats();
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const;
+
 private:
   // The statistics counters at the point where they were last printed.
   LULStats<uint32_t> mStatsPrevious;
 
   // Are we in admin mode?  Initially |true| but changes to |false|
   // once unwinding begins.
   bool mAdminMode;
 
--- a/tools/profiler/lul/LulMainInt.h
+++ b/tools/profiler/lul/LulMainInt.h
@@ -353,16 +353,18 @@ public:
   // address ranges which don't fall inside [start, +len).  |len| may
   // not be zero.
   void PrepareRuleSets(uintptr_t start, size_t len);
 
   bool IsEmpty();
 
   size_t Size() { return mRuleSets.size(); }
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
+
   // The min and max addresses of the addresses in the contained
   // RuleSets.  See comment above for invariants.
   uintptr_t mSummaryMinAddr;
   uintptr_t mSummaryMaxAddr;
 
 private:
   // False whilst adding entries; true once it is safe to call FindRuleSet.
   // Transition (false->true) is caused by calling PrepareRuleSets().
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -296,16 +296,17 @@ PROFILER_FUNC_VOID(profiler_log(const ch
 #include <stdlib.h>
 #include <signal.h>
 #include "js/ProfilingStack.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/ThreadLocal.h"
 #include "nscore.h"
 #include "PseudoStack.h"
 #include "ProfilerBacktrace.h"
+#include "nsIMemoryReporter.h"
 
 // Make sure that we can use std::min here without the Windows headers messing with us.
 #ifdef min
 #undef min
 #endif
 
 class Sampler;
 class nsISupports;
@@ -505,16 +506,31 @@ private:
 inline PseudoStack*
 profiler_get_pseudo_stack(void)
 {
   if (!stack_key_initialized)
     return nullptr;
   return tlsPseudoStack.get();
 }
 
+class GeckoProfilerReporter final : public nsIMemoryReporter
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  GeckoProfilerReporter() {}
+
+  NS_IMETHOD
+  CollectReports(nsIHandleReportCallback* aHandleReport,
+                 nsISupports* aData, bool aAnonymize) override;
+
+private:
+  ~GeckoProfilerReporter() {}
+};
+
 #endif  // defined(MOZ_GECKO_PROFILER)
 
 namespace mozilla {
 
 class MOZ_RAII GeckoProfilerInitRAII {
 public:
   explicit GeckoProfilerInitRAII(void* stackTop) {
     profiler_init(stackTop);
--- a/tools/profiler/public/PseudoStack.h
+++ b/tools/profiler/public/PseudoStack.h
@@ -349,16 +349,32 @@ public:
       enableJSSampling();
   }
   void disableJSSampling() {
     mStartJSSampling = false;
     if (mContext)
       js::EnableContextProfilingStack(mContext, false);
   }
 
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
+    size_t n = aMallocSizeOf(this);
+
+    // Measurement of the following members may be added later if DMD finds it
+    // is worthwhile:
+    // - things pointed to by mStack elements
+    // - mPendingMarkers
+    //
+    // If these measurements are added, the code must be careful to avoid data
+    // races. (The current code doesn't have any race issues because the
+    // contents of the PseudoStack object aren't accessed; |this| is used only
+    // as an address for lookup by aMallocSizeof).
+
+    return n;
+  }
+
   // Keep a list of active checkpoints
   StackEntry volatile mStack[1024];
  private:
 
   // A PseudoStack can only be created via the "create" method.
   PseudoStack()
     : mStackPointer(0)
     , mSleepId(0)
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -1559,16 +1559,22 @@ nsMemoryReporterManager::Init()
 #endif
 
   RegisterStrongReporter(new AtomTablesReporter());
 
 #ifdef DEBUG
   RegisterStrongReporter(new DeadlockDetectorReporter());
 #endif
 
+#ifdef MOZ_GECKO_PROFILER
+  // We have to register this here rather than in profiler_init() because
+  // profiler_init() runs prior to nsMemoryReporterManager's creation.
+  RegisterStrongReporter(new GeckoProfilerReporter());
+#endif
+
 #ifdef MOZ_DMD
   RegisterStrongReporter(new mozilla::dmd::DMDReporter());
 #endif
 
 #ifdef XP_WIN
   RegisterStrongReporter(new WindowsAddressSpaceReporter());
 #endif