Bumping manifests a=b2g-bump
[gecko.git] / xpcom / base / CountingAllocatorBase.h
blob9002cfc5fff187a27322d2e0d8da324e7488d52b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef CountingAllocatorBase_h
8 #define CountingAllocatorBase_h
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Atomics.h"
12 #include "nsIMemoryReporter.h"
14 namespace mozilla {
16 // This CRTP class handles several details of wrapping allocators and should
17 // be preferred to manually counting with MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC
18 // and MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE. The typical use is in a memory
19 // reporter for a particular third party library:
21 // class MyMemoryReporter : public CountingAllocatorBase<MyMemoryReporter>
22 // {
23 // ...
24 // NS_IMETHODIMP
25 // CollectReports(nsIHandleReportCallback* aHandleReport,
26 // nsISupports* aData, bool aAnonymize)
27 // {
28 // return MOZ_COLLECT_REPORT(
29 // "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES,
30 // MemoryAllocated(),
31 // "A description of what we are reporting."
32 // }
33 // };
35 // ...somewhere later in the code...
36 // SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc,
37 // MyMemoryReporter::CountingFree);
38 template<typename T>
39 class CountingAllocatorBase
41 public:
42 CountingAllocatorBase()
44 #ifdef DEBUG
45 // There must be only one instance of this class, due to |sAmount| being
46 // static.
47 static bool hasRun = false;
48 MOZ_ASSERT(!hasRun);
49 hasRun = true;
50 #endif
53 static size_t
54 MemoryAllocated()
56 return sAmount;
59 static void*
60 CountingMalloc(size_t size)
62 void* p = malloc(size);
63 sAmount += MallocSizeOfOnAlloc(p);
64 return p;
67 static void*
68 CountingCalloc(size_t nmemb, size_t size)
70 void* p = calloc(nmemb, size);
71 sAmount += MallocSizeOfOnAlloc(p);
72 return p;
75 static void*
76 CountingRealloc(void* p, size_t size)
78 size_t oldsize = MallocSizeOfOnFree(p);
79 void *pnew = realloc(p, size);
80 if (pnew) {
81 size_t newsize = MallocSizeOfOnAlloc(pnew);
82 sAmount += newsize - oldsize;
83 } else if (size == 0) {
84 // We asked for a 0-sized (re)allocation of some existing pointer
85 // and received NULL in return. 0-sized allocations are permitted
86 // to either return NULL or to allocate a unique object per call (!).
87 // For a malloc implementation that chooses the second strategy,
88 // that allocation may fail (unlikely, but possible).
90 // Given a NULL return value and an allocation size of 0, then, we
91 // don't know if that means the original pointer was freed or if
92 // the allocation of the unique object failed. If the original
93 // pointer was freed, then we have nothing to do here. If the
94 // allocation of the unique object failed, the original pointer is
95 // still valid and we ought to undo the decrement from above.
96 // However, we have no way of knowing how the underlying realloc
97 // implementation is behaving. Assuming that the original pointer
98 // was freed is the safest course of action. We do, however, need
99 // to note that we freed memory.
100 sAmount -= oldsize;
101 } else {
102 // realloc failed. The amount allocated hasn't changed.
104 return pnew;
107 // Some library code expects that realloc(x, 0) will free x, which is not
108 // the behavior of the version of jemalloc we're using, so this wrapped
109 // version of realloc is needed.
110 static void*
111 CountingFreeingRealloc(void* p, size_t size)
113 if (size == 0) {
114 CountingFree(p);
115 return nullptr;
117 return CountingRealloc(p, size);
120 static void
121 CountingFree(void* p)
123 sAmount -= MallocSizeOfOnFree(p);
124 free(p);
127 private:
128 // |sAmount| can be (implicitly) accessed by multiple threads, so it
129 // must be thread-safe.
130 static Atomic<size_t> sAmount;
132 MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
133 MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
136 } // namespace mozilla
138 #endif // CountingAllocatorBase_h