Bug 1393384 (attempt 2) - Take advantage of new support for measuring heap blocks via interior pointers. r=erahm.

We now have jemalloc_ptr_info() and moz_malloc_enclosing_size_of(), which can
be used to measure heap blocks via interior pointers. This patch does the
following.

- Adds MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF, for defining
  measure-via-interior-pointer functions.

- Uses these functions to replace some horrid pointer arithmetic in functions
  measuring Rust types.

--HG--
extra : rebase_source : 5128408256c128222025153ae3e0f924b2499a2a
This commit is contained in:
Nicholas Nethercote 2017-09-01 17:25:52 +10:00
parent 71d6942bcb
commit 78adeaf317
3 changed files with 40 additions and 37 deletions

View File

@ -29,6 +29,7 @@
#include "nsIDocumentInlines.h"
#include "nsILoadContext.h"
#include "nsIFrame.h"
#include "nsIMemoryReporter.h"
#include "nsINode.h"
#include "nsIPresShell.h"
#include "nsIPresShellInlines.h"
@ -226,38 +227,23 @@ ServoComputedData::GetStyleVariables() const
"called");
}
MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleStructsMallocSizeOf)
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoStyleStructsMallocEnclosingSizeOf)
void
ServoComputedData::AddSizeOfExcludingThis(nsWindowSizes& aSizes) const
{
// XXX WARNING: GetStyleFoo() returns an nsStyleFoo pointer. This nsStyleFoo
// sits within a servo_arc::Arc, i.e. it is preceded by a word-sized
// refcount. So this pointer is an interior pointer. To get the start address
// of the heap block we move the pointer back by one word. For this to work,
// two things must be true.
//
// - The layout of servo_arc::Arc must stay the same.
//
// - The alignment of each nsStyleFoo must not be greater than the size of a
// word (otherwise padding might be inserted between the refcount and the
// struct in the servo_arc::Arc).
//
// In the long run a better solution here is for mozjemalloc to provide a
// function that converts an interior pointer to a start pointer (bug
// 1389305), but that's not available right now.
//
// Also, we use ServoStyleStructsMallocSizeOf rather than
// |aSizes.mState.mMallocSizeOf| to better distinguish in DMD's output the
// memory measured here.
// Note: GetStyleFoo() returns a pointer to an nsStyleFoo that sits within a
// servo_arc::Arc, i.e. it is preceded by a word-sized refcount. So we need
// to measure it with a function that can handle an interior pointer. We use
// ServoStyleStructsEnclosingMallocSizeOf to clearly identify in DMD's
// output the memory measured here.
#define STYLE_STRUCT(name_, cb_) \
static_assert(alignof(nsStyle##name_) <= sizeof(size_t), \
"alignment will break AddSizeOfExcludingThis()"); \
const char* p##name_ = reinterpret_cast<const char*>(GetStyle##name_()); \
p##name_ -= sizeof(size_t); \
const void* p##name_ = GetStyle##name_(); \
if (!aSizes.mState.HaveSeenPtr(p##name_)) { \
aSizes.mServoStyleSizes.NS_STYLE_SIZES_FIELD(name_) += \
ServoStyleStructsMallocSizeOf(p##name_); \
ServoStyleStructsMallocEnclosingSizeOf(p##name_); \
}
#define STYLE_STRUCT_LIST_IGNORE_VARIABLES
#include "nsStyleStructList.h"

View File

@ -18,7 +18,7 @@ namespace dom {
class Element;
} // namespace dom
MOZ_DEFINE_MALLOC_SIZE_OF(ServoComputedValuesMallocSizeOf)
MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(ServoComputedValuesMallocEnclosingSizeOf)
class ServoStyleContext final : public nsStyleContext
{
@ -105,19 +105,11 @@ public:
// the size should be added to.
void AddSizeOfIncludingThis(nsWindowSizes& aSizes, size_t* aCVsSize) const
{
// XXX WARNING: similar to ServoComputedData::AddSizeOfExcludingThis(),
// but here we need to step back 4 or 8 bytes to get past the servo_arc::Arc
// refcount to the base pointer.
static_assert(alignof(ServoStyleContext) == 4 ||
alignof(ServoStyleContext) == 8,
"alignment will break AddSizeOfExcludingThis()");
const char* p = reinterpret_cast<const char*>(this);
p -= std::max(sizeof(size_t), alignof(ServoStyleContext));
// We use ServoComputedValuesMallocSizeOf rather than
// |aState.mMallocSizeOf| to better distinguish in DMD's output the memory
// measured here.
*aCVsSize += ServoComputedValuesMallocSizeOf(p);
// Note: |this| sits within a servo_arc::Arc, i.e. it is preceded by a
// refcount. So we need to measure it with a function that can handle an
// interior pointer. We use ServoComputedValuesMallocEnclosingSizeOf to
// clearly identify in DMD's output the memory measured here.
*aCVsSize += ServoComputedValuesMallocEnclosingSizeOf(this);
mSource.AddSizeOfExcludingThis(aSizes);
}

View File

@ -565,6 +565,31 @@ nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn);
return moz_malloc_size_of(aPtr); \
}
// This is an alternative to MOZ_DEFINE_MALLOC_SIZE_OF that defines a
// MallocSizeOf function that can handle interior pointers.
#ifdef MOZ_MEMORY
#include "mozmemory.h"
#define MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(fn) \
static size_t fn(const void* aPtr) \
{ \
jemalloc_ptr_info_t info; \
jemalloc_ptr_info(aPtr, &info); \
MOZ_REPORT(info.addr); \
return jemalloc_ptr_is_live(&info) ? info.size : 0; \
}
#else
#define MOZ_DEFINE_MALLOC_ENCLOSING_SIZE_OF(fn) \
static size_t fn(const void* aPtr) \
{ \
return 0; \
}
#endif
// Functions generated by the next two macros should be used by wrapping
// allocators that report heap blocks as soon as they are allocated and
// unreport them as soon as they are freed. Such allocators are used in cases