Bug 820652 (part 6) - DMD: Don't use LiveBlockKey in LiveBlock. r+a=jlebar
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 12 Dec 2012 21:40:01 -0800
changeset 118910 dfe6d957629116beb1a6f6ba0c14ecfbf80848f0
parent 118909 935851593ad461e22706b7b0350cfb6a6e9e806b
child 118911 070bb9a35fa97d5c72dd0e57bf1a847e0e18333d
push id2984
push userryanvm@gmail.com
push dateTue, 18 Dec 2012 03:08:28 +0000
treeherdermozilla-aurora@68ae24dc739c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs820652
milestone19.0a2
Bug 820652 (part 6) - DMD: Don't use LiveBlockKey in LiveBlock. r+a=jlebar
memory/replace/dmd/DMD.cpp
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -609,175 +609,70 @@ StackTrace::Get(Thread* aT)
 }
 
 //---------------------------------------------------------------------------
 // Heap blocks
 //---------------------------------------------------------------------------
 
 static const char* gUnreportedName = "unreported";
 
-// This is used by both LiveBlocks and LiveBlockGroups.
-class LiveBlockKey
-{
-public:
-  const StackTrace* const mAllocStackTrace;     // never null
-
-protected:
-  // Live blocks can be reported in two ways.
-  // - The most common is via a memory reporter traversal -- the block is
-  //   reported when the reporter runs, causing DMD to mark it as reported,
-  //   and DMD must clear the marking once it has finished its analysis.
-  // - Less common are ones that are reported immediately on allocation.  DMD
-  //   must *not* clear the markings of these blocks once it has finished its
-  //   analysis.  The |mReportedOnAlloc| field is set for such blocks.
-  //
-  // These fields are used as the value in LiveBlock, so it's ok for them to be
-  // |mutable|.
-  mutable const StackTrace* mReportStackTrace;  // nullptr if unreported
-  mutable const char*       mReporterName;      // gUnreportedName if unreported
-  mutable bool              mReportedOnAlloc;   // true if block was reported
-
-public:
-  LiveBlockKey(const StackTrace* aAllocStackTrace)
-    : mAllocStackTrace(aAllocStackTrace),
-      mReportStackTrace(nullptr),
-      mReporterName(gUnreportedName),
-      mReportedOnAlloc(false)
-  {
-    MOZ_ASSERT(IsSane());
-  }
-
-  bool IsSane() const
-  {
-    bool hasReporterName = mReporterName != gUnreportedName;
-    return mAllocStackTrace &&
-           (( mReportStackTrace &&  hasReporterName) ||
-            (!mReportStackTrace && !hasReporterName && !mReportedOnAlloc));
-  }
-
-  bool IsReported() const
-  {
-    MOZ_ASSERT(IsSane());
-    bool isRep = mReporterName != gUnreportedName;
-    return isRep;
-  }
-
-  // Hash policy.
-  //
-  // hash() and match() both assume that identical reporter names have
-  // identical pointers.  In practice this always happens because they are
-  // static strings (as specified in the NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN
-  // macro).  This is true even for multi-reporters.  (If it ever became
-  // untrue, the worst that would happen is that some blocks that should be in
-  // the same block group would end up in separate block groups.)
-
-  typedef LiveBlockKey Lookup;
-
-  static uint32_t hash(const LiveBlockKey& aKey)
-  {
-    return mozilla::HashGeneric(aKey.mAllocStackTrace,
-                                aKey.mReportStackTrace,
-                                aKey.mReporterName);
-  }
-
-  static bool match(const LiveBlockKey& aA, const LiveBlockKey& aB)
-  {
-    return aA.mAllocStackTrace  == aB.mAllocStackTrace &&
-           aA.mReportStackTrace == aB.mReportStackTrace &&
-           aA.mReporterName     == aB.mReporterName;
-  }
-};
-
-// This is used by DoubleReportBlockGroups.
-class DoubleReportBlockKey
-{
-public:
-  const StackTrace* const mAllocStackTrace;     // never null
-
-protected:
-  // When double-reports occur we record (and later print) the stack trace
-  // and reporter name of *both* the reporting locations.
-  const StackTrace* const mReportStackTrace1;   // never null
-  const StackTrace* const mReportStackTrace2;   // never null
-  const char*       const mReporterName1;       // never gUnreportedName
-  const char*       const mReporterName2;       // never gUnreportedName
-
-public:
-  DoubleReportBlockKey(const StackTrace* aAllocStackTrace,
-                       const StackTrace* aReportStackTrace1,
-                       const StackTrace* aReportStackTrace2,
-                       const char* aReporterName1,
-                       const char* aReporterName2)
-    : mAllocStackTrace(aAllocStackTrace),
-      mReportStackTrace1(aReportStackTrace1),
-      mReportStackTrace2(aReportStackTrace2),
-      mReporterName1(aReporterName1),
-      mReporterName2(aReporterName2)
-  {
-    MOZ_ASSERT(IsSane());
-  }
-
-  bool IsSane() const
-  {
-    return mAllocStackTrace &&
-           mReportStackTrace1 &&
-           mReportStackTrace2 &&
-           mReporterName1 != gUnreportedName &&
-           mReporterName2 != gUnreportedName;
-  }
-
-  // Hash policy.
-  //
-  // hash() and match() both assume that identical reporter names have
-  // identical pointers.  See LiveBlockKey for more.
-
-  typedef DoubleReportBlockKey Lookup;
-
-  static uint32_t hash(const DoubleReportBlockKey& aKey)
-  {
-    return mozilla::HashGeneric(aKey.mAllocStackTrace,
-                                aKey.mReportStackTrace1,
-                                aKey.mReportStackTrace2,
-                                aKey.mReporterName1,
-                                aKey.mReporterName2);
-  }
-
-  static bool match(const DoubleReportBlockKey& aA,
-                    const DoubleReportBlockKey& aB)
-  {
-    return aA.mAllocStackTrace   == aB.mAllocStackTrace &&
-           aA.mReportStackTrace1 == aB.mReportStackTrace1 &&
-           aA.mReportStackTrace2 == aB.mReportStackTrace2 &&
-           aA.mReporterName1     == aB.mReporterName1 &&
-           aA.mReporterName2     == aB.mReporterName2;
-  }
-};
-
 // A live heap block.
