layout/base/nsPresArena.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * vim: set ts=2 sw=2 et tw=78:
     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/.
     6  */
     8 /* arena allocation for the frame tree and closely-related objects */
    10 // Even on 32-bit systems, we allocate objects from the frame arena
    11 // that require 8-byte alignment.  The cast to uintptr_t is needed
    12 // because plarena isn't as careful about mask construction as it
    13 // ought to be.
    14 #define ALIGN_SHIFT 3
    15 #define PL_ARENA_CONST_ALIGN_MASK ((uintptr_t(1) << ALIGN_SHIFT) - 1)
    16 #include "plarena.h"
    17 // plarena.h needs to be included first to make it use the above
    18 // PL_ARENA_CONST_ALIGN_MASK in this file.
    20 #include "nsPresArena.h"
    22 #include "mozilla/Poison.h"
    23 #include "nsDebug.h"
    24 #include "nsArenaMemoryStats.h"
    25 #include "nsPrintfCString.h"
    27 // Size to use for PLArena block allocations.
    28 static const size_t ARENA_PAGE_SIZE = 8192;
    30 nsPresArena::nsPresArena()
    31 {
    32   PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
    33 }
    35 nsPresArena::~nsPresArena()
    36 {
    37 #if defined(MOZ_HAVE_MEM_CHECKS)
    38   mFreeLists.EnumerateEntries(UnpoisonFreeList, nullptr);
    39 #endif
    40   PL_FinishArenaPool(&mPool);
    41 }
    43 NS_HIDDEN_(void*)
    44 nsPresArena::Allocate(uint32_t aCode, size_t aSize)
    45 {
    46   NS_ABORT_IF_FALSE(aSize > 0, "PresArena cannot allocate zero bytes");
    48   // We only hand out aligned sizes
    49   aSize = PL_ARENA_ALIGN(&mPool, aSize);
    51   // If there is no free-list entry for this type already, we have
    52   // to create one now, to record its size.
    53   FreeList* list = mFreeLists.PutEntry(aCode);
    55   nsTArray<void*>::index_type len = list->mEntries.Length();
    56   if (list->mEntrySize == 0) {
    57     NS_ABORT_IF_FALSE(len == 0, "list with entries but no recorded size");
    58     list->mEntrySize = aSize;
    59   } else {
    60     NS_ABORT_IF_FALSE(list->mEntrySize == aSize,
    61                       "different sizes for same object type code");
    62   }
    64   void* result;
    65   if (len > 0) {
    66     // LIFO behavior for best cache utilization
    67     result = list->mEntries.ElementAt(len - 1);
    68     list->mEntries.RemoveElementAt(len - 1);
    69 #if defined(DEBUG)
    70     {
    71       MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
    72       char* p = reinterpret_cast<char*>(result);
    73       char* limit = p + list->mEntrySize;
    74       for (; p < limit; p += sizeof(uintptr_t)) {
    75         uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
    76         NS_ABORT_IF_FALSE(val == mozPoisonValue(),
    77                           nsPrintfCString("PresArena: poison overwritten; "
    78                                           "wanted %.16llx "
    79                                           "found %.16llx "
    80                                           "errors in bits %.16llx",
    81                                           uint64_t(mozPoisonValue()),
    82                                           uint64_t(val),
    83                                           uint64_t(mozPoisonValue() ^ val)
    84                                           ).get());
    85       }
    86     }
    87 #endif
    88     MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
    89     return result;
    90   }
    92   // Allocate a new chunk from the arena
    93   list->mEntriesEverAllocated++;
    94   PL_ARENA_ALLOCATE(result, &mPool, aSize);
    95   if (!result) {
    96     NS_RUNTIMEABORT("out of memory");
    97   }
    98   return result;
    99 }
   101 NS_HIDDEN_(void)
   102 nsPresArena::Free(uint32_t aCode, void* aPtr)
   103 {
   104   // Try to recycle this entry.
   105   FreeList* list = mFreeLists.GetEntry(aCode);
   106   NS_ABORT_IF_FALSE(list, "no free list for pres arena object");
   107   NS_ABORT_IF_FALSE(list->mEntrySize > 0, "PresArena cannot free zero bytes");
   109   mozWritePoison(aPtr, list->mEntrySize);
   111   MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
   112   list->mEntries.AppendElement(aPtr);
   113 }
   115 /* static */ size_t
   116 nsPresArena::SizeOfFreeListEntryExcludingThis(
   117   FreeList* aEntry, mozilla::MallocSizeOf aMallocSizeOf, void*)
   118 {
   119   return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf);
   120 }
   122 struct EnumerateData {
   123   nsArenaMemoryStats* stats;
   124   size_t total;
   125 };
   127 #if defined(MOZ_HAVE_MEM_CHECKS)
   128 /* static */ PLDHashOperator
   129 nsPresArena::UnpoisonFreeList(FreeList* aEntry, void*)
   130 {
   131   nsTArray<void*>::index_type len;
   132   while ((len = aEntry->mEntries.Length())) {
   133     void* result = aEntry->mEntries.ElementAt(len - 1);
   134     aEntry->mEntries.RemoveElementAt(len - 1);
   135     MOZ_MAKE_MEM_UNDEFINED(result, aEntry->mEntrySize);
   136   }
   137   return PL_DHASH_NEXT;
   138 }
   139 #endif
   141 /* static */ PLDHashOperator
   142 nsPresArena::FreeListEnumerator(FreeList* aEntry, void* aData)
   143 {
   144   EnumerateData* data = static_cast<EnumerateData*>(aData);
   145   // Note that we're not measuring the size of the entries on the free
   146   // list here.  The free list knows how many objects we've allocated
   147   // ever (which includes any objects that may be on the FreeList's
   148   // |mEntries| at this point) and we're using that to determine the
   149   // total size of objects allocated with a given ID.
   150   size_t totalSize = aEntry->mEntrySize * aEntry->mEntriesEverAllocated;
   151   size_t* p;
   153   switch (NS_PTR_TO_INT32(aEntry->mKey)) {
   154 #define FRAME_ID(classname)                                      \
   155     case nsQueryFrame::classname##_id:                           \
   156       p = &data->stats->FRAME_ID_STAT_FIELD(classname);          \
   157       break;
   158 #include "nsFrameIdList.h"
   159 #undef FRAME_ID
   160   case nsLineBox_id:
   161     p = &data->stats->mLineBoxes;
   162     break;
   163   case nsRuleNode_id:
   164     p = &data->stats->mRuleNodes;
   165     break;
   166   case nsStyleContext_id:
   167     p = &data->stats->mStyleContexts;
   168     break;
   169   default:
   170     return PL_DHASH_NEXT;
   171   }
   173   *p += totalSize;
   174   data->total += totalSize;
   176   return PL_DHASH_NEXT;
   177 }
   179 void
   180 nsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
   181                                     nsArenaMemoryStats* aArenaStats)
   182 {
   183   // We do a complicated dance here because we want to measure the
   184   // space taken up by the different kinds of objects in the arena,
   185   // but we don't have pointers to those objects.  And even if we did,
   186   // we wouldn't be able to use aMallocSizeOf on them, since they were
   187   // allocated out of malloc'd chunks of memory.  So we compute the
   188   // size of the arena as known by malloc and we add up the sizes of
   189   // all the objects that we care about.  Subtracting these two
   190   // quantities gives us a catch-all "other" number, which includes
   191   // slop in the arena itself as well as the size of objects that
   192   // we've not measured explicitly.
   194   size_t mallocSize = PL_SizeOfArenaPoolExcludingPool(&mPool, aMallocSizeOf);
   195   mallocSize += mFreeLists.SizeOfExcludingThis(SizeOfFreeListEntryExcludingThis,
   196                                                aMallocSizeOf);
   198   EnumerateData data = { aArenaStats, 0 };
   199   mFreeLists.EnumerateEntries(FreeListEnumerator, &data);
   200   aArenaStats->mOther += mallocSize - data.total;
   201 }

mercurial