LCOV - code coverage report
Current view: directory - layout/base - nsPresArena.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 116 0 0.0 %
Date: 2012-06-02 Functions: 25 0 0.0 %

       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                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Steve Clark <buster@netscape.com>
      25                 :  *   HÃ¥kan Waara <hwaara@chello.se>
      26                 :  *   Dan Rosen <dr@netscape.com>
      27                 :  *   Daniel Glazman <glazman@netscape.com>
      28                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      29                 :  *
      30                 :  * Alternatively, the contents of this file may be used under the terms of
      31                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      32                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      33                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      34                 :  * of those above. If you wish to allow use of your version of this file only
      35                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      36                 :  * use your version of this file under the terms of the MPL, indicate your
      37                 :  * decision by deleting the provisions above and replace them with the notice
      38                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      39                 :  * the provisions above, a recipient may use your version of this file under
      40                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      41                 :  *
      42                 :  * ***** END LICENSE BLOCK *****
      43                 :  */
      44                 : 
      45                 : /* arena allocation for the frame tree and closely-related objects */
      46                 : 
      47                 : #include "nsPresArena.h"
      48                 : #include "nsCRT.h"
      49                 : #include "nsDebug.h"
      50                 : #include "nsTArray.h"
      51                 : #include "nsTHashtable.h"
      52                 : #include "prmem.h"
      53                 : #include "prinit.h"
      54                 : #include "prlog.h"
      55                 : 
      56                 : #ifdef MOZ_CRASHREPORTER
      57                 : #include "nsICrashReporter.h"
      58                 : #include "nsCOMPtr.h"
      59                 : #include "nsServiceManagerUtils.h"
      60                 : #include "nsPrintfCString.h"
      61                 : #endif
      62                 : 
      63                 : // Even on 32-bit systems, we allocate objects from the frame arena
      64                 : // that require 8-byte alignment.  The cast to PRUword is needed
      65                 : // because plarena isn't as careful about mask construction as it
      66                 : // ought to be.
      67                 : #define ALIGN_SHIFT 3
      68                 : #define PL_ARENA_CONST_ALIGN_MASK ((PRUword(1) << ALIGN_SHIFT) - 1)
      69                 : #include "plarena.h"
      70                 : 
      71                 : #ifdef _WIN32
      72                 : # include <windows.h>
      73                 : #elif !defined(__OS2__)
      74                 : # include <unistd.h>
      75                 : # include <sys/mman.h>
      76                 : # ifndef MAP_ANON
      77                 : #  ifdef MAP_ANONYMOUS
      78                 : #   define MAP_ANON MAP_ANONYMOUS
      79                 : #  else
      80                 : #   error "Don't know how to get anonymous memory"
      81                 : #  endif
      82                 : # endif
      83                 : #endif
      84                 : 
      85                 : // Size to use for PLArena block allocations.
      86                 : static const size_t ARENA_PAGE_SIZE = 8192;
      87                 : 
      88                 : // Freed memory is filled with a poison value, which we arrange to
      89                 : // form a pointer either to an always-unmapped region of the address
      90                 : // space, or to a page that has been reserved and rendered
      91                 : // inaccessible via OS primitives.  See tests/TestPoisonArea.cpp for
      92                 : // extensive discussion of the requirements for this page.  The code
      93                 : // from here to 'class FreeList' needs to be kept in sync with that
      94                 : // file.
      95                 : 
      96                 : #ifdef _WIN32
      97                 : static void *
      98                 : ReserveRegion(PRUword region, PRUword size)
      99                 : {
     100                 :   return VirtualAlloc((void *)region, size, MEM_RESERVE, PAGE_NOACCESS);
     101                 : }
     102                 : 
     103                 : static void
     104                 : ReleaseRegion(void *region, PRUword size)
     105                 : {
     106                 :   VirtualFree(region, size, MEM_RELEASE);
     107                 : }
     108                 : 
     109                 : static bool
     110                 : ProbeRegion(PRUword region, PRUword size)
     111                 : {
     112                 :   SYSTEM_INFO sinfo;
     113                 :   GetSystemInfo(&sinfo);
     114                 :   if (region >= (PRUword)sinfo.lpMaximumApplicationAddress &&
     115                 :       region + size >= (PRUword)sinfo.lpMaximumApplicationAddress) {
     116                 :     return true;
     117                 :   } else {
     118                 :     return false;
     119                 :   }
     120                 : }
     121                 : 
     122                 : static PRUword
     123                 : GetDesiredRegionSize()
     124                 : {
     125                 :   SYSTEM_INFO sinfo;
     126                 :   GetSystemInfo(&sinfo);
     127                 :   return sinfo.dwAllocationGranularity;
     128                 : }
     129                 : 
     130                 : #define RESERVE_FAILED 0
     131                 : 
     132                 : #elif defined(__OS2__)
     133                 : static void *
     134                 : ReserveRegion(PRUword region, PRUword size)
     135                 : {
     136                 :   // OS/2 doesn't support allocation at an arbitrary address,
     137                 :   // so return an address that is known to be invalid.
     138                 :   return (void*)0xFFFD0000;
     139                 : }
     140                 : 
     141                 : static void
     142                 : ReleaseRegion(void *region, PRUword size)
     143                 : {
     144                 :   return;
     145                 : }
     146                 : 
     147                 : static bool
     148                 : ProbeRegion(PRUword region, PRUword size)
     149                 : {
     150                 :   // There's no reliable way to probe an address in the system
     151                 :   // arena other than by touching it and seeing if a trap occurs.
     152                 :   return false;
     153                 : }
     154                 : 
     155                 : static PRUword
     156                 : GetDesiredRegionSize()
     157                 : {
     158                 :   // Page size is fixed at 4k.
     159                 :   return 0x1000;
     160                 : }
     161                 : 
     162                 : #define RESERVE_FAILED 0
     163                 : 
     164                 : #else // Unix
     165                 : 
     166                 : static void *
     167               0 : ReserveRegion(PRUword region, PRUword size)
     168                 : {
     169               0 :   return mmap((caddr_t)region, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
     170                 : }
     171                 : 
     172                 : static void
     173               0 : ReleaseRegion(void *region, PRUword size)
     174                 : {
     175               0 :   munmap((caddr_t)region, size);
     176               0 : }
     177                 : 
     178                 : static bool
     179               0 : ProbeRegion(PRUword region, PRUword size)
     180                 : {
     181               0 :   if (madvise((caddr_t)region, size, MADV_NORMAL)) {
     182               0 :     return true;
     183                 :   } else {
     184               0 :     return false;
     185                 :   }
     186                 : }
     187                 : 
     188                 : static PRUword
     189               0 : GetDesiredRegionSize()
     190                 : {
     191               0 :   return sysconf(_SC_PAGESIZE);
     192                 : }
     193                 : 
     194                 : #define RESERVE_FAILED MAP_FAILED
     195                 : 
     196                 : #endif // system dependencies
     197                 : 
     198                 : PR_STATIC_ASSERT(sizeof(PRUword) == 4 || sizeof(PRUword) == 8);
     199                 : PR_STATIC_ASSERT(sizeof(PRUword) == sizeof(void *));
     200                 : 
     201                 : static PRUword
     202               0 : ReservePoisonArea(PRUword rgnsize)
     203                 : {
     204                 :   if (sizeof(PRUword) == 8) {
     205                 :     // Use the hardware-inaccessible region.
     206                 :     // We have to avoid 64-bit constants and shifts by 32 bits, since this
     207                 :     // code is compiled in 32-bit mode, although it is never executed there.
     208                 :     return
     209                 :       (((PRUword(0x7FFFFFFFu) << 31) << 1 | PRUword(0xF0DEAFFFu))
     210                 :        & ~(rgnsize-1));
     211                 : 
     212                 :   } else {
     213                 :     // First see if we can allocate the preferred poison address from the OS.
     214               0 :     PRUword candidate = (0xF0DEAFFF & ~(rgnsize-1));
     215               0 :     void *result = ReserveRegion(candidate, rgnsize);
     216               0 :     if (result == (void *)candidate) {
     217                 :       // success - inaccessible page allocated
     218               0 :       return candidate;
     219                 :     }
     220                 : 
     221                 :     // That didn't work, so see if the preferred address is within a range
     222                 :     // of permanently inacessible memory.
     223               0 :     if (ProbeRegion(candidate, rgnsize)) {
     224                 :       // success - selected page cannot be usable memory
     225               0 :       if (result != RESERVE_FAILED)
     226               0 :         ReleaseRegion(result, rgnsize);
     227               0 :       return candidate;
     228                 :     }
     229                 : 
     230                 :     // The preferred address is already in use.  Did the OS give us a
     231                 :     // consolation prize?
     232               0 :     if (result != RESERVE_FAILED) {
     233               0 :       return PRUword(result);
     234                 :     }
     235                 : 
     236                 :     // It didn't, so try to allocate again, without any constraint on
     237                 :     // the address.
     238               0 :     result = ReserveRegion(0, rgnsize);
     239               0 :     if (result != RESERVE_FAILED) {
     240               0 :       return PRUword(result);
     241                 :     }
     242                 : 
     243               0 :     NS_RUNTIMEABORT("no usable poison region identified");
     244               0 :     return 0;
     245                 :   }
     246                 : }
     247                 : 
     248                 : static PRUword ARENA_POISON;
     249                 : static PRCallOnceType ARENA_POISON_guard;
     250                 : 
     251                 : static PRStatus
     252               0 : ARENA_POISON_init()
     253                 : {
     254               0 :   PRUword rgnsize = GetDesiredRegionSize();
     255               0 :   PRUword rgnbase = ReservePoisonArea(rgnsize);
     256                 : 
     257               0 :   if (rgnsize == 0) // can't happen
     258               0 :     return PR_FAILURE;
     259                 : 
     260               0 :   ARENA_POISON = rgnbase + rgnsize/2 - 1;
     261                 : 
     262                 : #ifdef MOZ_CRASHREPORTER
     263                 :   nsCOMPtr<nsICrashReporter> cr =
     264               0 :     do_GetService("@mozilla.org/toolkit/crash-reporter;1");
     265                 :   bool enabled;
     266               0 :   if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) {
     267               0 :     cr->AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"),
     268               0 :                             nsPrintfCString(17, "%.16llx", PRUint64(rgnbase)));
     269               0 :     cr->AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"),
     270               0 :                             nsPrintfCString("%lu", PRUint32(rgnsize)));
     271                 :   }
     272                 : #endif
     273               0 :   return PR_SUCCESS;
     274                 : }
     275                 : 
     276                 : #ifndef DEBUG_TRACEMALLOC_PRESARENA
     277                 : 
     278                 : // All keys to this hash table fit in 32 bits (see below) so we do not
     279                 : // bother actually hashing them.
     280                 : 
     281                 : namespace {
     282                 : 
     283                 : class FreeList : public PLDHashEntryHdr
     284               0 : {
     285                 : public:
     286                 :   typedef PRUint32 KeyType;
     287                 :   nsTArray<void *> mEntries;
     288                 :   size_t mEntrySize;
     289                 : 
     290                 : protected:
     291                 :   typedef const void* KeyTypePointer;
     292                 :   KeyTypePointer mKey;
     293                 : 
     294               0 :   FreeList(KeyTypePointer aKey) : mEntrySize(0), mKey(aKey) {}
     295                 :   // Default copy constructor and destructor are ok.
     296                 : 
     297               0 :   bool KeyEquals(KeyTypePointer const aKey) const
     298               0 :   { return mKey == aKey; }
     299                 : 
     300               0 :   static KeyTypePointer KeyToPointer(KeyType aKey)
     301               0 :   { return NS_INT32_TO_PTR(aKey); }
     302                 : 
     303               0 :   static PLDHashNumber HashKey(KeyTypePointer aKey)
     304               0 :   { return NS_PTR_TO_INT32(aKey); }
     305                 : 
     306                 :   enum { ALLOW_MEMMOVE = false };
     307                 :   friend class nsTHashtable<FreeList>;
     308                 : };
     309                 : 
     310                 : }
     311                 : 
     312                 : struct nsPresArena::State {
     313                 :   nsTHashtable<FreeList> mFreeLists;
     314                 :   PLArenaPool mPool;
     315                 : 
     316               0 :   State()
     317               0 :   {
     318               0 :     mFreeLists.Init();
     319               0 :     PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
     320               0 :     PR_CallOnce(&ARENA_POISON_guard, ARENA_POISON_init);
     321               0 :   }
     322                 : 
     323               0 :   ~State()
     324               0 :   {
     325               0 :     PL_FinishArenaPool(&mPool);
     326               0 :   }
     327                 : 
     328               0 :   void* Allocate(PRUint32 aCode, size_t aSize)
     329                 :   {
     330               0 :     NS_ABORT_IF_FALSE(aSize > 0, "PresArena cannot allocate zero bytes");
     331                 : 
     332                 :     // We only hand out aligned sizes
     333               0 :     aSize = PL_ARENA_ALIGN(&mPool, aSize);
     334                 : 
     335                 :     // If there is no free-list entry for this type already, we have
     336                 :     // to create one now, to record its size.
     337               0 :     FreeList* list = mFreeLists.PutEntry(aCode);
     338               0 :     if (!list) {
     339               0 :       return nsnull;
     340                 :     }
     341                 : 
     342               0 :     nsTArray<void*>::index_type len = list->mEntries.Length();
     343               0 :     if (list->mEntrySize == 0) {
     344               0 :       NS_ABORT_IF_FALSE(len == 0, "list with entries but no recorded size");
     345               0 :       list->mEntrySize = aSize;
     346                 :     } else {
     347               0 :       NS_ABORT_IF_FALSE(list->mEntrySize == aSize,
     348                 :                         "different sizes for same object type code");
     349                 :     }
     350                 : 
     351                 :     void* result;
     352               0 :     if (len > 0) {
     353                 :       // LIFO behavior for best cache utilization
     354               0 :       result = list->mEntries.ElementAt(len - 1);
     355               0 :       list->mEntries.RemoveElementAt(len - 1);
     356                 : #ifdef DEBUG
     357                 :       {
     358               0 :         char* p = reinterpret_cast<char*>(result);
     359               0 :         char* limit = p + list->mEntrySize;
     360               0 :         for (; p < limit; p += sizeof(PRUword)) {
     361               0 :           NS_ABORT_IF_FALSE(*reinterpret_cast<PRUword*>(p) == ARENA_POISON,
     362                 :                             "PresArena: poison overwritten");
     363                 :         }
     364                 :       }
     365                 : #endif
     366               0 :       return result;
     367                 :     }
     368                 : 
     369                 :     // Allocate a new chunk from the arena
     370               0 :     PL_ARENA_ALLOCATE(result, &mPool, aSize);
     371               0 :     return result;
     372                 :   }
     373                 : 
     374               0 :   void Free(PRUint32 aCode, void* aPtr)
     375                 :   {
     376                 :     // Try to recycle this entry.
     377               0 :     FreeList* list = mFreeLists.GetEntry(aCode);
     378               0 :     NS_ABORT_IF_FALSE(list, "no free list for pres arena object");
     379               0 :     NS_ABORT_IF_FALSE(list->mEntrySize > 0, "PresArena cannot free zero bytes");
     380                 : 
     381               0 :     char* p = reinterpret_cast<char*>(aPtr);
     382               0 :     char* limit = p + list->mEntrySize;
     383               0 :     for (; p < limit; p += sizeof(PRUword)) {
     384               0 :       *reinterpret_cast<PRUword*>(p) = ARENA_POISON;
     385                 :     }
     386                 : 
     387               0 :     list->mEntries.AppendElement(aPtr);
     388               0 :   }
     389                 : 
     390               0 :   size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     391                 :   {
     392               0 :     size_t n = aMallocSizeOf(this);
     393                 : 
     394                 :     // The first PLArena is within the PLArenaPool, i.e. within |this|, so we
     395                 :     // don't measure it.  Subsequent PLArenas are by themselves and must be
     396                 :     // measured.
     397               0 :     const PLArena *arena = mPool.first.next;
     398               0 :     while (arena) {
     399               0 :       n += aMallocSizeOf(arena);
     400               0 :       arena = arena->next;
     401                 :     }
     402               0 :     return n;
     403                 :   }
     404                 : };
     405                 : 
     406                 : size_t
     407               0 : nsPresArena::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     408                 : {
     409               0 :   return mState ? mState->SizeOfIncludingThis(aMallocSizeOf) : 0;
     410                 : }
     411                 : 
     412                 : #else
     413                 : // Stub implementation that forwards everything to malloc and does not
     414                 : // poison allocations (it still initializes the poison value though,
     415                 : // for external use through GetPoisonValue()).
     416                 : 
     417                 : struct nsPresArena::State
     418                 : {
     419                 : 
     420                 :   State()
     421                 :   {
     422                 :     PR_CallOnce(&ARENA_POISON_guard, ARENA_POISON_init);
     423                 :   }
     424                 : 
     425                 :   void* Allocate(PRUint32 /* unused */, size_t aSize)
     426                 :   {
     427                 :     return PR_Malloc(aSize);
     428                 :   }
     429                 : 
     430                 :   void Free(PRUint32 /* unused */, void* aPtr)
     431                 :   {
     432                 :     PR_Free(aPtr);
     433                 :   }
     434                 : };
     435                 : 
     436                 : size_t
     437                 : nsPresArena::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
     438                 : {
     439                 :   return 0;
     440                 : }
     441                 : 
     442                 : #endif // DEBUG_TRACEMALLOC_PRESARENA
     443                 : 
     444                 : // Public interface
     445               0 : nsPresArena::nsPresArena()
     446               0 :   : mState(new nsPresArena::State())
     447               0 : {}
     448                 : 
     449               0 : nsPresArena::~nsPresArena()
     450                 : {
     451               0 :   delete mState;
     452               0 : }
     453                 : 
     454                 : void*
     455               0 : nsPresArena::AllocateBySize(size_t aSize)
     456                 : {
     457                 :   return mState->Allocate(PRUint32(aSize) |
     458                 :                           PRUint32(nsQueryFrame::NON_FRAME_MARKER),
     459               0 :                           aSize);
     460                 : }
     461                 : 
     462                 : void
     463               0 : nsPresArena::FreeBySize(size_t aSize, void* aPtr)
     464                 : {
     465                 :   mState->Free(PRUint32(aSize) |
     466               0 :                PRUint32(nsQueryFrame::NON_FRAME_MARKER), aPtr);
     467               0 : }
     468                 : 
     469                 : void*
     470               0 : nsPresArena::AllocateByCode(nsQueryFrame::FrameIID aCode, size_t aSize)
     471                 : {
     472               0 :   return mState->Allocate(aCode, aSize);
     473                 : }
     474                 : 
     475                 : void
     476               0 : nsPresArena::FreeByCode(nsQueryFrame::FrameIID aCode, void* aPtr)
     477                 : {
     478               0 :   mState->Free(aCode, aPtr);
     479               0 : }
     480                 : 
     481                 : /* static */ PRUword
     482               0 : nsPresArena::GetPoisonValue()
     483                 : {
     484               0 :   return ARENA_POISON;
     485                 : }

Generated by: LCOV version 1.7