Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
authorBogdan Tara <btara@mozilla.com>
Wed, 21 Nov 2018 11:50:34 +0200
changeset 503951 ab0dfc5b827dcc0a2eef87d8e9ccbf383a397f72
parent 503950 86d8ead0b9a51d9cd0f780e0c279f8a86d2b187e (current diff)
parent 503876 7488645b27ac9b273d6785db04204684673b3657 (diff)
child 503952 cbe820dfb9adb4d4cc693bc15201ff40fc8ca995
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to mozilla-inbound. a=merge CLOSED TREE
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -859,17 +859,17 @@ Accessible::XULElmName(DocAccessible* aD
 }
 
 nsresult
 Accessible::HandleAccEvent(AccEvent* aEvent)
 {
   NS_ENSURE_ARG_POINTER(aEvent);
 
 #ifdef MOZ_GECKO_PROFILER
-  if (profiler_is_active()) {
+  if (profiler_thread_is_being_profiled()) {
     nsAutoCString strEventType;
     GetAccService()->GetStringEventType(aEvent->GetEventType(), strEventType);
     nsAutoCString strMarker;
     strMarker.AppendLiteral("A11y Event - ");
     strMarker.Append(strEventType);
     profiler_add_marker(strMarker.get());
   }
 #endif
--- a/browser/app/winlauncher/DllBlocklistWin.cpp
+++ b/browser/app/winlauncher/DllBlocklistWin.cpp
@@ -336,27 +336,27 @@ public:
     if (!::VirtualProtectEx(aTargetProcess, aAddress, aLength, aProtFlags,
                             &mPrevProt)) {
       mError = WindowsError::FromLastError();
     }
   }
 
   ~AutoVirtualProtect()
   {
-    if (!mError) {
+    if (mError.IsFailure()) {
       return;
     }
 
     ::VirtualProtectEx(mTargetProcess, mAddress, mLength, mPrevProt,
                        &mPrevProt);
   }
 
   explicit operator bool() const
   {
-    return !!mError;
+    return mError.IsSuccess();
   }
 
   WindowsError GetError() const
   {
     return mError;
   }
 
   AutoVirtualProtect(const AutoVirtualProtect&) = delete;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -84,16 +84,17 @@
 
 <script type="application/javascript"
 #ifdef BROWSER_XHTML
 xmlns="http://www.w3.org/1999/xhtml"
 #endif
 >
   Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", this);
   Services.scriptloader.loadSubScript("chrome://browser/content/tabbrowser.js", this);
+  Services.scriptloader.loadSubScript("chrome://browser/content/search/searchbar.js", this);
 
   window.onload = gBrowserInit.onLoad.bind(gBrowserInit);
   window.onunload = gBrowserInit.onUnload.bind(gBrowserInit);
   window.onclose = WindowIsClosing;
 
 #ifdef BROWSER_XHTML
   window.addEventListener("readystatechange", () => {
     // We initially hide the window to prevent layouts during parse. This lets us
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -11,17 +11,16 @@
 #ifdef BROWSER_XHTML
 xmlns="http://www.w3.org/1999/xhtml"
 #endif
 >
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 for (let script of [
   "chrome://browser/content/browser.js",
-  "chrome://browser/content/search/searchbar.js",
 
   "chrome://browser/content/browser-captivePortal.js",
   "chrome://browser/content/browser-compacttheme.js",
   "chrome://browser/content/browser-contentblocking.js",
   "chrome://browser/content/browser-media.js",
   "chrome://browser/content/browser-pageActions.js",
   "chrome://browser/content/browser-places.js",
   "chrome://browser/content/browser-plugins.js",
--- a/browser/components/search/content/search-one-offs.js
+++ b/browser/components/search/content/search-one-offs.js
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 /* eslint-env mozilla/browser-window */
+/* globals XULCommandEvent */
 
 {
 
 class SearchOneOffs {
   constructor(container) {
     this.container = container;
 
     this.container.appendChild(MozXULElement.parseXULToFragment(`
--- a/devtools/client/performance-new/components/Settings.js
+++ b/devtools/client/performance-new/components/Settings.js
@@ -138,16 +138,21 @@ const featureCheckboxes = [
     value: "trackopts",
     title: "Track JIT optimizations in the JS engine.",
   },
   {
     name: "TaskTracer",
     value: "tasktracer",
     title: "Enable TaskTracer (Experimental, requires custom build.)",
   },
+  {
+    name: "Screenshots",
+    value: "screenshots",
+    title: "Record screenshots of all browser windows.",
+  },
 ];
 
 /**
  * This component manages the settings for recording a performance profile.
  */
 class Settings extends PureComponent {
   static get propTypes() {
     return {
--- a/dom/base/nsDOMNavigationTiming.cpp
+++ b/dom/base/nsDOMNavigationTiming.cpp
@@ -382,17 +382,17 @@ nsDOMNavigationTiming::NotifyNonBlankPai
 
   if (!mNonBlankPaint.IsNull()) {
     return;
   }
 
   mNonBlankPaint = TimeStamp::Now();
 
 #ifdef MOZ_GECKO_PROFILER
-  if (profiler_is_active()) {
+  if (profiler_thread_is_being_profiled()) {
     TimeDuration elapsed = mNonBlankPaint - mNavigationStart;
     nsAutoCString spec;
     if (mLoadedURI) {
       mLoadedURI->GetSpec(spec);
     }
     nsPrintfCString marker("Non-blank paint after %dms for URL %s, %s",
                            int(elapsed.ToMilliseconds()), spec.get(),
                            mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and first non-blank paint");
@@ -461,17 +461,17 @@ nsDOMNavigationTiming::NotifyDOMContentF
 
   if (!mDOMContentFlushed.IsNull()) {
     return;
   }
 
   mDOMContentFlushed = TimeStamp::Now();
 
 #ifdef MOZ_GECKO_PROFILER
-  if (profiler_is_active()) {
+  if (profiler_thread_is_being_profiled()) {
     TimeDuration elapsed = mDOMContentFlushed - mNavigationStart;
     nsAutoCString spec;
     if (mLoadedURI) {
       mLoadedURI->GetSpec(spec);
     }
     nsPrintfCString marker("DOMContentFlushed after %dms for URL %s, %s",
                            int(elapsed.ToMilliseconds()), spec.get(),
                            mDocShellHasBeenActiveSinceNavigationStart ? "foreground tab" : "this tab was inactive some of the time between navigation start and DOMContentFlushed");
--- a/dom/indexedDB/ProfilerHelpers.h
+++ b/dom/indexedDB/ProfilerHelpers.h
@@ -287,17 +287,17 @@ LoggingHelper(bool aUseProfiler, const c
 
   mozilla::LogModule* logModule = IndexedDatabaseManager::GetLoggingModule();
   MOZ_ASSERT(logModule);
 
   static const mozilla::LogLevel logLevel = LogLevel::Warning;
 
   if (MOZ_LOG_TEST(logModule, logLevel) ||
 #ifdef MOZ_GECKO_PROFILER
-      (aUseProfiler && profiler_is_active())
+      (aUseProfiler && profiler_thread_is_being_profiled())
 #else
       false
 #endif
      ) {
     nsAutoCString message;
 
     {
       va_list args;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3433,17 +3433,19 @@ ContentParent::ForceKillTimerCallback(ns
 
 void
 ContentParent::GeneratePairedMinidump(const char* aReason)
 {
   // We're about to kill the child process associated with this content.
   // Something has gone wrong to get us here, so we generate a minidump
   // of the parent and child for submission to the crash server unless we're
   // already shutting down.
-  if (mCrashReporter && !mShuttingDown) {
+  if (mCrashReporter &&
+      !mShuttingDown &&
+      Preferences::GetBool("dom.ipc.tabs.createKillHardCrashReports", false)) {
     // GeneratePairedMinidump creates two minidumps for us - the main
     // one is for the content process we're about to kill, and the other
     // one is for the main browser process. That second one is the extra
     // minidump tagging along, so we have to tell the crash reporter that
     // it exists and is being appended.
     nsAutoCString additionalDumps("browser");
     mCrashReporter->AddAnnotation(
       CrashReporter::Annotation::additional_minidumps, additionalDumps);
@@ -3453,18 +3455,16 @@ ContentParent::GeneratePairedMinidump(co
 
     // Generate the report and insert into the queue for submittal.
     if (mCrashReporter->GenerateMinidumpAndPair(this,
                                                 nullptr,
                                                 NS_LITERAL_CSTRING("browser")))
     {
       mCreatedPairedMinidumps = mCrashReporter->FinalizeCrashReport();
     }
-
-    Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
   }
 }
 
 // WARNING: aReason appears in telemetry, so any new value passed in requires
 // data review.
 void
 ContentParent::KillHard(const char* aReason)
 {
@@ -3476,16 +3476,19 @@ ContentParent::KillHard(const char* aRea
   if (mCalledKillHard) {
     return;
   }
   mCalledKillHard = true;
   mForceKillTimer = nullptr;
 
   GeneratePairedMinidump(aReason);
 
+  nsDependentCString reason(aReason);
+  Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1);
+
   ProcessHandle otherProcessHandle;
   if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
     NS_ERROR("Failed to open child process when attempting kill.");
     return;
   }
 
   if (!KillProcess(otherProcessHandle, base::PROCESS_END_KILLED_BY_USER,
            false)) {
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -134,16 +134,17 @@ static const char* const sExtensionNames
     "GL_EXT_draw_instanced",
     "GL_EXT_draw_range_elements",
     "GL_EXT_frag_depth",
     "GL_EXT_framebuffer_blit",
     "GL_EXT_framebuffer_multisample",
     "GL_EXT_framebuffer_object",
     "GL_EXT_framebuffer_sRGB",
     "GL_EXT_gpu_shader4",
+    "GL_EXT_map_buffer_range",
     "GL_EXT_multisampled_render_to_texture",
     "GL_EXT_occlusion_query_boolean",
     "GL_EXT_packed_depth_stencil",
     "GL_EXT_read_format_bgra",
     "GL_EXT_robustness",
     "GL_EXT_sRGB",
     "GL_EXT_sRGB_write_control",
     "GL_EXT_shader_texture_lod",
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -435,16 +435,17 @@ public:
         EXT_draw_instanced,
         EXT_draw_range_elements,
         EXT_frag_depth,
         EXT_framebuffer_blit,
         EXT_framebuffer_multisample,
         EXT_framebuffer_object,
         EXT_framebuffer_sRGB,
         EXT_gpu_shader4,
+        EXT_map_buffer_range,
         EXT_multisampled_render_to_texture,
         EXT_occlusion_query_boolean,
         EXT_packed_depth_stencil,
         EXT_read_format_bgra,
         EXT_robustness,
         EXT_sRGB,
         EXT_sRGB_write_control,
         EXT_shader_texture_lod,
--- a/gfx/gl/GLContextFeatures.cpp
+++ b/gfx/gl/GLContextFeatures.cpp
@@ -367,16 +367,17 @@ static const FeatureInfo sFeatureInfoArr
         }
     },
     {
         "map_buffer_range",
         GLVersion::GL3,
         GLESVersion::ES3,
         GLContext::ARB_map_buffer_range,
         {
+            GLContext::EXT_map_buffer_range,
             GLContext::Extensions_End
         }
     },
     {
         "occlusion_query",
         GLVersion::GL2,
         GLESVersion::NONE,
         GLContext::Extension_None,
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -81,17 +81,17 @@ DrawLayerInfo(const RenderTargetIntRect&
     aLayer->GetEffectiveTransform(), 16,
     maxWidth);
 }
 
 static void
 PrintUniformityInfo(Layer* aLayer)
 {
 #if defined(MOZ_GECKO_PROFILER)
-  if (!profiler_is_active()) {
+  if (!profiler_thread_is_being_profiled()) {
     return;
   }
 
   // Don't want to print a log for smaller layers
   if (aLayer->GetLocalVisibleRegion().GetBounds().Width() < 300 ||
       aLayer->GetLocalVisibleRegion().GetBounds().Height() < 300) {
     return;
   }
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -2071,19 +2071,21 @@ CompositorBridgeParent::GetAPZCTreeManag
   return apzctm.forget();
 }
 
 #if defined(MOZ_GECKO_PROFILER)
 static void
 InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
-  profiler_add_marker(
-    "VsyncTimestamp",
-    MakeUnique<VsyncMarkerPayload>(aVsyncTimestamp));
+  if (profiler_thread_is_being_profiled()) {
+    profiler_add_marker(
+      "VsyncTimestamp",
+      MakeUnique<VsyncMarkerPayload>(aVsyncTimestamp));
+  }
 }
 #endif
 
 /*static */ void
 CompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp)
 {
 #if defined(MOZ_GECKO_PROFILER)
   // Called in the vsync thread
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -121,32 +121,43 @@ AsyncReadbackBufferOGL::MapAndCopyInto(D
   MOZ_RELEASE_ASSERT(aReadSize <= aSurface->GetSize());
 
   if (!mGL || !mGL->MakeCurrent()) {
     return false;
   }
 
   ScopedPackState scopedPackState(mGL);
   Bind();
-  uint8_t* srcData = static_cast<uint8_t*>(
-    mGL->fMapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, LOCAL_GL_READ_ONLY));
+
+  const uint8_t *srcData = nullptr;
+  if (mGL->IsSupported(GLFeature::map_buffer_range)) {
+    srcData = static_cast<uint8_t*>(
+      mGL->fMapBufferRange(
+        LOCAL_GL_PIXEL_PACK_BUFFER,
+        0,
+        aReadSize.height * aReadSize.width * 4,
+        LOCAL_GL_MAP_READ_BIT));
+  } else {
+    srcData = static_cast<uint8_t*>(
+      mGL->fMapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, LOCAL_GL_READ_ONLY));
+  }
 
   if (!srcData) {
     return false;
   }
 
   int32_t srcStride = mSize.width * 4; // Bind() sets an alignment of 1
   DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::WRITE);
   uint8_t* destData = map.GetData();
   int32_t destStride = map.GetStride();
   SurfaceFormat destFormat = aSurface->GetFormat();
   for (int32_t destRow = 0; destRow < aReadSize.height; destRow++) {
     // Turn srcData upside down during the copy.
     int32_t srcRow = aReadSize.height - 1 - destRow;
-    uint8_t* src = &srcData[srcRow * srcStride];
+    const uint8_t* src = &srcData[srcRow * srcStride];
     uint8_t* dest = &destData[destRow * destStride];
     SwizzleData(src, srcStride, SurfaceFormat::R8G8B8A8,
                 dest, destStride, destFormat, IntSize(aReadSize.width, 1));
   }
 
   mGL->fUnmapBuffer(LOCAL_GL_PIXEL_PACK_BUFFER);
 
   return true;
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -127,16 +127,17 @@
 #include "mozilla/Alignment.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/DoublyLinkedList.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
+#include "mozilla/RandomNum.h"
 #include "mozilla/Sprintf.h"
 // Note: MozTaggedAnonymousMmap() could call an LD_PRELOADed mmap
 // instead of the one defined here; use only MozTagAnonymousMemory().
 #include "mozilla/TaggedAnonymousMemory.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/fallible.h"
@@ -1153,18 +1154,20 @@ public:
 
   Iterator iter() { return Iterator(&mArenas, &mPrivateArenas); }
 
   inline arena_t* GetDefault() { return mDefaultArena; }
 
   Mutex mLock;
 
 private:
+  inline arena_t* GetByIdInternal(arena_id_t aArenaId, bool aIsPrivate);
+
   arena_t* mDefaultArena;
-  arena_id_t mLastArenaId;
+  arena_id_t mLastPublicArenaId;
   Tree mArenas;
   Tree mPrivateArenas;
 };
 
 static ArenaCollection gArenas;
 
 // ******
 // Chunks.
@@ -3729,20 +3732,44 @@ ArenaCollection::CreateArena(bool aIsPri
     // In practice, this is an extremely unlikely failure.
     _malloc_message(_getprogname(), ": (malloc) Error initializing arena\n");
 
     return mDefaultArena;
   }
 
   MutexAutoLock lock(mLock);
 
-  // TODO: Use random Ids.
-  ret->mId = mLastArenaId++;
-  (aIsPrivate ? mPrivateArenas : mArenas).Insert(ret);
-  return ret;
+  // For public arenas, it's fine to just use incrementing arena id
+  if (!aIsPrivate) {
+    ret->mId = mLastPublicArenaId++;
+    mArenas.Insert(ret);
+    return ret;
+  }
+
+  // For private arenas, generate a cryptographically-secure random id for the 
+  // new arena. If an attacker manages to get control of the process, this 
+  // should make it more difficult for them to "guess" the ID of a memory 
+  // arena, stopping them from getting data they may want
+
+  while(true) {
+    mozilla::Maybe<uint64_t> maybeRandomId = mozilla::RandomUint64();
+    MOZ_RELEASE_ASSERT(maybeRandomId.isSome());
+
+    // Keep looping until we ensure that the random number we just generated
+    // isn't already in use by another active arena
+    arena_t* existingArena =
+      GetByIdInternal(maybeRandomId.value(), true /*aIsPrivate*/);
+
+    if (!existingArena) {
+      ret->mId = static_cast<arena_id_t>(maybeRandomId.value());
+      mPrivateArenas.Insert(ret);
+      return ret;
+    }
+  }
+
 }
 
 // End arena.
 // ***************************************************************************
 // Begin general internal functions.
 
 void*
 arena_t::MallocHuge(size_t aSize, bool aZero)
@@ -4557,27 +4584,34 @@ MozJemalloc::jemalloc_free_dirty_pages(v
     for (auto arena : gArenas.iter()) {
       MutexAutoLock arena_lock(arena->mLock);
       arena->Purge(true);
     }
   }
 }
 
 inline arena_t*
+ArenaCollection::GetByIdInternal(arena_id_t aArenaId, bool aIsPrivate)
+{
+  // Use AlignedStorage2 to avoid running the arena_t constructor, while
+  // we only need it as a placeholder for mId.
+  mozilla::AlignedStorage2<arena_t> key;
+  key.addr()->mId = aArenaId;
+  return (aIsPrivate ? mPrivateArenas : mArenas).Search(key.addr());
+}
+
+inline arena_t*
 ArenaCollection::GetById(arena_id_t aArenaId, bool aIsPrivate)
 {
   if (!malloc_initialized) {
     return nullptr;
   }
-  // Use AlignedStorage2 to avoid running the arena_t constructor, while
-  // we only need it as a placeholder for mId.
-  mozilla::AlignedStorage2<arena_t> key;
-  key.addr()->mId = aArenaId;
+  
   MutexAutoLock lock(mLock);
-  arena_t* result = (aIsPrivate ? mPrivateArenas : mArenas).Search(key.addr());
+  arena_t* result = GetByIdInternal(aArenaId, aIsPrivate);
   MOZ_RELEASE_ASSERT(result);
   return result;
 }
 
 template<>
 inline arena_id_t
 MozJemalloc::moz_create_arena_with_params(arena_params_t* aParams)
 {
--- a/memory/replace/logalloc/replay/Replay.cpp
+++ b/memory/replace/logalloc/replay/Replay.cpp
@@ -295,22 +295,16 @@ MOZ_BEGIN_EXTERN_C
 #define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
 #include "malloc_decls.h"
 
 #define MALLOC_DECL(name, return_type, ...) return_type name(__VA_ARGS__);
 #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
 #include "malloc_decls.h"
 
 #ifdef ANDROID
-/* mozjemalloc uses MozTagAnonymousMemory, which doesn't have an inline
- * implementation on Android */
-void
-MozTagAnonymousMemory(const void* aPtr, size_t aLength, const char* aTag)
-{
-}
 
 /* mozjemalloc and jemalloc use pthread_atfork, which Android doesn't have.
  * While gecko has one in libmozglue, the replay program can't use that.
  * Since we're not going to fork anyways, make it a dummy function. */
 int
 pthread_atfork(void (*aPrepare)(void),
                void (*aParent)(void),
                void (*aChild)(void))
--- a/memory/replace/logalloc/replay/moz.build
+++ b/memory/replace/logalloc/replay/moz.build
@@ -3,25 +3,27 @@
 # 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/.
 
 Program('logalloc-replay')
 
 SOURCES += [
     '/mfbt/Assertions.cpp',
+    '/mfbt/Poison.cpp',
+    '/mfbt/RandomNum.cpp',
+    '/mfbt/TaggedAnonymousMemory.cpp',
     '/mfbt/Unused.cpp',
     'Replay.cpp',
 ]
 
 if CONFIG['MOZ_REPLACE_MALLOC_STATIC'] and CONFIG['MOZ_DMD']:
     UNIFIED_SOURCES += [
         '/mfbt/HashFunctions.cpp',
         '/mfbt/JSONWriter.cpp',
-        '/mfbt/Poison.cpp',
         '/mozglue/misc/StackWalk.cpp',
     ]
 
 if not CONFIG['MOZ_REPLACE_MALLOC_STATIC']:
     SOURCES += [
         '../FdPrintf.cpp',
     ]
 
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3307,16 +3307,24 @@ pref("dom.ipc.plugins.contentTimeoutSecs
 pref("dom.ipc.plugins.processLaunchTimeoutSecs", 0);
 pref("dom.ipc.plugins.parentTimeoutSecs", 0);
 #ifdef XP_WIN
 pref("dom.ipc.plugins.hangUITimeoutSecs", 0);
 pref("dom.ipc.plugins.hangUIMinDisplaySecs", 0);
 #endif
 #endif
 
+// Whether or not to collect a paired minidump when force-killing a
+// content process.
+#ifdef RELEASE_OR_BETA
+pref("dom.ipc.tabs.createKillHardCrashReports", false);
+#else
+pref("dom.ipc.tabs.createKillHardCrashReports", true);
+#endif
+
 pref("dom.ipc.plugins.flash.disable-protected-mode", false);
 
 pref("dom.ipc.plugins.flash.subprocess.crashreporter.enabled", true);
 pref("dom.ipc.plugins.reportCrashURL", true);
 
 // How long we wait before unloading an idle plugin process.
 // Defaults to 30 seconds.
 pref("dom.ipc.plugins.unloadTimeoutSecs", 30);
--- a/testing/raptor/raptor/playback/mitmproxy.py
+++ b/testing/raptor/raptor/playback/mitmproxy.py
@@ -30,19 +30,16 @@ else:
     mozharness_dir = os.path.join(here, '../../../mozharness')
 sys.path.insert(0, mozharness_dir)
 
 # required for using a python3 virtualenv on win for mitmproxy
 from mozharness.base.python import Python3Virtualenv
 from mozharness.mozilla.testing.testbase import TestingMixin
 from mozharness.base.vcs.vcsbase import MercurialScript
 
-# import mozharness write_autoconfig_files
-from mozharness.mozilla.firefox.autoconfig import write_autoconfig_files
-
 raptor_dir = os.path.join(here, '..')
 sys.path.insert(0, raptor_dir)
 
 from utils import transform_platform
 
 external_tools_path = os.environ.get('EXTERNALTOOLSPATH', None)
 
 if external_tools_path is not None:
@@ -56,42 +53,38 @@ else:
 # on local machine it is 'HOME', however it is different on production machines
 try:
     DEFAULT_CERT_PATH = os.path.join(os.getenv('HOME'),
                                      '.mitmproxy', 'mitmproxy-ca-cert.cer')
 except Exception:
     DEFAULT_CERT_PATH = os.path.join(os.getenv('HOMEDRIVE'), os.getenv('HOMEPATH'),
                                      '.mitmproxy', 'mitmproxy-ca-cert.cer')
 
-MITMPROXY_ON_SETTINGS = '''// Start with a comment
-// Load up mitmproxy cert
-var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
-var certdb2 = certdb;
-
-try {
-certdb2 = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB2);
-} catch (e) {}
-
-cert = "%(cert)s";
-certdb2.addCertFromBase64(cert, "C,C,C", "");
+# to install mitmproxy certificate into Firefox and turn on/off proxy
+POLICIES_CONTENT_ON = '''{
+  "policies": {
+    "Certificates": {
+      "Install": ["%(cert)s"]
+    },
+    "Proxy": {
+      "Mode": "manual",
+      "HTTPProxy": "%(host)s:8080",
+      "SSLProxy": "%(host)s:8080",
+      "Passthrough": "localhost, 127.0.0.1, %(host)s"
+    }
+  }
+}'''
 
-// Use mitmdump as the proxy
-// Manual proxy configuration
-pref("network.proxy.type", 1);
-pref("network.proxy.http", "%(host)s");
-pref("network.proxy.http_port", 8080);
-pref("network.proxy.ssl", "%(host)s");
-pref("network.proxy.ssl_port", 8080);
-pref("network.proxy.no_proxies_on", "localhost, 127.0.0.1, %(host)s");
-'''
-
-MITMPROXY_OFF_SETTINGS = '''// Start with a comment
-// Turn off proxy
-pref("network.proxy.type", 0);
-'''
+POLICIES_CONTENT_OFF = '''{
+  "policies": {
+    "Proxy": {
+      "Mode": "none"
+    }
+  }
+}'''
 
 
 class Mitmproxy(Playback, Python3Virtualenv, TestingMixin, MercurialScript):
 
     def __init__(self, config):
         self.config = config
         self.mitmproxy_proc = None
         self.mitmdump_path = None
@@ -219,70 +212,93 @@ class Mitmproxy(Playback, Python3Virtual
                                                             self.browser_path)
         return
 
     def stop(self):
         self.stop_mitmproxy_playback()
         self.turn_off_browser_proxy()
         return
 
-    def configure_mitmproxy(self,
-                            fx_install_dir,
-                            certificate_path=DEFAULT_CERT_PATH):
-        certificate = self._read_certificate(certificate_path)
-        write_autoconfig_files(fx_install_dir=fx_install_dir,
-                               cfg_contents=MITMPROXY_ON_SETTINGS % {
-                                   'cert': certificate,
-                                   'host': self.config['host']})
+    def install_mitmproxy_cert(self, mitmproxy_proc, browser_path):
+        """Install the CA certificate generated by mitmproxy, into Firefox
+        1. Create a directory called distribution in the same directory as the Firefox executable
+        2. Create a file called policies.json with:
+        {
+          "policies": {
+            "certificates": {
+              "Install": ["FULL_PATH_TO_CERT"]
+            }
+          }
+        }
+        """
+        LOG.info("Installing mitmproxy CA certficate into Firefox")
+        # browser_path is the exe, we want the folder
+        self.policies_dir = os.path.dirname(browser_path)
+        # on macosx we need to remove the last folders 'MacOS'
+        # and the policies json needs to go in ../Content/Resources/
+        if 'mac' in self.config['platform']:
+            self.policies_dir = os.path.join(self.policies_dir[:-6], "Resources")
+        # for all platforms the policies json goes in a 'distribution' dir
+        self.policies_dir = os.path.join(self.policies_dir, "distribution")
+
+        self.cert_path = DEFAULT_CERT_PATH
+        # for windows only
+        if mozinfo.os == 'win':
+            self.cert_path = self.cert_path.replace('\\', '\\\\')
 
-    def _read_certificate(self, certificate_path):
-        ''' Return the certificate's hash from the certificate file.'''
-        # NOTE: mitmproxy's certificates do not exist until one of its binaries
-        #       has been executed once on the host
-        with open(certificate_path, 'r') as fd:
-            contents = fd.read()
-        return ''.join(contents.splitlines()[1:-1])
+        if not os.path.exists(self.policies_dir):
+            LOG.info("creating folder: %s" % self.policies_dir)
+            os.makedirs(self.policies_dir)
+        else:
+            LOG.info("folder already exists: %s" % self.policies_dir)
+
+        self.write_policies_json(self.policies_dir,
+                                 policies_content=POLICIES_CONTENT_ON %
+                                 {'cert': self.cert_path,
+                                  'host': self.config['host']})
+
+        # cannot continue if failed to add CA cert to Firefox, need to check
+        if not self.is_mitmproxy_cert_installed():
+            LOG.error('Aborting: failed to install mitmproxy CA cert into Firefox')
+            self.stop_mitmproxy_playback()
+            sys.exit()
 
-    def is_mitmproxy_cert_installed(self, browser_install):
+    def write_policies_json(self, location, policies_content):
+        policies_file = os.path.join(location, "policies.json")
+        LOG.info("writing: %s" % policies_file)
+
+        with open(policies_file, 'w') as fd:
+            fd.write(policies_content)
+
+    def read_policies_json(self, location):
+        policies_file = os.path.join(location, "policies.json")
+        LOG.info("reading: %s" % policies_file)
+
+        with open(policies_file, 'r') as fd:
+            return fd.read()
+
+    def is_mitmproxy_cert_installed(self):
         """Verify mitmxproy CA cert was added to Firefox"""
-        from mozharness.mozilla.firefox.autoconfig import read_autoconfig_file
         try:
             # read autoconfig file, confirm mitmproxy cert is in there
-            certificate = self._read_certificate(DEFAULT_CERT_PATH)
-            contents = read_autoconfig_file(browser_install)
-            if (MITMPROXY_ON_SETTINGS % {
-                    'cert': certificate,
+            contents = self.read_policies_json(self.policies_dir)
+            LOG.info("Firefox policies file contents:")
+            LOG.info(contents)
+            if (POLICIES_CONTENT_ON % {
+                    'cert': self.cert_path,
                     'host': self.config['host']}) in contents:
                 LOG.info("Verified mitmproxy CA certificate is installed in Firefox")
             else:
-                LOG.info("Firefox autoconfig file contents:")
-                LOG.info(contents)
+
                 return False
-        except Exception:
-            LOG.info("Failed to read Firefox autoconfig file, when verifying CA cert install")
+        except Exception as e:
+            LOG.info("failed to read Firefox policies file, exeption: %s" % e)
             return False
         return True
 
-    def install_mitmproxy_cert(self, mitmproxy_proc, browser_path):
-        """Install the CA certificate generated by mitmproxy, into Firefox"""
-        LOG.info("Installing mitmxproxy CA certficate into Firefox")
-        # browser_path is exe, we want install dir
-        self.browser_install = os.path.dirname(browser_path)
-        # on macosx we need to remove the last folders 'Content/MacOS'
-        if mozinfo.os == 'mac':
-            self.browser_install = self.browser_install[:-14]
-
-        LOG.info('Calling configure_mitmproxy with browser folder: %s' % self.browser_install)
-        self.configure_mitmproxy(self.browser_install)
-        # cannot continue if failed to add CA cert to Firefox, need to check
-        if not self.is_mitmproxy_cert_installed(self.browser_install):
-            LOG.error('Aborting: failed to install mitmproxy CA cert into Firefox')
-            self.stop_mitmproxy_playback()
-            sys.exit()
-
     def start_mitmproxy_playback(self,
                                  mitmdump_path,
                                  mitmproxy_recording_path,
                                  mitmproxy_recordings_list,
                                  browser_path):
         """Startup mitmproxy and replay the specified flow file"""
 
         LOG.info("mitmdump path: %s" % mitmdump_path)
@@ -351,10 +367,10 @@ class Mitmproxy(Playback, Python3Virtual
     def turn_off_browser_proxy(self):
         """Turn off the browser proxy that was used for mitmproxy playback"""
         # in firefox we need to change the autoconfig files to revert
         # the proxy; for google chromium the proxy was setup on the cmd line
         # so nothing is required here
         if self.config['app'] == "firefox":
             LOG.info("Turning off the browser proxy")
 
-            write_autoconfig_files(fx_install_dir=self.browser_install,
-                                   cfg_contents=MITMPROXY_OFF_SETTINGS)
+            self.write_policies_json(self.policies_dir,
+                                     policies_content=POLICIES_CONTENT_OFF)
--- a/testing/talos/talos/mitmproxy/mitmproxy.py
+++ b/testing/talos/talos/mitmproxy/mitmproxy.py
@@ -20,98 +20,124 @@ LOG = get_proxy_logger()
 # on local machine it is 'HOME', however it is different on production machines
 try:
     DEFAULT_CERT_PATH = os.path.join(os.getenv('HOME'),
                                      '.mitmproxy', 'mitmproxy-ca-cert.cer')
 except Exception:
     DEFAULT_CERT_PATH = os.path.join(os.getenv('HOMEDRIVE'), os.getenv('HOMEPATH'),
                                      '.mitmproxy', 'mitmproxy-ca-cert.cer')
 
-MITMPROXY_SETTINGS = '''// Start with a comment
-// Load up mitmproxy cert
-var certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB);
-var certdb2 = certdb;
-
-try {
-certdb2 = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB2);
-} catch (e) {}
-
-cert = "%(cert)s";
-certdb2.addCertFromBase64(cert, "C,C,C", "");
+# to install mitmproxy certificate into Firefox and turn on/off proxy
+POLICIES_CONTENT_ON = '''{
+  "policies": {
+    "Certificates": {
+      "Install": ["%(cert)s"]
+    },
+    "Proxy": {
+      "Mode": "manual",
+      "HTTPProxy": "127.0.0.1:8080",
+      "SSLProxy": "127.0.0.1:8080",
+      "Passthrough": "localhost, 127.0.0.1"
+    }
+  }
+}'''
 
-// Use mitmdump as the proxy
-// Manual proxy configuration
-pref("network.proxy.type", 1);
-pref("network.proxy.http", "127.0.0.1");
-pref("network.proxy.http_port", 8080);
-pref("network.proxy.ssl", "127.0.0.1");
-pref("network.proxy.ssl_port", 8080);
-'''
-
-
-def configure_mitmproxy(fx_install_dir,
-                        scripts_path,
-                        certificate_path=DEFAULT_CERT_PATH):
-    # scripts_path is path to mozharness on test machine; needed so can import
-    if scripts_path is not False:
-        sys.path.insert(1, scripts_path)
-        sys.path.insert(1, os.path.join(scripts_path, 'mozharness'))
-    from mozharness.mozilla.firefox.autoconfig import write_autoconfig_files
-    certificate = _read_certificate(certificate_path)
-    write_autoconfig_files(fx_install_dir=fx_install_dir,
-                           cfg_contents=MITMPROXY_SETTINGS % {
-                              'cert': certificate})
+POLICIES_CONTENT_OFF = '''{
+  "policies": {
+    "Proxy": {
+      "Mode": "none"
+    }
+  }
+}'''
 
 
-def _read_certificate(certificate_path):
-    ''' Return the certificate's hash from the certificate file.'''
-    # NOTE: mitmproxy's certificates do not exist until one of its binaries
-    #       has been executed once on the host
-    with open(certificate_path, 'r') as fd:
-        contents = fd.read()
-    return ''.join(contents.splitlines()[1:-1])
-
+def install_mitmproxy_cert(mitmproxy_proc, browser_path):
+    """Install the CA certificate generated by mitmproxy, into Firefox
+    1. Create a directory called distribution in the same directory as the Firefox executable
+    2. Create a file called policies.json with:
+    {
+      "policies": {
+        "certificates": {
+          "Install": ["FULL_PATH_TO_CERT"]
+        }
+      }
+    }
+    """
+    LOG.info("Installing mitmproxy CA certficate into Firefox")
+    # browser_path is the exe, we want the folder
+    policies_dir = os.path.dirname(browser_path)
+    # on macosx we need to remove the last folders 'MacOS'
+    # and the policies json needs to go in ../Content/Resources/
+    if 'mac' in mozinfo.os:
+        policies_dir = os.path.join(policies_dir[:-6], "Resources")
+    # for all platforms the policies json goes in a 'distribution' dir
+    policies_dir = os.path.join(policies_dir, "distribution")
 
-def is_mitmproxy_cert_installed(browser_install):
-    """Verify mitmxproy CA cert was added to Firefox"""
-    from mozharness.mozilla.firefox.autoconfig import read_autoconfig_file
-    try:
-        # read autoconfig file, confirm mitmproxy cert is in there
-        certificate = _read_certificate(DEFAULT_CERT_PATH)
-        contents = read_autoconfig_file(browser_install)
-        if (MITMPROXY_SETTINGS % {'cert': certificate}) in contents:
-            LOG.info("Verified mitmproxy CA certificate is installed in Firefox")
-        else:
-            LOG.info("Firefox autoconfig file contents:")
-            LOG.info(contents)
-            return False
-    except Exception:
-        LOG.info("Failed to read Firefox autoconfig file, when verifying CA certificate install")
-        return False
-    return True
+    cert_path = DEFAULT_CERT_PATH
+    # for windows only
+    if mozinfo.os == 'win':
+        cert_path = cert_path.replace('\\', '\\\\')
 
+    if not os.path.exists(policies_dir):
+        LOG.info("creating folder: %s" % policies_dir)
+        os.makedirs(policies_dir)
+    else:
+        LOG.info("folder already exists: %s" % policies_dir)
 
-def install_mitmproxy_cert(mitmproxy_proc, browser_path, scripts_path):
-    """Install the CA certificate generated by mitmproxy, into Firefox"""
-    LOG.info("Installing mitmxproxy CA certficate into Firefox")
-    # browser_path is exe, we want install dir
-    browser_install = os.path.dirname(browser_path)
-    # on macosx we need to remove the last folders 'Content/MacOS'
-    if mozinfo.os == 'mac':
-        browser_install = browser_install[:-14]
+    write_policies_json(policies_dir,
+                        policies_content=POLICIES_CONTENT_ON %
+                        {'cert': cert_path})
 
-    LOG.info('Calling configure_mitmproxy with browser folder: %s' % browser_install)
-    configure_mitmproxy(browser_install, scripts_path)
     # cannot continue if failed to add CA cert to Firefox, need to check
-    if not is_mitmproxy_cert_installed(browser_install):
+    if not is_mitmproxy_cert_installed(policies_dir):
         LOG.error('Aborting: failed to install mitmproxy CA cert into Firefox')
         stop_mitmproxy_playback(mitmproxy_proc)
         sys.exit()
 
 
+def write_policies_json(location, policies_content):
+    policies_file = os.path.join(location, "policies.json")
+    LOG.info("writing: %s" % policies_file)
+
+    with open(policies_file, 'w') as fd:
+        fd.write(policies_content)
+
+
+def read_policies_json(location):
+    policies_file = os.path.join(location, "policies.json")
+    LOG.info("reading: %s" % policies_file)
+
+    with open(policies_file, 'r') as fd:
+        return fd.read()
+
+
+def is_mitmproxy_cert_installed(policies_dir):
+    """Verify mitmxproy CA cert was added to Firefox"""
+    try:
+        # read autoconfig file, confirm mitmproxy cert is in there
+        contents = read_policies_json(policies_dir)
+        LOG.info("Firefox policies file contents:")
+        LOG.info(contents)
+
+        cert_path = DEFAULT_CERT_PATH
+        # for windows only
+        if mozinfo.os == 'win':
+            cert_path = cert_path.replace('\\', '\\\\')
+
+        if (POLICIES_CONTENT_ON % {
+                'cert': cert_path}) in contents:
+            LOG.info("Verified mitmproxy CA certificate is installed in Firefox")
+        else:
+            return False
+    except Exception as e:
+        LOG.info("failed to read Firefox policies file, exeption: %s" % e)
+        return False
+    return True
+
+
 def start_mitmproxy_playback(mitmdump_path,
                              mitmproxy_recording_path,
                              mitmproxy_recordings_list,
                              browser_path):
     """Startup mitmproxy and replay the specified flow file"""
     mitmproxy_recordings = []
     # recording names can be provided in comma-separated list; build py list including path
     for recording in mitmproxy_recordings_list:
--- a/testing/talos/talos/run_tests.py
+++ b/testing/talos/talos/run_tests.py
@@ -239,22 +239,18 @@ def run_tests(config, browser_config):
         mitmproxy_recording_path = os.path.join(here, 'mitmproxy')
         mitmproxy_proc = mitmproxy.start_mitmproxy_playback(mitmdump_path,
                                                             mitmproxy_recording_path,
                                                             mitmproxy_recordings_list.split(),
                                                             browser_config['browser_path'])
 
         # install the generated CA certificate into Firefox
         # mitmproxy cert setup needs path to mozharness install; mozharness has set this
-        # value in the SCRIPTSPATH env var for us in mozharness/mozilla/testing/talos.py
-        scripts_path = os.environ.get('SCRIPTSPATH')
-        LOG.info('scripts_path: %s' % str(scripts_path))
         mitmproxy.install_mitmproxy_cert(mitmproxy_proc,
-                                         browser_config['browser_path'],
-                                         str(scripts_path))
+                                         browser_config['browser_path'])
 
     testname = None
 
     # run the tests
     timer = utils.Timer()
     LOG.suite_start(tests=[test['name'] for test in tests])
     try:
         for test in tests:
--- a/tools/profiler/core/RegisteredThread.h
+++ b/tools/profiler/core/RegisteredThread.h
@@ -18,29 +18,39 @@
 // the "Racy" prefix.
 //
 class RacyRegisteredThread final
 {
 public:
   explicit RacyRegisteredThread(int aThreadId)
     : mThreadId(aThreadId)
     , mSleep(AWAKE)
+    , mIsBeingProfiled(false)
   {
     MOZ_COUNT_CTOR(RacyRegisteredThread);
   }
 
   ~RacyRegisteredThread()
   {
     MOZ_COUNT_DTOR(RacyRegisteredThread);
   }
 
+  void SetIsBeingProfiled(bool aIsBeingProfiled)
+  {
+    mIsBeingProfiled = aIsBeingProfiled;
+  }
+
+  bool IsBeingProfiled() const { return mIsBeingProfiled; }
+
   void AddPendingMarker(const char* aMarkerName,
                         mozilla::UniquePtr<ProfilerMarkerPayload> aPayload,
                         double aTime)
   {
+    // Note: We don't assert on mIsBeingProfiled, because it could have changed
+    // between the check in the caller and now.
     ProfilerMarker* marker =
       new ProfilerMarker(aMarkerName, mThreadId, std::move(aPayload), aTime);
     mPendingMarkers.insert(marker);
   }
 
   // Called within signal. Function must be reentrant.
   ProfilerMarkerLinkedList* GetPendingMarkers()
   {
@@ -140,16 +150,22 @@ private:
   // e.g. the section where Tick() is called. But that would reduce the
   // effectiveness of the optimization because more code would have to be run
   // before we can tell that duplication is allowed.
   //
   static const int AWAKE = 0;
   static const int SLEEPING_NOT_OBSERVED = 1;
   static const int SLEEPING_OBSERVED = 2;
   mozilla::Atomic<int> mSleep;
+
+  // Is this thread being profiled? (e.g., should markers be recorded?)
+  // Accesses to this atomic are not recorded by web replay as they may occur
+  // at non-deterministic points.
+  mozilla::Atomic<bool, mozilla::MemoryOrdering::Relaxed,
+                  recordreplay::Behavior::DontPreserve> mIsBeingProfiled;
 };
 
 // This class contains information that's relevant to a single thread only
 // while that thread is running and registered with the profiler, but
 // regardless of whether the profiler is running. All accesses to it are
 // protected by the profiler state lock.
 class RegisteredThread final
 {
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -2525,16 +2525,17 @@ locked_register_thread(PSLockRef aLock, 
   UniquePtr<RegisteredThread> registeredThread =
     MakeUnique<RegisteredThread>(info, NS_GetCurrentThreadNoCreate(),
                                  aStackTop);
 
   TLSRegisteredThread::SetRegisteredThread(aLock, registeredThread.get());
 
   if (ActivePS::Exists(aLock) &&
       ActivePS::ShouldProfileThread(aLock, info)) {
+    registeredThread->RacyRegisteredThread().SetIsBeingProfiled(true);
     nsCOMPtr<nsIEventTarget> eventTarget = registeredThread->GetEventTarget();
     ProfiledThreadData* profiledThreadData =
       ActivePS::AddLiveProfiledThread(aLock, registeredThread.get(),
         MakeUnique<ProfiledThreadData>(info, eventTarget,
                                        ActivePS::FeatureResponsiveness(aLock)));
 
     if (ActivePS::FeatureJS(aLock)) {
       // This StartJSSampling() call is on-thread, so we can poll manually to
@@ -3161,16 +3162,17 @@ locked_profiler_start(PSLockRef aLock, u
   // Set up profiling for each registered thread, if appropriate.
   int tid = Thread::GetCurrentId();
   const nsTArray<UniquePtr<RegisteredThread>>& registeredThreads =
     CorePS::RegisteredThreads(aLock);
   for (auto& registeredThread : registeredThreads) {
     RefPtr<ThreadInfo> info = registeredThread->Info();
 
     if (ActivePS::ShouldProfileThread(aLock, info)) {
+      registeredThread->RacyRegisteredThread().SetIsBeingProfiled(true);
       nsCOMPtr<nsIEventTarget> eventTarget = registeredThread->GetEventTarget();
       ProfiledThreadData* profiledThreadData =
         ActivePS::AddLiveProfiledThread(aLock, registeredThread.get(),
           MakeUnique<ProfiledThreadData>(info, eventTarget,
                                          ActivePS::FeatureResponsiveness(aLock)));
       if (ActivePS::FeatureJS(aLock)) {
         registeredThread->StartJSSampling(
           ActivePS::FeatureTrackOptimizations(aLock));
@@ -3328,16 +3330,17 @@ locked_profiler_stop(PSLockRef aLock)
 #endif
 
   // Stop sampling live threads.
   int tid = Thread::GetCurrentId();
   const nsTArray<LiveProfiledThreadData>& liveProfiledThreads =
     ActivePS::LiveProfiledThreads(aLock);
   for (auto& thread : liveProfiledThreads) {
     RegisteredThread* registeredThread = thread.mRegisteredThread;
+    registeredThread->RacyRegisteredThread().SetIsBeingProfiled(false);
     if (ActivePS::FeatureJS(aLock)) {
       registeredThread->StopJSSampling();
       RefPtr<ThreadInfo> info = registeredThread->Info();
       if (info->ThreadId() == tid) {
         // We can manually poll the current thread so it stops profiling
         // immediately.
         registeredThread->PollJSSampling();
       } else if (info->IsMainThread()) {
@@ -3632,16 +3635,26 @@ profiler_thread_wake()
   if (!racyRegisteredThread) {
     return;
   }
 
   racyRegisteredThread->SetAwake();
 }
 
 bool
+mozilla::profiler::detail::IsThreadBeingProfiled()
+{
+  MOZ_RELEASE_ASSERT(CorePS::Exists());
+
+  const RacyRegisteredThread* racyRegisteredThread =
+    TLSRegisteredThread::RacyRegisteredThread();
+  return racyRegisteredThread && racyRegisteredThread->IsBeingProfiled();
+}
+
+bool
 profiler_thread_is_sleeping()
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
   RacyRegisteredThread* racyRegisteredThread =
     TLSRegisteredThread::RacyRegisteredThread();
   if (!racyRegisteredThread) {
@@ -3711,26 +3724,26 @@ ProfilerBacktraceDestructor::operator()(
 }
 
 static void
 racy_profiler_add_marker(const char* aMarkerName,
                          UniquePtr<ProfilerMarkerPayload> aPayload)
 {
   MOZ_RELEASE_ASSERT(CorePS::Exists());
 
-  // We don't assert that RacyFeatures::IsActiveWithoutPrivacy() is true here,
-  // because it's possible that the result has changed since we tested it in
-  // the caller.
+  // We don't assert that RacyFeatures::IsActiveWithoutPrivacy() or
+  // RacyRegisteredThread::IsBeingProfiled() is true here, because it's
+  // possible that the result has changed since we tested it in the caller.
   //
   // Because of this imprecision it's possible to miss a marker or record one
   // we shouldn't. Either way is not a big deal.
 
   RacyRegisteredThread* racyRegisteredThread =
     TLSRegisteredThread::RacyRegisteredThread();
-  if (!racyRegisteredThread) {
+  if (!racyRegisteredThread || !racyRegisteredThread->IsBeingProfiled()) {
     return;
   }
 
   TimeStamp origin = (aPayload && !aPayload->GetStartTime().IsNull())
                        ? aPayload->GetStartTime()
                        : TimeStamp::Now();
   TimeDuration delta = origin - CorePS::ProcessStartTime();
   racyRegisteredThread->AddPendingMarker(aMarkerName, std::move(aPayload),
--- a/tools/profiler/gecko/ProfilerIOInterposeObserver.cpp
+++ b/tools/profiler/gecko/ProfilerIOInterposeObserver.cpp
@@ -5,17 +5,17 @@
 #include "GeckoProfiler.h"
 #include "ProfilerIOInterposeObserver.h"
 #include "ProfilerMarkerPayload.h"
 
 using namespace mozilla;
 
 void ProfilerIOInterposeObserver::Observe(Observation& aObservation)
 {
-  if (!IsMainThread()) {
+  if (!IsMainThread() || !profiler_thread_is_being_profiled()) {
     return;
   }
 
   UniqueProfilerBacktrace stack = profiler_get_backtrace();
 
   nsString filename;
   aObservation.Filename(filename);
   profiler_add_marker(
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -222,16 +222,18 @@ private:
 
   // We combine the active bit with the feature bits so they can be read or
   // written in a single atomic operation. Accesses to this atomic are not
   // recorded by web replay as they may occur at non-deterministic points.
   static mozilla::Atomic<uint32_t, mozilla::MemoryOrdering::Relaxed,
                          recordreplay::Behavior::DontPreserve> sActiveAndFeatures;
 };
 
+bool IsThreadBeingProfiled();
+
 } // namespace detail
 } // namespace profiler
 } // namespace mozilla
 
 //---------------------------------------------------------------------------
 // Start and stop the profiler
 //---------------------------------------------------------------------------
 
@@ -389,16 +391,24 @@ void profiler_clear_js_context();
 // expensive data will end up being created but not used if another thread
 // stops the profiler between the CreateExpensiveData() and PROFILER_OPERATION
 // calls.
 inline bool profiler_is_active()
 {
   return mozilla::profiler::detail::RacyFeatures::IsActive();
 }
 
+// Is the profiler active, and is the current thread being profiled?
+// (Same caveats and recommented usage as profiler_is_active().)
+inline bool profiler_thread_is_being_profiled()
+{
+  return profiler_is_active() &&
+         mozilla::profiler::detail::IsThreadBeingProfiled();
+}
+
 // Is the profiler active and paused? Returns false if the profiler is inactive.
 bool profiler_is_paused();
 
 // Is the current thread sleeping?
 bool profiler_thread_is_sleeping();
 
 // Get all the features supported by the profiler that are accepted by
 // profiler_start(). The result is the same whether the profiler is active or
--- a/widget/windows/WinHeaderOnlyUtils.h
+++ b/widget/windows/WinHeaderOnlyUtils.h
@@ -91,21 +91,26 @@ public:
     return WindowsError(S_OK);
   }
 
   static WindowsError CreateGeneric()
   {
     return FromWin32Error(ERROR_UNIDENTIFIED_ERROR);
   }
 
-  explicit operator bool() const
+  bool IsSuccess() const
   {
     return SUCCEEDED(mHResult);
   }
 
+  bool IsFailure() const
+  {
+    return FAILED(mHResult);
+  }
+
   bool IsAvailableAsWin32Error() const
   {
     return IsAvailableAsNtStatus() ||
            HRESULT_FACILITY(mHResult) == FACILITY_WIN32;
   }
 
   bool IsAvailableAsNtStatus() const
   {
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -834,17 +834,17 @@ CycleCollectedJSRuntime::GCCallback(JSCo
 CycleCollectedJSRuntime::GCSliceCallback(JSContext* aContext,
                                          JS::GCProgress aProgress,
                                          const JS::GCDescription& aDesc)
 {
   CycleCollectedJSRuntime* self = CycleCollectedJSRuntime::Get();
   MOZ_ASSERT(CycleCollectedJSContext::Get()->Context() == aContext);
 
 #ifdef MOZ_GECKO_PROFILER
-  if (profiler_is_active()) {
+  if (profiler_thread_is_being_profiled()) {
     if (aProgress == JS::GC_CYCLE_END) {
       profiler_add_marker(
         "GCMajor",
         MakeUnique<GCMajorMarkerPayload>(aDesc.startTime(aContext),
                                          aDesc.endTime(aContext),
                                          aDesc.summaryToJSON(aContext)));
     } else if (aProgress == JS::GC_SLICE_END) {
       profiler_add_marker(
@@ -935,17 +935,17 @@ CycleCollectedJSRuntime::GCNurseryCollec
     timelines->AddMarkerForAllObservedDocShells(abstractMarker);
   }
 
   if (aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_START) {
     self->mLatestNurseryCollectionStart = TimeStamp::Now();
   }
 #ifdef MOZ_GECKO_PROFILER
   else if (aProgress == JS::GCNurseryProgress::GC_NURSERY_COLLECTION_END &&
-           profiler_is_active())
+           profiler_thread_is_being_profiled())
   {
     profiler_add_marker(
       "GCMinor",
       MakeUnique<GCMinorMarkerPayload>(self->mLatestNurseryCollectionStart,
                                        TimeStamp::Now(),
                                        JS::MinorGcToJSON(aContext)));
   }
 #endif
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -1250,17 +1250,17 @@ nsThread::ProcessNextEvent(bool aMayWait
         duration = now - mCurrentEventStart;
         if (duration.ToMilliseconds() > LONGTASK_BUSY_WINDOW_MS) {
           // Idle events (gc...) don't *really* count here
           if (priority != EventPriority::Idle) {
             mLastLongNonIdleTaskEnd = now;
           }
           mLastLongTaskEnd = now;
 #ifdef MOZ_GECKO_PROFILER
-          if (profiler_is_active()) {
+          if (profiler_thread_is_being_profiled()) {
               profiler_add_marker(
                 (priority != EventPriority::Idle) ? "LongTask" : "LongIdleTask",
                 MakeUnique<LongTaskMarkerPayload>(mCurrentEventStart, now));
           }
 #endif
         }
       }