Bug 1441754 - Shrink CallbackNode by combining mMatchKind and mNext into a tagged pointer. r=glandium
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 28 Feb 2018 16:21:42 +1100
changeset 461544 e6680fcb17a0392208b7413a214a662f8b8ca284
parent 461543 13e0252c67c9caeb7fa73ae5b2e16080c84cb728
child 461545 76a740cc4454f92c44b10e63abcc3d68daf8ee06
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1441754
milestone60.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 1441754 - Shrink CallbackNode by combining mMatchKind and mNext into a tagged pointer. r=glandium The following table shows the effect of this change: > old 64-bit new 64-bit old 32-bit new 32-bit > sizeof(CallbackNode) 40 32 20 16 > size when heap allocated 48 32 32 16 This reduces memory usage by about 15--40 KB per process. MozReview-Commit-ID: 4gXgGI3SiJz
modules/libpref/Preferences.cpp
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -751,51 +751,71 @@ class CallbackNode
 public:
   CallbackNode(const char* aDomain,
                PrefChangedFunc aFunc,
                void* aData,
                Preferences::MatchKind aMatchKind)
     : mDomain(moz_xstrdup(aDomain))
     , mFunc(aFunc)
     , mData(aData)
-    , mMatchKind(aMatchKind)
-    , mNext(nullptr)
+    , mNextAndMatchKind(aMatchKind)
   {
   }
 
   // mDomain is a UniquePtr<>, so any uses of Domain() should only be temporary
   // borrows.
   const char* Domain() const { return mDomain.get(); }
 
   PrefChangedFunc Func() const { return mFunc; }
   void ClearFunc() { mFunc = nullptr; }
 
   void* Data() const { return mData; }
 
-  Preferences::MatchKind MatchKind() const { return mMatchKind; }
-
-  CallbackNode* Next() const { return mNext; }
-  void SetNext(CallbackNode* aNext) { mNext = aNext; }
+  Preferences::MatchKind MatchKind() const
+  {
+    return static_cast<Preferences::MatchKind>(mNextAndMatchKind &
+                                               kMatchKindMask);
+  }
+
+  CallbackNode* Next() const
+  {
+    return reinterpret_cast<CallbackNode*>(mNextAndMatchKind & kNextMask);
+  }
+
+  void SetNext(CallbackNode* aNext)
+  {
+    uintptr_t matchKind = mNextAndMatchKind & kMatchKindMask;
+    mNextAndMatchKind = reinterpret_cast<uintptr_t>(aNext);
+    MOZ_ASSERT((mNextAndMatchKind & kMatchKindMask) == 0);
+    mNextAndMatchKind |= matchKind;
+  }
 
   void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes)
   {
     aSizes.mCallbacksObjects += aMallocSizeOf(this);
     aSizes.mCallbacksDomains += aMallocSizeOf(mDomain.get());
   }
 
 private:
+  static const uintptr_t kMatchKindMask = uintptr_t(0x1);
+  static const uintptr_t kNextMask = ~kMatchKindMask;
+
   UniqueFreePtr<const char> mDomain;
 
   // If someone attempts to remove the node from the callback list while
   // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will
   // be removed at the end of NotifyCallbacks().
   PrefChangedFunc mFunc;
   void* mData;
-  Preferences::MatchKind mMatchKind;
-  CallbackNode* mNext;
+
+  // Conceptually this is two fields:
+  // - CallbackNode* mNext;
+  // - Preferences::MatchKind mMatchKind;
+  // They are combined into a tagged pointer to save memory.
+  uintptr_t mNextAndMatchKind;
 };
 
 static PLDHashTable* gHashTable;
 
 // The callback list contains all the priority callbacks followed by the
 // non-priority callbacks. gLastPriorityNode records where the first part ends.
 static CallbackNode* gFirstCallback = nullptr;
 static CallbackNode* gLastPriorityNode = nullptr;