-class LiveBlock : public LiveBlockKey
+class LiveBlock
 {
   const void*  mPtr;
 
   // This assumes that we'll never request an allocation of 2 GiB or more on
   // 32-bit platforms.
   static const size_t kReqBits = sizeof(size_t) * 8 - 1;    // 31 or 63
   const size_t mReqSize:kReqBits; // size requested
   const size_t mSampled:1;        // was this block sampled? (if so, slop == 0)
 
 public:
+  const StackTrace* const mAllocStackTrace;     // never null
+
+  // Live blocks can be reported in two ways.
+  // - The most common is via a memory reporter traversal -- the block is
+  //   reported when the reporter runs, causing DMD to mark it as reported,
+  //   and DMD must clear the marking once it has finished its analysis.
+  // - Less common are ones that are reported immediately on allocation.  DMD
+  //   must *not* clear the markings of these blocks once it has finished its
+  //   analysis.  The |mReportedOnAlloc| field is set for such blocks.
+  //
+  // |mPtr| is used as the key in LiveBlockTable, so it's ok for these fields
+  // to be |mutable|.
+private:
+  mutable const StackTrace* mReportStackTrace;  // nullptr if unreported
+  mutable const char*       mReporterName;      // gUnreportedName if unreported
+  mutable bool              mReportedOnAlloc;   // true if block was reported
+                                                //   immediately after alloc
+
+public:
   LiveBlock(const void* aPtr, size_t aReqSize,
             const StackTrace* aAllocStackTrace, bool aSampled)
-    : LiveBlockKey(aAllocStackTrace),
-      mPtr(aPtr),
+    : mPtr(aPtr),
       mReqSize(aReqSize),
-      mSampled(aSampled)
-  {
-    if (mReqSize != aReqSize) {
+      mSampled(aSampled),
+      mAllocStackTrace(aAllocStackTrace),
+      mReportStackTrace(nullptr),
+      mReporterName(gUnreportedName),
+      mReportedOnAlloc(false)
+ {
+    if (mReqSize != aReqSize)
+    {
       MOZ_CRASH();              // overflowed mReqSize
     }
+    MOZ_ASSERT(IsSane());
+  }
+
+  bool IsSane() const
+  {
+    bool hasReporterName = mReporterName != gUnreportedName;
+    return mAllocStackTrace &&
+           (( mReportStackTrace &&  hasReporterName) ||
+            (!mReportStackTrace && !hasReporterName && !mReportedOnAlloc));
   }
 
   size_t ReqSize() const { return mReqSize; }
 
   // Sampled blocks always have zero slop.
   size_t SlopSize() const
   {
     return mSampled ? 0 : MallocSizeOf(mPtr) - mReqSize;
@@ -785,16 +680,26 @@ public:
 
   size_t UsableSize() const
   {
     return mSampled ? mReqSize : MallocSizeOf(mPtr);
   }
 
   bool IsSampled() const { return mSampled; }
 
+  bool IsReported() const
+  {
+    MOZ_ASSERT(IsSane());
+    bool isRep = mReporterName != gUnreportedName;
+    return isRep;
+  }
+
+  const StackTrace* ReportStackTrace() const { return mReportStackTrace; }
+  const char* ReporterName() const { return mReporterName; }
+
   // This is |const| thanks to the |mutable| fields above.
   void Report(Thread* aT, const char* aReporterName, bool aReportedOnAlloc)
        const;
 
   void UnreportIfNotReportedOnAlloc() const;
 
   // Hash policy.
 
@@ -1011,16 +916,138 @@ replace_free(void* aPtr)
 
 namespace mozilla {
 namespace dmd {
 
 //---------------------------------------------------------------------------
 // Live and double-report block groups
 //---------------------------------------------------------------------------
 
+class LiveBlockKey
+{
+public:
+  const StackTrace* const mAllocStackTrace;   // never null
+protected:
+  const StackTrace* const mReportStackTrace;  // nullptr if unreported
+  const char*       const mReporterName;      // gUnreportedName if unreported
+
+public:
+  LiveBlockKey(const LiveBlock& aB)
+    : mAllocStackTrace(aB.mAllocStackTrace),
+      mReportStackTrace(aB.ReportStackTrace()),
+      mReporterName(aB.ReporterName())
+  {
+    MOZ_ASSERT(IsSane());
+  }
+
+  bool IsSane() const
+  {
+    bool hasReporterName = mReporterName != gUnreportedName;
+    return mAllocStackTrace &&
+           (( mReportStackTrace &&  hasReporterName) ||
+            (!mReportStackTrace && !hasReporterName));
+  }
+
+  bool IsReported() const
+  {
+    MOZ_ASSERT(IsSane());
+    bool isRep = mReporterName != gUnreportedName;
+    return isRep;
+  }
+
+  // Hash policy.
+  //
+  // hash() and match() both assume that identical reporter names have
+  // identical pointers.  In practice this always happens because they are
+  // static strings (as specified in the NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN
+  // macro).  This is true even for multi-reporters.  (If it ever became
+  // untrue, the worst that would happen is that some blocks that should be in
+  // the same block group would end up in separate block groups.)
+
+  typedef LiveBlockKey Lookup;
+
+  static uint32_t hash(const LiveBlockKey& aKey)
+  {
+    return mozilla::HashGeneric(aKey.mAllocStackTrace,
+                                aKey.mReportStackTrace,
+                                aKey.mReporterName);
+  }
+
+  static bool match(const LiveBlockKey& aA, const LiveBlockKey& aB)
+  {
+    return aA.mAllocStackTrace  == aB.mAllocStackTrace &&
+           aA.mReportStackTrace == aB.mReportStackTrace &&
+           aA.mReporterName     == aB.mReporterName;
+  }
+};
+
+class DoubleReportBlockKey
+{
+public:
+  const StackTrace* const mAllocStackTrace;     // never null
+
+protected:
+  // When double-reports occur we record (and later print) the stack trace
+  // and reporter name of *both* the reporting locations.
+  const StackTrace* const mReportStackTrace1;   // never null
+  const StackTrace* const mReportStackTrace2;   // never null
+  const char*       const mReporterName1;       // never gUnreportedName
+  const char*       const mReporterName2;       // never gUnreportedName
+
+public:
+  DoubleReportBlockKey(const StackTrace* aAllocStackTrace,
+                       const StackTrace* aReportStackTrace1,
+                       const StackTrace* aReportStackTrace2,
+                       const char* aReporterName1,
+                       const char* aReporterName2)
+    : mAllocStackTrace(aAllocStackTrace),
+      mReportStackTrace1(aReportStackTrace1),
+      mReportStackTrace2(aReportStackTrace2),
+      mReporterName1(aReporterName1),
+      mReporterName2(aReporterName2)
+  {
+    MOZ_ASSERT(IsSane());
+  }
+
+  bool IsSane() const
+  {
+    return mAllocStackTrace &&
+           mReportStackTrace1 &&
+           mReportStackTrace2 &&
+           mReporterName1 != gUnreportedName &&
+           mReporterName2 != gUnreportedName;
+  }
+
+  // Hash policy.
+  //
+  // hash() and match() both assume that identical reporter names have
+  // identical pointers.  See LiveBlockKey for more.
+
+  typedef DoubleReportBlockKey Lookup;
+
+  static uint32_t hash(const DoubleReportBlockKey& aKey)
+  {
+    return mozilla::HashGeneric(aKey.mAllocStackTrace,
+                                aKey.mReportStackTrace1,
+                                aKey.mReportStackTrace2,
+                                aKey.mReporterName1,
+                                aKey.mReporterName2);
+  }
+
+  static bool match(const DoubleReportBlockKey& aA,
+                    const DoubleReportBlockKey& aB)
+  {
+    return aA.mAllocStackTrace   == aB.mAllocStackTrace &&
+           aA.mReportStackTrace1 == aB.mReportStackTrace1 &&
+           aA.mReportStackTrace2 == aB.mReportStackTrace2 &&
+           aA.mReporterName1     == aB.mReporterName1 &&
+           aA.mReporterName2     == aB.mReporterName2;
+  }
+};
+
 class GroupSize
 {
   static const size_t kReqBits = sizeof(size_t) * 8 - 1;  // 31 or 63
 
   size_t mReq;              // size requested
   size_t mSlop:kReqBits;    // slop bytes
   size_t mSampled:1;        // were one or more blocks contributing to this
                             //   GroupSize sampled?
@@ -1791,17 +1818,18 @@ Dump(Writer aWriter)
     const LiveBlock& b = r.front();
 
     size_t& size = !b.IsReported() ? unreportedUsableSize : reportedUsableSize;
     size += b.UsableSize();
 
     LiveBlockGroupTable& table = !b.IsReported()
                                ? unreportedLiveBlockGroupTable
                                : reportedLiveBlockGroupTable;
-    LiveBlockGroupTable::AddPtr p = table.lookupForAdd(b);
+    LiveBlockKey liveKey(b);
+    LiveBlockGroupTable::AddPtr p = table.lookupForAdd(liveKey);
     if (!p) {
       LiveBlockGroup bg(b);
       (void)table.add(p, bg);
     }
     p->Add(b);
 
     anyBlocksSampled = anyBlocksSampled || b.IsSampled();
   }