layout/base/nsPresArena.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/base/nsPresArena.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,201 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * vim: set ts=2 sw=2 et tw=78:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.9 + */
    1.10 +
    1.11 +/* arena allocation for the frame tree and closely-related objects */
    1.12 +
    1.13 +// Even on 32-bit systems, we allocate objects from the frame arena
    1.14 +// that require 8-byte alignment.  The cast to uintptr_t is needed
    1.15 +// because plarena isn't as careful about mask construction as it
    1.16 +// ought to be.
    1.17 +#define ALIGN_SHIFT 3
    1.18 +#define PL_ARENA_CONST_ALIGN_MASK ((uintptr_t(1) << ALIGN_SHIFT) - 1)
    1.19 +#include "plarena.h"
    1.20 +// plarena.h needs to be included first to make it use the above
    1.21 +// PL_ARENA_CONST_ALIGN_MASK in this file.
    1.22 +
    1.23 +#include "nsPresArena.h"
    1.24 +
    1.25 +#include "mozilla/Poison.h"
    1.26 +#include "nsDebug.h"
    1.27 +#include "nsArenaMemoryStats.h"
    1.28 +#include "nsPrintfCString.h"
    1.29 +
    1.30 +// Size to use for PLArena block allocations.
    1.31 +static const size_t ARENA_PAGE_SIZE = 8192;
    1.32 +
    1.33 +nsPresArena::nsPresArena()
    1.34 +{
    1.35 +  PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
    1.36 +}
    1.37 +
    1.38 +nsPresArena::~nsPresArena()
    1.39 +{
    1.40 +#if defined(MOZ_HAVE_MEM_CHECKS)
    1.41 +  mFreeLists.EnumerateEntries(UnpoisonFreeList, nullptr);
    1.42 +#endif
    1.43 +  PL_FinishArenaPool(&mPool);
    1.44 +}
    1.45 +
    1.46 +NS_HIDDEN_(void*)
    1.47 +nsPresArena::Allocate(uint32_t aCode, size_t aSize)
    1.48 +{
    1.49 +  NS_ABORT_IF_FALSE(aSize > 0, "PresArena cannot allocate zero bytes");
    1.50 +
    1.51 +  // We only hand out aligned sizes
    1.52 +  aSize = PL_ARENA_ALIGN(&mPool, aSize);
    1.53 +
    1.54 +  // If there is no free-list entry for this type already, we have
    1.55 +  // to create one now, to record its size.
    1.56 +  FreeList* list = mFreeLists.PutEntry(aCode);
    1.57 +
    1.58 +  nsTArray<void*>::index_type len = list->mEntries.Length();
    1.59 +  if (list->mEntrySize == 0) {
    1.60 +    NS_ABORT_IF_FALSE(len == 0, "list with entries but no recorded size");
    1.61 +    list->mEntrySize = aSize;
    1.62 +  } else {
    1.63 +    NS_ABORT_IF_FALSE(list->mEntrySize == aSize,
    1.64 +                      "different sizes for same object type code");
    1.65 +  }
    1.66 +
    1.67 +  void* result;
    1.68 +  if (len > 0) {
    1.69 +    // LIFO behavior for best cache utilization
    1.70 +    result = list->mEntries.ElementAt(len - 1);
    1.71 +    list->mEntries.RemoveElementAt(len - 1);
    1.72 +#if defined(DEBUG)
    1.73 +    {
    1.74 +      MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
    1.75 +      char* p = reinterpret_cast<char*>(result);
    1.76 +      char* limit = p + list->mEntrySize;
    1.77 +      for (; p < limit; p += sizeof(uintptr_t)) {
    1.78 +        uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
    1.79 +        NS_ABORT_IF_FALSE(val == mozPoisonValue(),
    1.80 +                          nsPrintfCString("PresArena: poison overwritten; "
    1.81 +                                          "wanted %.16llx "
    1.82 +                                          "found %.16llx "
    1.83 +                                          "errors in bits %.16llx",
    1.84 +                                          uint64_t(mozPoisonValue()),
    1.85 +                                          uint64_t(val),
    1.86 +                                          uint64_t(mozPoisonValue() ^ val)
    1.87 +                                          ).get());
    1.88 +      }
    1.89 +    }
    1.90 +#endif
    1.91 +    MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
    1.92 +    return result;
    1.93 +  }
    1.94 +
    1.95 +  // Allocate a new chunk from the arena
    1.96 +  list->mEntriesEverAllocated++;
    1.97 +  PL_ARENA_ALLOCATE(result, &mPool, aSize);
    1.98 +  if (!result) {
    1.99 +    NS_RUNTIMEABORT("out of memory");
   1.100 +  }
   1.101 +  return result;
   1.102 +}
   1.103 +
   1.104 +NS_HIDDEN_(void)
   1.105 +nsPresArena::Free(uint32_t aCode, void* aPtr)
   1.106 +{
   1.107 +  // Try to recycle this entry.
   1.108 +  FreeList* list = mFreeLists.GetEntry(aCode);
   1.109 +  NS_ABORT_IF_FALSE(list, "no free list for pres arena object");
   1.110 +  NS_ABORT_IF_FALSE(list->mEntrySize > 0, "PresArena cannot free zero bytes");
   1.111 +
   1.112 +  mozWritePoison(aPtr, list->mEntrySize);
   1.113 +
   1.114 +  MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
   1.115 +  list->mEntries.AppendElement(aPtr);
   1.116 +}
   1.117 +
   1.118 +/* static */ size_t
   1.119 +nsPresArena::SizeOfFreeListEntryExcludingThis(
   1.120 +  FreeList* aEntry, mozilla::MallocSizeOf aMallocSizeOf, void*)
   1.121 +{
   1.122 +  return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf);
   1.123 +}
   1.124 +
   1.125 +struct EnumerateData {
   1.126 +  nsArenaMemoryStats* stats;
   1.127 +  size_t total;
   1.128 +};
   1.129 +
   1.130 +#if defined(MOZ_HAVE_MEM_CHECKS)
   1.131 +/* static */ PLDHashOperator
   1.132 +nsPresArena::UnpoisonFreeList(FreeList* aEntry, void*)
   1.133 +{
   1.134 +  nsTArray<void*>::index_type len;
   1.135 +  while ((len = aEntry->mEntries.Length())) {
   1.136 +    void* result = aEntry->mEntries.ElementAt(len - 1);
   1.137 +    aEntry->mEntries.RemoveElementAt(len - 1);
   1.138 +    MOZ_MAKE_MEM_UNDEFINED(result, aEntry->mEntrySize);
   1.139 +  }
   1.140 +  return PL_DHASH_NEXT;
   1.141 +}
   1.142 +#endif
   1.143 +
   1.144 +/* static */ PLDHashOperator
   1.145 +nsPresArena::FreeListEnumerator(FreeList* aEntry, void* aData)
   1.146 +{
   1.147 +  EnumerateData* data = static_cast<EnumerateData*>(aData);
   1.148 +  // Note that we're not measuring the size of the entries on the free
   1.149 +  // list here.  The free list knows how many objects we've allocated
   1.150 +  // ever (which includes any objects that may be on the FreeList's
   1.151 +  // |mEntries| at this point) and we're using that to determine the
   1.152 +  // total size of objects allocated with a given ID.
   1.153 +  size_t totalSize = aEntry->mEntrySize * aEntry->mEntriesEverAllocated;
   1.154 +  size_t* p;
   1.155 +
   1.156 +  switch (NS_PTR_TO_INT32(aEntry->mKey)) {
   1.157 +#define FRAME_ID(classname)                                      \
   1.158 +    case nsQueryFrame::classname##_id:                           \
   1.159 +      p = &data->stats->FRAME_ID_STAT_FIELD(classname);          \
   1.160 +      break;
   1.161 +#include "nsFrameIdList.h"
   1.162 +#undef FRAME_ID
   1.163 +  case nsLineBox_id:
   1.164 +    p = &data->stats->mLineBoxes;
   1.165 +    break;
   1.166 +  case nsRuleNode_id:
   1.167 +    p = &data->stats->mRuleNodes;
   1.168 +    break;
   1.169 +  case nsStyleContext_id:
   1.170 +    p = &data->stats->mStyleContexts;
   1.171 +    break;
   1.172 +  default:
   1.173 +    return PL_DHASH_NEXT;
   1.174 +  }
   1.175 +
   1.176 +  *p += totalSize;
   1.177 +  data->total += totalSize;
   1.178 +
   1.179 +  return PL_DHASH_NEXT;
   1.180 +}
   1.181 +
   1.182 +void
   1.183 +nsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
   1.184 +                                    nsArenaMemoryStats* aArenaStats)
   1.185 +{
   1.186 +  // We do a complicated dance here because we want to measure the
   1.187 +  // space taken up by the different kinds of objects in the arena,
   1.188 +  // but we don't have pointers to those objects.  And even if we did,
   1.189 +  // we wouldn't be able to use aMallocSizeOf on them, since they were
   1.190 +  // allocated out of malloc'd chunks of memory.  So we compute the
   1.191 +  // size of the arena as known by malloc and we add up the sizes of
   1.192 +  // all the objects that we care about.  Subtracting these two
   1.193 +  // quantities gives us a catch-all "other" number, which includes
   1.194 +  // slop in the arena itself as well as the size of objects that
   1.195 +  // we've not measured explicitly.
   1.196 +
   1.197 +  size_t mallocSize = PL_SizeOfArenaPoolExcludingPool(&mPool, aMallocSizeOf);
   1.198 +  mallocSize += mFreeLists.SizeOfExcludingThis(SizeOfFreeListEntryExcludingThis,
   1.199 +                                               aMallocSizeOf);
   1.200 +
   1.201 +  EnumerateData data = { aArenaStats, 0 };
   1.202 +  mFreeLists.EnumerateEntries(FreeListEnumerator, &data);
   1.203 +  aArenaStats->mOther += mallocSize - data.total;
   1.204 +}

mercurial