Bug 1052579 - Add ability to query ArenaID to mozjemalloc_ptr_info r=glandium
authorChris Martin <cmartin@mozilla.com>
Tue, 23 Apr 2019 12:39:58 +0000
changeset 470492 401f2be1ced14464292c27ac0a563650ecd3f8c0
parent 470491 512231282d5f08fbf997840fc66c968a9ebaac75
child 470493 17c6c03c439e2e4b99dbe53414a4c96c56741528
push id83773
push userrvandermeulen@mozilla.com
push dateTue, 23 Apr 2019 12:43:20 +0000
treeherderautoland@401f2be1ced1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1052579
milestone68.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 1052579 - Add ability to query ArenaID to mozjemalloc_ptr_info r=glandium To ensure that any new JSString has its char buffer allocated in the new arena, it is useful to be able to query a pointer and assert that it is in the correct arena (at-least in Debug Build). This adds the required functionality to mozjemalloc, and JSString can use it for its new assertion in a later change. Differential Revision: https://phabricator.services.mozilla.com/D25711
memory/build/mozjemalloc.cpp
memory/build/mozjemalloc_types.h
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -3049,51 +3049,51 @@ template <>
 inline void MozJemalloc::jemalloc_ptr_info(const void* aPtr,
                                            jemalloc_ptr_info_t* aInfo) {
   arena_chunk_t* chunk = GetChunkForPtr(aPtr);
 
   // Is the pointer null, or within one chunk's size of null?
   // Alternatively, if the allocator is not initialized yet, the pointer
   // can't be known.
   if (!chunk || !malloc_initialized) {
-    *aInfo = {TagUnknown, nullptr, 0};
+    *aInfo = {TagUnknown, nullptr, 0, 0};
     return;
   }
 
   // Look for huge allocations before looking for |chunk| in gChunkRTree.
   // This is necessary because |chunk| won't be in gChunkRTree if it's
   // the second or subsequent chunk in a huge allocation.
   extent_node_t* node;
   extent_node_t key;
   {
     MutexAutoLock lock(huge_mtx);
     key.mAddr = const_cast<void*>(aPtr);
     node =
         reinterpret_cast<RedBlackTree<extent_node_t, ExtentTreeBoundsTrait>*>(
             &huge)
             ->Search(&key);
     if (node) {
-      *aInfo = {TagLiveHuge, node->mAddr, node->mSize};
+      *aInfo = {TagLiveHuge, node->mAddr, node->mSize, node->mArena->mId};
       return;
     }
   }
 
   // It's not a huge allocation. Check if we have a known chunk.
   if (!gChunkRTree.Get(chunk)) {
-    *aInfo = {TagUnknown, nullptr, 0};
+    *aInfo = {TagUnknown, nullptr, 0, 0};
     return;
   }
 
   MOZ_DIAGNOSTIC_ASSERT(chunk->arena->mMagic == ARENA_MAGIC);
 
   // Get the page number within the chunk.
   size_t pageind = (((uintptr_t)aPtr - (uintptr_t)chunk) >> gPageSize2Pow);
   if (pageind < gChunkHeaderNumPages) {
     // Within the chunk header.
-    *aInfo = {TagUnknown, nullptr, 0};
+    *aInfo = {TagUnknown, nullptr, 0, 0};
     return;
   }
 
   size_t mapbits = chunk->map[pageind].bits;
 
   if (!(mapbits & CHUNK_MAP_ALLOCATED)) {
     PtrInfoTag tag = TagFreedPageDirty;
     if (mapbits & CHUNK_MAP_DIRTY) {
@@ -3104,17 +3104,17 @@ inline void MozJemalloc::jemalloc_ptr_in
       tag = TagFreedPageMadvised;
     } else if (mapbits & CHUNK_MAP_ZEROED) {
       tag = TagFreedPageZeroed;
     } else {
       MOZ_CRASH();
     }
 
     void* pageaddr = (void*)(uintptr_t(aPtr) & ~gPageSizeMask);
-    *aInfo = {tag, pageaddr, gPageSize};
+    *aInfo = {tag, pageaddr, gPageSize, chunk->arena->mId};
     return;
   }
 
   if (mapbits & CHUNK_MAP_LARGE) {
     // It's a large allocation. Only the first page of a large
     // allocation contains its size, so if the address is not in
     // the first page, scan back to find the allocation size.
     size_t size;
@@ -3124,61 +3124,61 @@ inline void MozJemalloc::jemalloc_ptr_in
         break;
       }
 
       // The following two return paths shouldn't occur in
       // practice unless there is heap corruption.
       pageind--;
       MOZ_DIAGNOSTIC_ASSERT(pageind >= gChunkHeaderNumPages);
       if (pageind < gChunkHeaderNumPages) {
-        *aInfo = {TagUnknown, nullptr, 0};
+        *aInfo = {TagUnknown, nullptr, 0, 0};
         return;
       }
 
       mapbits = chunk->map[pageind].bits;
       MOZ_DIAGNOSTIC_ASSERT(mapbits & CHUNK_MAP_LARGE);
       if (!(mapbits & CHUNK_MAP_LARGE)) {
-        *aInfo = {TagUnknown, nullptr, 0};
+        *aInfo = {TagUnknown, nullptr, 0, 0};
         return;
       }
     }
 
     void* addr = ((char*)chunk) + (pageind << gPageSize2Pow);
