Bug 820652 (part 6) - DMD: Don't use LiveBlockKey in LiveBlock. r=jlebar.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 12 Dec 2012 21:40:01 -0800
changeset 115989 9f305729255b0b2df0ca04e03d1774b7f2724a64
parent 115988 5ac16858d004081963395e018ef4d4c1423429f1
child 115990 8c77de31ddc4e93faed739de65073c5ff96f6bf8
push id19664
push usernnethercote@mozilla.com
push dateThu, 13 Dec 2012 23:31:59 +0000
treeherdermozilla-inbound@8c77de31ddc4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlebar
bugs820652
milestone20.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 820652 (part 6) - DMD: Don't use LiveBlockKey in LiveBlock. r=jlebar.
memory/replace/dmd/DMD.cpp
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -644,175 +644,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;
@@ -820,16 +715,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.
 
@@ -1046,16 +951,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?
@@ -1826,17 +1853,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();
   }