LCOV - code coverage report
Current view: top level - layout/base - nsPresArena.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 62 81 76.5 %
Date: 2017-07-14 16:53:18 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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             :  */
       7             : 
       8             : /* arena allocation for the frame tree and closely-related objects */
       9             : 
      10             : #include "nsPresArena.h"
      11             : 
      12             : #include "mozilla/Poison.h"
      13             : #include "nsDebug.h"
      14             : #include "nsArenaMemoryStats.h"
      15             : #include "nsPrintfCString.h"
      16             : #include "GeckoStyleContext.h"
      17             : #include "FrameLayerBuilder.h"
      18             : #include "mozilla/ArrayUtils.h"
      19             : 
      20             : #include <inttypes.h>
      21             : 
      22             : using namespace mozilla;
      23             : 
      24          28 : nsPresArena::nsPresArena()
      25             : {
      26          28 : }
      27             : 
      28           8 : nsPresArena::~nsPresArena()
      29             : {
      30           4 :   ClearArenaRefPtrs();
      31             : 
      32             : #if defined(MOZ_HAVE_MEM_CHECKS)
      33             :   for (FreeList* entry = mFreeLists; entry != ArrayEnd(mFreeLists); ++entry) {
      34             :     nsTArray<void*>::index_type len;
      35             :     while ((len = entry->mEntries.Length())) {
      36             :       void* result = entry->mEntries.ElementAt(len - 1);
      37             :       entry->mEntries.RemoveElementAt(len - 1);
      38             :       MOZ_MAKE_MEM_UNDEFINED(result, entry->mEntrySize);
      39             :     }
      40             :   }
      41             : #endif
      42           4 : }
      43             : 
      44             : /* inline */ void
      45           0 : nsPresArena::ClearArenaRefPtrWithoutDeregistering(void* aPtr,
      46             :                                                   ArenaObjectID aObjectID)
      47             : {
      48           0 :   switch (aObjectID) {
      49             : #define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_)                     \
      50             :     case eArenaObjectID_##name_:                                              \
      51             :       static_cast<ArenaRefPtr<name_>*>(aPtr)->ClearWithoutDeregistering();    \
      52             :       return;
      53             : #include "nsPresArenaObjectList.h"
      54             : #undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
      55             :     default:
      56           0 :       break;
      57             :   }
      58           0 :   switch (aObjectID) {
      59             : #define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_)                  \
      60             :     case eArenaObjectID_##name_:                                              \
      61             :       MOZ_ASSERT(false, #name_ " must be declared in nsPresArenaObjectList.h "\
      62             :                         "with PRES_ARENA_OBJECT_SUPPORTS_ARENAREFPTR");       \
      63             :       break;
      64             : #include "nsPresArenaObjectList.h"
      65             : #undef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
      66             :     default:
      67           0 :       MOZ_ASSERT(false, "unexpected ArenaObjectID value");
      68             :       break;
      69             :   }
      70             : }
      71             : 
      72             : void
      73           8 : nsPresArena::ClearArenaRefPtrs()
      74             : {
      75           8 :   for (auto iter = mArenaRefPtrs.Iter(); !iter.Done(); iter.Next()) {
      76           0 :     void* ptr = iter.Key();
      77           0 :     ArenaObjectID id = iter.UserData();
      78           0 :     ClearArenaRefPtrWithoutDeregistering(ptr, id);
      79             :   }
      80           8 :   mArenaRefPtrs.Clear();
      81           8 : }
      82             : 
      83             : void
      84           2 : nsPresArena::ClearArenaRefPtrs(ArenaObjectID aObjectID)
      85             : {
      86           2 :   for (auto iter = mArenaRefPtrs.Iter(); !iter.Done(); iter.Next()) {
      87           0 :     void* ptr = iter.Key();
      88           0 :     ArenaObjectID id = iter.UserData();
      89           0 :     if (id == aObjectID) {
      90           0 :       ClearArenaRefPtrWithoutDeregistering(ptr, id);
      91           0 :       iter.Remove();
      92             :     }
      93             :   }
      94           2 : }
      95             : 
      96             : void*
      97       11959 : nsPresArena::Allocate(uint32_t aCode, size_t aSize)
      98             : {
      99       11959 :   MOZ_ASSERT(aSize > 0, "PresArena cannot allocate zero bytes");
     100       11959 :   MOZ_ASSERT(aCode < ArrayLength(mFreeLists));
     101             : 
     102             :   // We only hand out aligned sizes
     103       11959 :   aSize = mPool.AlignedSize(aSize);
     104             : 
     105       11959 :   FreeList* list = &mFreeLists[aCode];
     106             : 
     107       11959 :   nsTArray<void*>::index_type len = list->mEntries.Length();
     108       11959 :   if (list->mEntrySize == 0) {
     109         720 :     MOZ_ASSERT(len == 0, "list with entries but no recorded size");
     110         720 :     list->mEntrySize = aSize;
     111             :   } else {
     112       11239 :     MOZ_ASSERT(list->mEntrySize == aSize,
     113             :                "different sizes for same object type code");
     114             :   }
     115             : 
     116             :   void* result;
     117       11959 :   if (len > 0) {
     118             :     // Remove from the end of the mEntries array to avoid memmoving entries,
     119             :     // and use SetLengthAndRetainStorage to avoid a lot of malloc/free
     120             :     // from ShrinkCapacity on smaller sizes.  500 pointers means the malloc size
     121             :     // for the array is 4096 bytes or more on a 64-bit system.  The next smaller
     122             :     // size is 2048 (with jemalloc), which we consider not worth compacting.
     123        4812 :     result = list->mEntries.ElementAt(len - 1);
     124        4812 :     if (list->mEntries.Capacity() > 500) {
     125         245 :       list->mEntries.RemoveElementAt(len - 1);
     126             :     } else {
     127        4567 :       list->mEntries.SetLengthAndRetainStorage(len - 1);
     128             :     }
     129             : #if defined(DEBUG)
     130             :     {
     131             :       MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
     132        4812 :       char* p = reinterpret_cast<char*>(result);
     133        4812 :       char* limit = p + list->mEntrySize;
     134      153782 :       for (; p < limit; p += sizeof(uintptr_t)) {
     135       74485 :         uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
     136       74485 :         if (val != mozPoisonValue()) {
     137           0 :           MOZ_ReportAssertionFailure(
     138           0 :             nsPrintfCString("PresArena: poison overwritten; "
     139             :                             "wanted %.16" PRIx64 " "
     140             :                             "found %.16" PRIx64 " "
     141             :                             "errors in bits %.16" PRIx64 " ",
     142           0 :                             uint64_t(mozPoisonValue()),
     143             :                             uint64_t(val),
     144           0 :                             uint64_t(mozPoisonValue() ^ val)).get(),
     145           0 :             __FILE__, __LINE__);
     146           0 :           MOZ_CRASH();
     147             :         }
     148             :       }
     149             :     }
     150             : #endif
     151             :     MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
     152        4812 :     return result;
     153             :   }
     154             : 
     155             :   // Allocate a new chunk from the arena
     156        7147 :   list->mEntriesEverAllocated++;
     157        7147 :   return mPool.Allocate(aSize);
     158             : }
     159             : 
     160             : void
     161        6852 : nsPresArena::Free(uint32_t aCode, void* aPtr)
     162             : {
     163        6852 :   MOZ_ASSERT(aCode < ArrayLength(mFreeLists));
     164             : 
     165             :   // Try to recycle this entry.
     166        6852 :   FreeList* list = &mFreeLists[aCode];
     167        6852 :   MOZ_ASSERT(list->mEntrySize > 0, "object of this type was never allocated");
     168             : 
     169        6852 :   mozWritePoison(aPtr, list->mEntrySize);
     170             : 
     171             :   MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
     172        6852 :   list->mEntries.AppendElement(aPtr);
     173        6852 : }
     174             : 
     175             : void
     176          21 : nsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
     177             :                                     nsArenaMemoryStats* aArenaStats)
     178             : {
     179             :   // We do a complicated dance here because we want to measure the
     180             :   // space taken up by the different kinds of objects in the arena,
     181             :   // but we don't have pointers to those objects.  And even if we did,
     182             :   // we wouldn't be able to use aMallocSizeOf on them, since they were
     183             :   // allocated out of malloc'd chunks of memory.  So we compute the
     184             :   // size of the arena as known by malloc and we add up the sizes of
     185             :   // all the objects that we care about.  Subtracting these two
     186             :   // quantities gives us a catch-all "other" number, which includes
     187             :   // slop in the arena itself as well as the size of objects that
     188             :   // we've not measured explicitly.
     189             : 
     190          21 :   size_t mallocSize = mPool.SizeOfExcludingThis(aMallocSizeOf);
     191             : 
     192          21 :   size_t totalSizeInFreeLists = 0;
     193        4494 :   for (FreeList* entry = mFreeLists; entry != ArrayEnd(mFreeLists); ++entry) {
     194        4473 :     mallocSize += entry->SizeOfExcludingThis(aMallocSizeOf);
     195             : 
     196             :     // Note that we're not measuring the size of the entries on the free
     197             :     // list here.  The free list knows how many objects we've allocated
     198             :     // ever (which includes any objects that may be on the FreeList's
     199             :     // |mEntries| at this point) and we're using that to determine the
     200             :     // total size of objects allocated with a given ID.
     201        4473 :     size_t totalSize = entry->mEntrySize * entry->mEntriesEverAllocated;
     202             :     size_t* p;
     203             : 
     204        4473 :     switch (entry - mFreeLists) {
     205             : #define FRAME_ID(classname, ...)                          \
     206             :       case nsQueryFrame::classname##_id:                  \
     207             :         p = &aArenaStats->FRAME_ID_STAT_FIELD(classname); \
     208             :         break;
     209             : #define ABSTRACT_FRAME_ID(...)
     210             : #include "nsFrameIdList.h"
     211             : #undef FRAME_ID
     212             : #undef ABSTRACT_FRAME_ID
     213             :       case eArenaObjectID_nsLineBox:
     214          21 :         p = &aArenaStats->mLineBoxes;
     215          21 :         break;
     216             :       case eArenaObjectID_nsRuleNode:
     217          21 :         p = &aArenaStats->mRuleNodes;
     218          21 :         break;
     219             :       case eArenaObjectID_GeckoStyleContext:
     220          21 :         p = &aArenaStats->mStyleContexts;
     221          21 :         break;
     222             : #define STYLE_STRUCT(name_, checkdata_cb_)      \
     223             :         case eArenaObjectID_nsStyle##name_:
     224             : #include "nsStyleStructList.h"
     225             : #undef STYLE_STRUCT
     226         504 :         p = &aArenaStats->mStyleStructs;
     227         504 :         break;
     228             :       default:
     229         903 :         continue;
     230             :     }
     231             : 
     232        3570 :     *p += totalSize;
     233        3570 :     totalSizeInFreeLists += totalSize;
     234             :   }
     235             : 
     236          21 :   aArenaStats->mOther += mallocSize - totalSizeInFreeLists;
     237          21 : }

Generated by: LCOV version 1.13