Bug 1128768: Part 2 - Refactor hang annotation code; r=vladan
authorAaron Klotz <aklotz@mozilla.com>
Mon, 09 Mar 2015 19:41:24 -0600
changeset 232584 13eb8592325c6886fd8f02b7b0390120f08ac503
parent 232583 613ea27a306e068e3343b5f45f5e7e026d6b6e0c
child 232585 c3501a329f69bad4ab9f90bc827c69758f1a5d49
push id56615
push useraklotz@mozilla.com
push dateTue, 10 Mar 2015 01:45:08 +0000
treeherdermozilla-inbound@0df0abc0f58c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvladan
bugs1128768
milestone39.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
Bug 1128768: Part 2 - Refactor hang annotation code; r=vladan
toolkit/components/telemetry/Telemetry.cpp
xpcom/threads/HangAnnotations.cpp
xpcom/threads/HangAnnotations.h
xpcom/threads/HangMonitor.cpp
xpcom/threads/HangMonitor.h
xpcom/threads/moz.build
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -2548,19 +2548,19 @@ TelemetryImpl::GetChromeHangs(JSContext 
       indexValue.setNumber(annotationInfo[iterIndex].mHangIndex);
       if (!JS_DefineElement(cx, keyValueArray, 0, indexValue, JSPROP_ENUMERATE)) {
         return NS_ERROR_FAILURE;
       }
       JS::Rooted<JSObject*> jsAnnotation(cx, JS_NewPlainObject(cx));
       if (!jsAnnotation) {
         return NS_ERROR_FAILURE;
       }
-      nsAutoPtr<HangAnnotations::Enumerator> annotationsEnum;
-      if (!annotationInfo[iterIndex].mAnnotations->GetEnumerator(
-            annotationsEnum.StartAssignment())) {
+      UniquePtr<HangAnnotations::Enumerator> annotationsEnum =
+        annotationInfo[iterIndex].mAnnotations->GetEnumerator();
+      if (!annotationsEnum) {
         return NS_ERROR_FAILURE;
       }
       nsAutoString  key;
       nsAutoString  value;
       while (annotationsEnum->Next(key, value)) {
         JS::RootedValue jsValue(cx);
         jsValue.setString(JS_NewUCStringCopyN(cx, value.get(), value.Length()));
         if (!JS_DefineUCProperty(cx, jsAnnotation, key.get(), key.Length(),
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/HangAnnotations.cpp
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/HangAnnotations.h"
+
+#include <vector>
+
+#include "MainThreadUtils.h"
+#include "mozilla/DebugOnly.h"
+#include "nsXULAppAPI.h"
+
+namespace mozilla {
+namespace HangMonitor {
+
+// Chrome hang annotators. This can go away once BHR has completely replaced
+// ChromeHangs.
+static StaticAutoPtr<Observer::Annotators> gChromehangAnnotators;
+
+class BrowserHangAnnotations : public HangAnnotations
+{
+public:
+  BrowserHangAnnotations();
+  ~BrowserHangAnnotations();
+
+  void AddAnnotation(const nsAString& aName, const int32_t aData) MOZ_OVERRIDE;
+  void AddAnnotation(const nsAString& aName, const double aData) MOZ_OVERRIDE;
+  void AddAnnotation(const nsAString& aName, const nsAString& aData) MOZ_OVERRIDE;
+  void AddAnnotation(const nsAString& aName, const nsACString& aData) MOZ_OVERRIDE;
+  void AddAnnotation(const nsAString& aName, const bool aData) MOZ_OVERRIDE;
+
+  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
+  bool IsEmpty() const MOZ_OVERRIDE;
+  UniquePtr<Enumerator> GetEnumerator() MOZ_OVERRIDE;
+
+  typedef std::pair<nsString, nsString> AnnotationType;
+  typedef std::vector<AnnotationType> VectorType;
+  typedef VectorType::const_iterator IteratorType;
+
+private:
+  VectorType  mAnnotations;
+};
+
+BrowserHangAnnotations::BrowserHangAnnotations()
+{
+  MOZ_COUNT_CTOR(BrowserHangAnnotations);
+}
+
+BrowserHangAnnotations::~BrowserHangAnnotations()
+{
+  MOZ_COUNT_DTOR(BrowserHangAnnotations);
+}
+
+void
+BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData)
+{
+  nsString dataString;
+  dataString.AppendInt(aData);
+  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
+  mAnnotations.push_back(annotation);
+}
+
+void
+BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const double aData)
+{
+  nsString dataString;
+  dataString.AppendFloat(aData);
+  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
+  mAnnotations.push_back(annotation);
+}
+
+void
+BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData)
+{
+  AnnotationType annotation = std::make_pair(nsString(aName), nsString(aData));
+  mAnnotations.push_back(annotation);
+}
+
+void
+BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData)
+{
+  nsString dataString;
+  AppendUTF8toUTF16(aData, dataString);
+  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
+  mAnnotations.push_back(annotation);
+}
+
+void
+BrowserHangAnnotations::AddAnnotation(const nsAString& aName, const bool aData)
+{
+  nsString dataString;
+  dataString += aData ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false");
+  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
+  mAnnotations.push_back(annotation);
+}
+
+/**
+ * This class itself does not use synchronization but it (and its parent object)
+ * should be protected by mutual exclusion in some way. In Telemetry the chrome
+ * hang data is protected via TelemetryImpl::mHangReportsMutex.
+ */
+class ChromeHangAnnotationEnumerator : public HangAnnotations::Enumerator
+{
+public:
+  explicit ChromeHangAnnotationEnumerator(const BrowserHangAnnotations::VectorType& aAnnotations);
+  ~ChromeHangAnnotationEnumerator();
+
+  virtual bool Next(nsAString& aOutName, nsAString& aOutValue);
+
+private:
+  BrowserHangAnnotations::IteratorType mIterator;
+  BrowserHangAnnotations::IteratorType mEnd;
+};
+
+ChromeHangAnnotationEnumerator::ChromeHangAnnotationEnumerator(
+                          const BrowserHangAnnotations::VectorType& aAnnotations)
+  : mIterator(aAnnotations.begin())
+  , mEnd(aAnnotations.end())
+{
+  MOZ_COUNT_CTOR(ChromeHangAnnotationEnumerator);
+}
+
+ChromeHangAnnotationEnumerator::~ChromeHangAnnotationEnumerator()
+{
+  MOZ_COUNT_DTOR(ChromeHangAnnotationEnumerator);
+}
+
+bool
+ChromeHangAnnotationEnumerator::Next(nsAString& aOutName, nsAString& aOutValue)
+{
+  aOutName.Truncate();
+  aOutValue.Truncate();
+  if (mIterator == mEnd) {
+    return false;
+  }
+  aOutName = mIterator->first;
+  aOutValue = mIterator->second;
+  ++mIterator;
+  return true;
+}
+
+bool
+BrowserHangAnnotations::IsEmpty() const
+{
+  return mAnnotations.empty();
+}
+
+size_t
+BrowserHangAnnotations::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+{
+  size_t result = sizeof(mAnnotations) +
+                  mAnnotations.capacity() * sizeof(AnnotationType);
+  for (IteratorType i = mAnnotations.begin(), e = mAnnotations.end(); i != e;
+       ++i) {
+    result += i->first.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+    result += i->second.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
+  }
+
+  return result;
+}
+
+UniquePtr<HangAnnotations::Enumerator>
+BrowserHangAnnotations::GetEnumerator()
+{
+  if (mAnnotations.empty()) {
+    return nullptr;
+  }
+  return MakeUnique<ChromeHangAnnotationEnumerator>(mAnnotations);
+}
+
+namespace Observer {
+
+Annotators::Annotators()
+  : mMutex("HangMonitor::Annotators::mMutex")
+{
+  MOZ_COUNT_CTOR(Annotators);
+}
+
+Annotators::~Annotators()
+{
+  MOZ_ASSERT(mAnnotators.empty());
+  MOZ_COUNT_DTOR(Annotators);
+}
+
+bool
+Annotators::Register(Annotator& aAnnotator)
+{
+  MutexAutoLock lock(mMutex);
+  auto result = mAnnotators.insert(&aAnnotator);
+  return result.second;
+}
+
+bool
+Annotators::Unregister(Annotator& aAnnotator)
+{
+  MutexAutoLock lock(mMutex);
+  DebugOnly<std::set<Annotator*>::size_type> numErased;
+  numErased = mAnnotators.erase(&aAnnotator);
+  MOZ_ASSERT(numErased == 1);
+  return mAnnotators.empty();
+}
+
+UniquePtr<HangAnnotations>
+Annotators::GatherAnnotations()
+{
+  auto annotations = MakeUnique<BrowserHangAnnotations>();
+  { // Scope for lock
+    MutexAutoLock lock(mMutex);
+    for (std::set<Annotator*>::iterator i = mAnnotators.begin(),
+                                        e = mAnnotators.end();
+         i != e; ++i) {
+      (*i)->AnnotateHang(*annotations);
+    }
+  }
+  if (annotations->IsEmpty()) {
+    return nullptr;
+  }
+  return Move(annotations);
+}
+
+} // namespace Observer
+
+void
+RegisterAnnotator(Annotator& aAnnotator)
+{
+  BackgroundHangMonitor::RegisterAnnotator(aAnnotator);
+  // We still register annotators for ChromeHangs
+  if (NS_IsMainThread() &&
+      GeckoProcessType_Default == XRE_GetProcessType()) {
+    if (!gChromehangAnnotators) {
+      gChromehangAnnotators = new Observer::Annotators();
+    }
+    gChromehangAnnotators->Register(aAnnotator);
+  }
+}
+
+void
+UnregisterAnnotator(Annotator& aAnnotator)
+{
+  BackgroundHangMonitor::UnregisterAnnotator(aAnnotator);
+  // We still register annotators for ChromeHangs
+  if (NS_IsMainThread() &&
+      GeckoProcessType_Default == XRE_GetProcessType()) {
+    if (gChromehangAnnotators->Unregister(aAnnotator)) {
+      gChromehangAnnotators = nullptr;
+    }
+  }
+}
+
+UniquePtr<HangAnnotations>
+ChromeHangAnnotatorCallout()
+{
+  if (!gChromehangAnnotators) {
+    return nullptr;
+  }
+  return gChromehangAnnotators->GatherAnnotations();
+}
+
+} // namespace HangMonitor
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/HangAnnotations.h
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_HangAnnotations_h
+#define mozilla_HangAnnotations_h
+
+#include <set>
+
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Vector.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace HangMonitor {
+
+/**
+ * This class declares an abstraction for a data type that encapsulates all
+ * of the annotations being reported by a registered hang Annotator.
+ */
+class HangAnnotations
+{
+public:
+  virtual ~HangAnnotations() {}
+
+  virtual void AddAnnotation(const nsAString& aName, const int32_t aData) = 0;
+  virtual void AddAnnotation(const nsAString& aName, const double aData) = 0;
+  virtual void AddAnnotation(const nsAString& aName, const nsAString& aData) = 0;
+  virtual void AddAnnotation(const nsAString& aName, const nsACString& aData) = 0;
+  virtual void AddAnnotation(const nsAString& aName, const bool aData) = 0;
+
+  class Enumerator
+  {
+  public:
+    virtual ~Enumerator() {}
+    virtual bool Next(nsAString& aOutName, nsAString& aOutValue) = 0;
+  };
+
+  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
+  virtual bool IsEmpty() const = 0;
+  virtual UniquePtr<Enumerator> GetEnumerator() = 0;
+};
+
+typedef UniquePtr<HangAnnotations> HangAnnotationsPtr;
+typedef Vector<HangAnnotationsPtr> HangAnnotationsVector;
+
+class Annotator
+{
+public:
+  /**
+   * NB: This function is always called by the HangMonitor thread.
+   *     Plan accordingly.
+   */
+  virtual void AnnotateHang(HangAnnotations& aAnnotations) = 0;
+};
+
+/**
+ * Registers an Annotator to be called when a hang is detected.
+ * @param aAnnotator Reference to an object that implements the
+ * HangMonitor::Annotator interface.
+ */
+void RegisterAnnotator(Annotator& aAnnotator);
+
+/**
+ * Registers an Annotator that was previously registered via RegisterAnnotator.
+ * @param aAnnotator Reference to an object that implements the
+ * HangMonitor::Annotator interface.
+ */
+void UnregisterAnnotator(Annotator& aAnnotator);
+
+/**
+ * Gathers annotations. This function should be called by ChromeHangs.
+ * @return UniquePtr to HangAnnotations object or nullptr if none.
+ */
+HangAnnotationsPtr ChromeHangAnnotatorCallout();
+
+namespace Observer {
+
+class Annotators
+{
+public:
+  Annotators();
+  ~Annotators();
+
+  bool Register(Annotator& aAnnotator);
+  bool Unregister(Annotator& aAnnotator);
+
+  HangAnnotationsPtr GatherAnnotations();
+
+private:
+  Mutex                mMutex;
+  std::set<Annotator*> mAnnotators;
+};
+
+} // namespace Observer
+
+} // namespace HangMonitor
+} // namespace mozilla
+
+#endif // mozilla_HangAnnotations_h
--- a/xpcom/threads/HangMonitor.cpp
+++ b/xpcom/threads/HangMonitor.cpp
@@ -1,18 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/HangMonitor.h"
 
-#include <set>
-
 #include "mozilla/Atomics.h"
 #include "mozilla/BackgroundHangMonitor.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessedStack.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/UniquePtr.h"
@@ -69,19 +67,16 @@ Atomic<PRIntervalTime> gTimestamp(PR_INT
 // Main thread ID used in reporting chrome hangs under Windows
 static HANDLE winMainThreadHandle = nullptr;
 
 // Default timeout for reporting chrome hangs to Telemetry (5 seconds)
 static const int32_t DEFAULT_CHROME_HANG_INTERVAL = 5;
 
 // Maximum number of PCs to gather from the stack
 static const int32_t MAX_CALL_STACK_PCS = 400;
-
-// Chrome hang annotators
-static StaticAutoPtr<std::set<Annotator*>> gAnnotators;
 #endif
 
 // PrefChangedFunc
 void
 PrefChanged(const char*, void*)
 {
   int32_t newval = Preferences::GetInt(kHangMonitorPrefName);
 #ifdef REPORT_CHROME_HANGS
@@ -117,171 +112,16 @@ Crash()
   CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Hang"),
                                      NS_LITERAL_CSTRING("1"));
 #endif
 
   NS_RUNTIMEABORT("HangMonitor triggered");
 }
 
 #ifdef REPORT_CHROME_HANGS
-class ChromeHangAnnotations : public HangAnnotations
-{
-public:
-  ChromeHangAnnotations();
-  ~ChromeHangAnnotations();
-
-  void AddAnnotation(const nsAString& aName, const int32_t aData) MOZ_OVERRIDE;
-  void AddAnnotation(const nsAString& aName, const double aData) MOZ_OVERRIDE;
-  void AddAnnotation(const nsAString& aName, const nsAString& aData) MOZ_OVERRIDE;
-  void AddAnnotation(const nsAString& aName, const nsACString& aData) MOZ_OVERRIDE;
-  void AddAnnotation(const nsAString& aName, const bool aData) MOZ_OVERRIDE;
-
-  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
-  bool IsEmpty() const MOZ_OVERRIDE;
-  bool GetEnumerator(Enumerator** aOutEnum) MOZ_OVERRIDE;
-
-  typedef std::pair<nsString, nsString> AnnotationType;
-  typedef std::vector<AnnotationType> VectorType;
-  typedef VectorType::const_iterator IteratorType;
-
-private:
-  VectorType  mAnnotations;
-};
-
-ChromeHangAnnotations::ChromeHangAnnotations()
-{
-  MOZ_COUNT_CTOR(ChromeHangAnnotations);
-}
-
-ChromeHangAnnotations::~ChromeHangAnnotations()
-{
-  MOZ_COUNT_DTOR(ChromeHangAnnotations);
-}
-
-void
-ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const int32_t aData)
-{
-  nsString dataString;
-  dataString.AppendInt(aData);
-  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
-  mAnnotations.push_back(annotation);
-}
-
-void
-ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const double aData)
-{
-  nsString dataString;
-  dataString.AppendFloat(aData);
-  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
-  mAnnotations.push_back(annotation);
-}
-
-void
-ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const nsAString& aData)
-{
-  AnnotationType annotation = std::make_pair(nsString(aName), nsString(aData));
-  mAnnotations.push_back(annotation);
-}
-
-void
-ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const nsACString& aData)
-{
-  nsString dataString;
-  AppendUTF8toUTF16(aData, dataString);
-  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
-  mAnnotations.push_back(annotation);
-}
-
-void
-ChromeHangAnnotations::AddAnnotation(const nsAString& aName, const bool aData)
-{
-  nsString dataString;
-  dataString += aData ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false");
-  AnnotationType annotation = std::make_pair(nsString(aName), dataString);
-  mAnnotations.push_back(annotation);
-}
-
-/**
- * This class itself does not use synchronization but it (and its parent object)
- * should be protected by mutual exclusion in some way. In Telemetry the chrome
- * hang data is protected via TelemetryImpl::mHangReportsMutex.
- */
-class ChromeHangAnnotationEnumerator : public HangAnnotations::Enumerator
-{
-public:
-  ChromeHangAnnotationEnumerator(const ChromeHangAnnotations::VectorType& aAnnotations);
-  ~ChromeHangAnnotationEnumerator();
-
-  virtual bool Next(nsAString& aOutName, nsAString& aOutValue);
-
-private:
-  ChromeHangAnnotations::IteratorType mIterator;
-  ChromeHangAnnotations::IteratorType mEnd;
-};
-
-ChromeHangAnnotationEnumerator::ChromeHangAnnotationEnumerator(
-                          const ChromeHangAnnotations::VectorType& aAnnotations)
-  : mIterator(aAnnotations.begin())
-  , mEnd(aAnnotations.end())
-{
-  MOZ_COUNT_CTOR(ChromeHangAnnotationEnumerator);
-}
-
-ChromeHangAnnotationEnumerator::~ChromeHangAnnotationEnumerator()
-{
-  MOZ_COUNT_DTOR(ChromeHangAnnotationEnumerator);
-}
-
-bool
-ChromeHangAnnotationEnumerator::Next(nsAString& aOutName, nsAString& aOutValue)
-{
-  aOutName.Truncate();
-  aOutValue.Truncate();
-  if (mIterator == mEnd) {
-    return false;
-  }
-  aOutName = mIterator->first;
-  aOutValue = mIterator->second;
-  ++mIterator;
-  return true;
-}
-
-bool
-ChromeHangAnnotations::IsEmpty() const
-{
-  return mAnnotations.empty();
-}
-
-size_t
-ChromeHangAnnotations::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
-{
-  size_t result = sizeof(mAnnotations) +
-                  mAnnotations.capacity() * sizeof(AnnotationType);
-  for (IteratorType i = mAnnotations.begin(), e = mAnnotations.end(); i != e;
-       ++i) {
-    result += i->first.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-    result += i->second.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-  }
-
-  return result;
-}
-
-bool
-ChromeHangAnnotations::GetEnumerator(HangAnnotations::Enumerator** aOutEnum)
-{
-  if (!aOutEnum) {
-    return false;
-  }
-  *aOutEnum = nullptr;
-  if (mAnnotations.empty()) {
-    return false;
-  }
-  *aOutEnum = new ChromeHangAnnotationEnumerator(mAnnotations);
-  return true;
-}
 
 static void
 ChromeStackWalker(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
 {
   MOZ_ASSERT(aClosure);
   std::vector<uintptr_t>* stack =
     static_cast<std::vector<uintptr_t>*>(aClosure);
   if (stack->size() == MAX_CALL_STACK_PCS) {
@@ -324,31 +164,16 @@ GetChromeHangReport(Telemetry::Processed
   if (!error) {
     TimeDuration td = TimeStamp::Now() - processCreation;
     aFirefoxUptime = (static_cast<int32_t>(td.ToSeconds()) - (gTimeout * 2)) / 60;
   } else {
     aFirefoxUptime = -1;
   }
 }
 
-static void
-ChromeHangAnnotatorCallout(ChromeHangAnnotations& aAnnotations)
-{
-  gMonitor->AssertCurrentThreadOwns();
-  MOZ_ASSERT(gAnnotators);
-  if (!gAnnotators) {
-    return;
-  }
-  for (std::set<Annotator*>::iterator i = gAnnotators->begin(),
-                                      e = gAnnotators->end();
-       i != e; ++i) {
-    (*i)->AnnotateHang(aAnnotations);
-  }
-}
-
 #endif
 
 void
 ThreadMain(void*)
 {
   PR_SetCurrentThreadName("Hang Monitor");
 
   MonitorAutoLock lock(*gMonitor);
@@ -358,17 +183,17 @@ ThreadMain(void*)
   // run twice to trigger hang protection.
   PRIntervalTime lastTimestamp = 0;
   int waitCount = 0;
 
 #ifdef REPORT_CHROME_HANGS
   Telemetry::ProcessedStack stack;
   int32_t systemUptime = -1;
   int32_t firefoxUptime = -1;
-  auto annotations = MakeUnique<ChromeHangAnnotations>();
+  UniquePtr<HangAnnotations> annotations;
 #endif
 
   while (true) {
     if (gShutdown) {
       return; // Exit the thread
     }
 
     // avoid rereading the volatile value in this loop
@@ -386,17 +211,17 @@ ThreadMain(void*)
         timestamp == lastTimestamp &&
         gTimeout > 0) {
       ++waitCount;
 #ifdef REPORT_CHROME_HANGS
       // Capture the chrome-hang stack + Firefox & system uptimes after
       // the minimum hang duration has been reached (not when the hang ends)
       if (waitCount == 2) {
         GetChromeHangReport(stack, systemUptime, firefoxUptime);
-        ChromeHangAnnotatorCallout(*annotations);
+        annotations = ChromeHangAnnotatorCallout();
       }
 #else
       // This is the crash-on-hang feature.
       // See bug 867313 for the quirk in the waitCount comparison
       if (waitCount >= 2) {
         int32_t delay =
           int32_t(PR_IntervalToSeconds(now - timestamp));
         if (delay >= gTimeout) {
@@ -407,17 +232,16 @@ ThreadMain(void*)
 #endif
     } else {
 #ifdef REPORT_CHROME_HANGS
       if (waitCount >= 2) {
         uint32_t hangDuration = PR_IntervalToSeconds(now - lastTimestamp);
         Telemetry::RecordChromeHang(hangDuration, stack, systemUptime,
                                     firefoxUptime, Move(annotations));
         stack.Clear();
-        annotations = MakeUnique<ChromeHangAnnotations>();
       }
 #endif
       lastTimestamp = timestamp;
       waitCount = 0;
     }
 
     PRIntervalTime timeout;
     if (gTimeout <= 0) {
@@ -447,17 +271,16 @@ Startup()
 
 #ifdef REPORT_CHROME_HANGS
   Preferences::RegisterCallback(PrefChanged, kTelemetryPrefName, nullptr);
   winMainThreadHandle =
     OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
   if (!winMainThreadHandle) {
     return;
   }
-  gAnnotators = new std::set<Annotator*>();
 #endif
 
   // Don't actually start measuring hangs until we hit the main event loop.
   // This potentially misses a small class of really early startup hangs,
   // but avoids dealing with some xpcshell tests and other situations which
   // start XPCOM but don't ever start the event loop.
   Suspend();
 
@@ -486,21 +309,16 @@ Shutdown()
   // thread creation could theoretically fail
   if (gThread) {
     PR_JoinThread(gThread);
     gThread = nullptr;
   }
 
   delete gMonitor;
   gMonitor = nullptr;
-
-#ifdef REPORT_CHROME_HANGS
-  // gAnnotators is a StaticAutoPtr, so we just need to null it out.
-  gAnnotators = nullptr;
-#endif
 }
 
 static bool
 IsUIMessageWaiting()
 {
 #ifndef XP_WIN
   return false;
 #else
@@ -579,36 +397,10 @@ Suspend()
   // Because gTimestamp changes this resets the wait count.
   gTimestamp = PR_INTERVAL_NO_WAIT;
 
   if (gThread && !gShutdown) {
     mozilla::BackgroundHangMonitor().NotifyWait();
   }
 }
 
-void
-RegisterAnnotator(Annotator& aAnnotator)
-{
-#ifdef REPORT_CHROME_HANGS
-  if (GeckoProcessType_Default != XRE_GetProcessType()) {
-    return;
-  }
-  MonitorAutoLock lock(*gMonitor);
-  MOZ_ASSERT(gAnnotators);
-  gAnnotators->insert(&aAnnotator);
-#endif
-}
-
-void
-UnregisterAnnotator(Annotator& aAnnotator)
-{
-#ifdef REPORT_CHROME_HANGS
-  if (GeckoProcessType_Default != XRE_GetProcessType()) {
-    return;
-  }
-  MonitorAutoLock lock(*gMonitor);
-  MOZ_ASSERT(gAnnotators);
-  gAnnotators->erase(&aAnnotator);
-#endif
-}
-
 } // namespace HangMonitor
 } // namespace mozilla
--- a/xpcom/threads/HangMonitor.h
+++ b/xpcom/threads/HangMonitor.h
@@ -2,19 +2,16 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_HangMonitor_h
 #define mozilla_HangMonitor_h
 
-#include "mozilla/MemoryReporting.h"
-#include "nsString.h"
-
 namespace mozilla {
 namespace HangMonitor {
 
 /**
  * Signifies the type of activity in question
 */
 enum ActivityType
 {
@@ -37,67 +34,16 @@ enum ActivityType
 void Startup();
 
 /**
  * Stop monitoring hangs and join the thread.
  */
 void Shutdown();
 
 /**
- * This class declares an abstraction for a data type that encapsulates all
- * of the annotations being reported by a registered hang Annotator.
- */
-class HangAnnotations
-{
-public:
-  virtual ~HangAnnotations() {}
-
-  virtual void AddAnnotation(const nsAString& aName, const int32_t aData) = 0;
-  virtual void AddAnnotation(const nsAString& aName, const double aData) = 0;
-  virtual void AddAnnotation(const nsAString& aName, const nsAString& aData) = 0;
-  virtual void AddAnnotation(const nsAString& aName, const nsACString& aData) = 0;
-  virtual void AddAnnotation(const nsAString& aName, const bool aData) = 0;
-
-  class Enumerator
-  {
-  public:
-    virtual ~Enumerator() {}
-    virtual bool Next(nsAString& aOutName, nsAString& aOutValue) = 0;
-  };
-
-  virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const = 0;
-  virtual bool IsEmpty() const = 0;
-  virtual bool GetEnumerator(Enumerator **aOutEnum) = 0;
-};
-
-class Annotator
-{
-public:
-  /**
-   * NB: This function is always called by the HangMonitor thread.
-   *     Plan accordingly.
-   */
-  virtual void AnnotateHang(HangAnnotations& aAnnotations) = 0;
-};
-
-/**
- * Registers an Annotator to be called when a hang is detected.
- * @param aAnnotator Reference to an object that implements the
- * HangMonitor::Annotator interface.
- */
-void RegisterAnnotator(Annotator& aAnnotator);
-
-/**
- * Registers an Annotator that was previously registered via RegisterAnnotator.
- * @param aAnnotator Reference to an object that implements the
- * HangMonitor::Annotator interface.
- */
-void UnregisterAnnotator(Annotator& aAnnotator);
-
-/**
  * Notify the hang monitor of activity which will reset its internal timer.
  *
  * @param activityType The type of activity being reported.
  * @see ActivityType
  */
 void NotifyActivity(ActivityType activityType = kGeneralActivity);
 
 /*
--- a/xpcom/threads/moz.build
+++ b/xpcom/threads/moz.build
@@ -24,23 +24,25 @@ EXPORTS += [
     'nsEventQueue.h',
     'nsMemoryPressure.h',
     'nsProcess.h',
     'nsThread.h',
 ]
 
 EXPORTS.mozilla += [
     'BackgroundHangMonitor.h',
+    'HangAnnotations.h',
     'HangMonitor.h',
     'LazyIdleThread.h',
     'SyncRunnable.h',
 ]
 
 UNIFIED_SOURCES += [
     'BackgroundHangMonitor.cpp',
+    'HangAnnotations.cpp',
     'HangMonitor.cpp',
     'LazyIdleThread.cpp',
     'nsEnvironment.cpp',
     'nsEventQueue.cpp',
     'nsMemoryPressure.cpp',
     'nsProcessCommon.cpp',
     'nsThread.cpp',
     'nsThreadManager.cpp',