Bug 1052579 - Add ability to query ArenaID to mozjemalloc_ptr_info. r=glandium
☠☠ backed out by f6a2f11fd0b7 ☠ ☠
authorChris Martin <cmartin@mozilla.com>
Tue, 02 Apr 2019 03:55:06 +0000
changeset 470365 497561b767374edfe627dcdbadd9b05133c9bf71
parent 470364 47d1596a579ff86f45311cb5eb25e18b99b14b78
child 470366 b6dd2d9ef99dfe490ca1130fe51007582f3bfe17
push id112868
push useropoprus@mozilla.com
push dateMon, 22 Apr 2019 22:19:22 +0000
treeherdermozilla-inbound@24537856cc88 [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() {}
+  jemalloc_ptr_info_s(enum PtrInfoTag tag, void* addr, size_t size,
+                      arena_id_t arenaId)
+      : tag(tag),
+        addr(addr),
+        size(size)
+#  ifdef MOZ_DEBUG
+        ,
+        arenaId(arenaId)
+#  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) {