-    *aInfo = {TagLiveLarge, addr, size};
+    *aInfo = {TagLiveLarge, addr, size, chunk->arena->mId};
     return;
   }
 
   // It must be a small allocation.
   auto run = (arena_run_t*)(mapbits & ~gPageSizeMask);
   MOZ_DIAGNOSTIC_ASSERT(run->mMagic == ARENA_RUN_MAGIC);
 
   // The allocation size is stored in the run metadata.
   size_t size = run->mBin->mSizeClass;
 
   // Address of the first possible pointer in the run after its headers.
   uintptr_t reg0_addr = (uintptr_t)run + run->mBin->mRunFirstRegionOffset;
   if (aPtr < (void*)reg0_addr) {
     // In the run header.
-    *aInfo = {TagUnknown, nullptr, 0};
+    *aInfo = {TagUnknown, nullptr, 0, 0};
     return;
   }
 
   // Position in the run.
   unsigned regind = ((uintptr_t)aPtr - reg0_addr) / size;
 
   // Pointer to the allocation's base address.
   void* addr = (void*)(reg0_addr + regind * size);
 
   // Check if the allocation has been freed.
   unsigned elm = regind >> (LOG2(sizeof(int)) + 3);
   unsigned bit = regind - (elm << (LOG2(sizeof(int)) + 3));
   PtrInfoTag tag =
       ((run->mRegionsMask[elm] & (1U << bit))) ? TagFreedSmall : TagLiveSmall;
 
-  *aInfo = {tag, addr, size};
+  *aInfo = {tag, addr, size, chunk->arena->mId};
 }
 
 namespace Debug {
 // Helper for debuggers. We don't want it to be inlined and optimized out.
 MOZ_NEVER_INLINE jemalloc_ptr_info_t* jemalloc_ptr_info(const void* aPtr) {
   static jemalloc_ptr_info_t info;
   MozJemalloc::jemalloc_ptr_info(aPtr, &info);
   return &info;
--- a/memory/build/mozjemalloc_types.h
+++ b/memory/build/mozjemalloc_types.h
@@ -89,47 +89,66 @@ typedef struct {
                        // cache.  (jemalloc calls these "dirty".)
   size_t bookkeeping;  // Committed bytes used internally by the
                        // allocator.
   size_t bin_unused;   // Bytes committed to a bin but currently unused.
 } jemalloc_stats_t;
 
 enum PtrInfoTag {
   // The pointer is not currently known to the allocator.
-  // 'addr' and 'size' are always 0.
+  // 'addr', 'size', and 'arenaId' are always 0.
   TagUnknown,
 
   // The pointer is within a live allocation.
-  // 'addr' and 'size' describe the allocation.
+  // 'addr', 'size', and 'arenaId' describe the allocation.
   TagLiveSmall,
   TagLiveLarge,
   TagLiveHuge,
 
   // The pointer is within a small freed allocation.
-  // 'addr' and 'size' describe the allocation.
+  // 'addr', 'size', and 'arenaId' describe the allocation.
   TagFreedSmall,
 
   // The pointer is within a freed page. Details about the original
   // allocation, including its size, are not available.
-  // 'addr' and 'size' describe the page.
+  // 'addr', 'size', and 'arenaId' describe the page.
   TagFreedPageDirty,
   TagFreedPageDecommitted,
   TagFreedPageMadvised,
   TagFreedPageZeroed,
 };
 
 // The information in jemalloc_ptr_info_t could be represented in a variety of
 // ways. The chosen representation has the following properties.
 // - The number of fields is minimized.
 // - The 'tag' field unambiguously defines the meaning of the subsequent fields.
 // Helper functions are used to group together related categories of tags.
-typedef struct {
+typedef struct jemalloc_ptr_info_s {
   enum PtrInfoTag tag;
   void* addr;   // meaning depends on tag; see above
   size_t size;  // meaning depends on tag; see above
+
+#ifdef MOZ_DEBUG
+  arena_id_t arenaId;  // meaning depends on tag; see above
+#endif
+
+#ifdef __cplusplus
+  jemalloc_ptr_info_s() = default;
+  jemalloc_ptr_info_s(enum PtrInfoTag aTag, void* aAddr, size_t aSize,
+                      arena_id_t aArenaId)
+      : tag(aTag),
+        addr(aAddr),
+        size(aSize)
+#  ifdef MOZ_DEBUG
+        ,
+        arenaId(aArenaId)
+#  endif
+  {
+  }
+#endif
 } jemalloc_ptr_info_t;
 
 static inline bool jemalloc_ptr_is_live(jemalloc_ptr_info_t* info) {
   return info->tag == TagLiveSmall || info->tag == TagLiveLarge ||
          info->tag == TagLiveHuge;
 }
 
 static inline bool jemalloc_ptr_is_freed(jemalloc_ptr_info_t* info) {