tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsPresArena.cpp (7261B)


      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/.
      6 */
      7 
      8 /* arena allocation for the frame tree and closely-related objects */
      9 
     10 #include "nsPresArena.h"
     11 
     12 #include <inttypes.h>
     13 
     14 #include "mozilla/ComputedStyle.h"
     15 #include "mozilla/ComputedStyleInlines.h"
     16 #include "mozilla/Poison.h"
     17 #include "nsDebug.h"
     18 #include "nsDisplayList.h"
     19 #include "nsPrintfCString.h"
     20 #include "nsWindowSizes.h"
     21 
     22 using namespace mozilla;
     23 
     24 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
     25 nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::~nsPresArena() {
     26 #if defined(MOZ_HAVE_MEM_CHECKS)
     27  for (FreeList* entry = mFreeLists; entry != std::end(mFreeLists); ++entry) {
     28    for (void* result : entry->mEntries) {
     29      MOZ_MAKE_MEM_UNDEFINED(result, entry->mEntrySize);
     30    }
     31    entry->mEntries.Clear();
     32  }
     33 #endif
     34 }
     35 
     36 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
     37 void* nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::Allocate(ObjectId aCode,
     38                                                                size_t aSize) {
     39  MOZ_ASSERT(NS_IsMainThread());
     40  MOZ_ASSERT(aSize > 0, "PresArena cannot allocate zero bytes");
     41  MOZ_ASSERT(size_t(aCode) < std::size(mFreeLists));
     42 
     43  // We only hand out aligned sizes
     44  aSize = mPool.AlignedSize(aSize);
     45 
     46  FreeList* list = &mFreeLists[size_t(aCode)];
     47 
     48  nsTArray<void*>::index_type len = list->mEntries.Length();
     49  if (list->mEntrySize == 0) {
     50    MOZ_ASSERT(len == 0, "list with entries but no recorded size");
     51    list->mEntrySize = aSize;
     52  } else {
     53    MOZ_ASSERT(list->mEntrySize == aSize,
     54               "different sizes for same object type code");
     55  }
     56 
     57  void* result;
     58  if (len > 0) {
     59    // Remove from the end of the mEntries array to avoid memmoving entries,
     60    // and use SetLengthAndRetainStorage to avoid a lot of malloc/free
     61    // from ShrinkCapacity on smaller sizes.  500 pointers means the malloc size
     62    // for the array is 4096 bytes or more on a 64-bit system.  The next smaller
     63    // size is 2048 (with jemalloc), which we consider not worth compacting.
     64    result = list->mEntries.Elements()[len - 1];
     65    if (list->mEntries.Capacity() > 500) {
     66      list->mEntries.RemoveElementAtUnsafe(len - 1);
     67    } else {
     68      list->mEntries.SetLengthAndRetainStorage(len - 1);
     69    }
     70 #if defined(DEBUG)
     71    {
     72      MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
     73      char* p = reinterpret_cast<char*>(result);
     74      char* limit = p + list->mEntrySize;
     75      for (; p < limit; p += sizeof(uintptr_t)) {
     76        uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
     77        if (val != mozPoisonValue()) {
     78          MOZ_ReportAssertionFailure(
     79              nsPrintfCString("PresArena: poison overwritten; "
     80                              "wanted %.16" PRIx64 " "
     81                              "found %.16" PRIx64 " "
     82                              "errors in bits %.16" PRIx64 " ",
     83                              uint64_t(mozPoisonValue()), uint64_t(val),
     84                              uint64_t(mozPoisonValue() ^ val))
     85                  .get(),
     86              __FILE__, __LINE__);
     87          MOZ_CRASH();
     88        }
     89      }
     90    }
     91 #endif
     92    MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
     93    return result;
     94  }
     95 
     96  // Allocate a new chunk from the arena
     97  list->mEntriesEverAllocated++;
     98  return mPool.Allocate(aSize);
     99 }
    100 
    101 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
    102 void nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::Free(ObjectId aCode,
    103                                                           void* aPtr) {
    104  MOZ_ASSERT(NS_IsMainThread());
    105  MOZ_ASSERT(size_t(aCode) < std::size(mFreeLists));
    106 
    107  // Try to recycle this entry.
    108  FreeList* list = &mFreeLists[size_t(aCode)];
    109  MOZ_ASSERT(list->mEntrySize > 0, "object of this type was never allocated");
    110 
    111  mozWritePoison(aPtr, list->mEntrySize);
    112 
    113  MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
    114  list->mEntries.AppendElement(aPtr);
    115 }
    116 
    117 template <size_t ArenaSize, typename ObjectId, size_t ObjectIdCount>
    118 void nsPresArena<ArenaSize, ObjectId, ObjectIdCount>::AddSizeOfExcludingThis(
    119    nsWindowSizes& aSizes, ArenaKind aKind) const {
    120  // We do a complicated dance here because we want to measure the
    121  // space taken up by the different kinds of objects in the arena,
    122  // but we don't have pointers to those objects.  And even if we did,
    123  // we wouldn't be able to use mMallocSizeOf on them, since they were
    124  // allocated out of malloc'd chunks of memory.  So we compute the
    125  // size of the arena as known by malloc and we add up the sizes of
    126  // all the objects that we care about.  Subtracting these two
    127  // quantities gives us a catch-all "other" number, which includes
    128  // slop in the arena itself as well as the size of objects that
    129  // we've not measured explicitly.
    130 
    131  size_t mallocSize = mPool.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
    132 
    133  size_t totalSizeInFreeLists = 0;
    134  for (const FreeList* entry = mFreeLists; entry != std::end(mFreeLists);
    135       ++entry) {
    136    mallocSize += entry->SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
    137 
    138    // Note that we're not measuring the size of the entries on the free
    139    // list here.  The free list knows how many objects we've allocated
    140    // ever (which includes any objects that may be on the FreeList's
    141    // |mEntries| at this point) and we're using that to determine the
    142    // total size of objects allocated with a given ID.
    143    size_t totalSize = entry->mEntrySize * entry->mEntriesEverAllocated;
    144 
    145    if (aKind == ArenaKind::PresShell) {
    146      switch (entry - mFreeLists) {
    147 #define PRES_ARENA_OBJECT(name_)                                 \
    148  case eArenaObjectID_##name_:                                   \
    149    aSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_) += totalSize; \
    150    break;
    151 #include "nsPresArenaObjectList.h"
    152 #undef PRES_ARENA_OBJECT
    153        default:
    154          MOZ_ASSERT_UNREACHABLE("Unknown arena object type");
    155      }
    156    } else {
    157      MOZ_ASSERT(aKind == ArenaKind::DisplayList);
    158      switch (DisplayListArenaObjectId(entry - mFreeLists)) {
    159 #define DISPLAY_LIST_ARENA_OBJECT(name_)                         \
    160  case DisplayListArenaObjectId::name_:                          \
    161    aSizes.mArenaSizes.NS_ARENA_SIZES_FIELD(name_) += totalSize; \
    162    break;
    163 #include "nsDisplayListArenaTypes.h"
    164 #undef DISPLAY_LIST_ARENA_OBJECT
    165        default:
    166          MOZ_ASSERT_UNREACHABLE("Unknown display item arena type");
    167      }
    168    }
    169 
    170    totalSizeInFreeLists += totalSize;
    171  }
    172 
    173  auto& field = aKind == ArenaKind::PresShell
    174                    ? aSizes.mLayoutPresShellSize
    175                    : aSizes.mLayoutRetainedDisplayListSize;
    176 
    177  field += mallocSize - totalSizeInFreeLists;
    178 }
    179 
    180 // Explicitly instantiate templates for the used nsPresArena allocator sizes.
    181 // This is needed because nsPresArena definition is split across multiple files.
    182 template class nsPresArena<8192, ArenaObjectID, eArenaObjectID_COUNT>;
    183 template class nsPresArena<32768, DisplayListArenaObjectId,
    184                           size_t(DisplayListArenaObjectId::COUNT)>;