2009-08-17 20:21:06 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* vim: set ts=2 sw=2 et tw=78:
|
2012-05-21 04:12:37 -07:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2009-08-17 20:21:06 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* arena allocation for the frame tree and closely-related objects */
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
// Even on 32-bit systems, we allocate objects from the frame arena
|
|
|
|
// that require 8-byte alignment. The cast to uintptr_t is needed
|
|
|
|
// because plarena isn't as careful about mask construction as it
|
|
|
|
// ought to be.
|
|
|
|
#define ALIGN_SHIFT 3
|
|
|
|
#define PL_ARENA_CONST_ALIGN_MASK ((uintptr_t(1) << ALIGN_SHIFT) - 1)
|
|
|
|
#include "plarena.h"
|
|
|
|
// plarena.h needs to be included first to make it use the above
|
|
|
|
// PL_ARENA_CONST_ALIGN_MASK in this file.
|
|
|
|
|
2009-08-17 20:21:06 -07:00
|
|
|
#include "nsPresArena.h"
|
|
|
|
#include "nsCRT.h"
|
|
|
|
#include "nsDebug.h"
|
2009-11-17 11:17:20 -08:00
|
|
|
#include "prinit.h"
|
2012-06-06 10:29:16 -07:00
|
|
|
#include "nsArenaMemoryStats.h"
|
2009-12-01 14:48:23 -08:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsServiceManagerUtils.h"
|
|
|
|
#include "nsPrintfCString.h"
|
2012-08-29 18:27:01 -07:00
|
|
|
|
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
|
|
#include "nsICrashReporter.h"
|
2009-12-01 14:48:23 -08:00
|
|
|
#endif
|
|
|
|
|
2009-11-17 11:17:20 -08:00
|
|
|
#ifdef _WIN32
|
|
|
|
# include <windows.h>
|
2011-02-15 14:10:16 -08:00
|
|
|
#elif !defined(__OS2__)
|
2009-11-17 11:17:20 -08:00
|
|
|
# include <unistd.h>
|
|
|
|
# include <sys/mman.h>
|
|
|
|
# ifndef MAP_ANON
|
|
|
|
# ifdef MAP_ANONYMOUS
|
|
|
|
# define MAP_ANON MAP_ANONYMOUS
|
|
|
|
# else
|
|
|
|
# error "Don't know how to get anonymous memory"
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2009-09-14 17:26:08 -07:00
|
|
|
// Size to use for PLArena block allocations.
|
2011-08-21 23:34:11 -07:00
|
|
|
static const size_t ARENA_PAGE_SIZE = 8192;
|
2009-09-14 14:29:56 -07:00
|
|
|
|
2009-11-17 11:17:20 -08:00
|
|
|
// Freed memory is filled with a poison value, which we arrange to
|
|
|
|
// form a pointer either to an always-unmapped region of the address
|
|
|
|
// space, or to a page that has been reserved and rendered
|
|
|
|
// inaccessible via OS primitives. See tests/TestPoisonArea.cpp for
|
|
|
|
// extensive discussion of the requirements for this page. The code
|
|
|
|
// from here to 'class FreeList' needs to be kept in sync with that
|
|
|
|
// file.
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
static void *
|
2012-04-11 17:17:44 -07:00
|
|
|
ReserveRegion(uintptr_t region, uintptr_t size)
|
2009-11-17 11:17:20 -08:00
|
|
|
{
|
|
|
|
return VirtualAlloc((void *)region, size, MEM_RESERVE, PAGE_NOACCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-04-11 17:17:44 -07:00
|
|
|
ReleaseRegion(void *region, uintptr_t size)
|
2009-11-17 11:17:20 -08:00
|
|
|
{
|
|
|
|
VirtualFree(region, size, MEM_RELEASE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2012-04-11 17:17:44 -07:00
|
|
|
ProbeRegion(uintptr_t region, uintptr_t size)
|
2009-11-17 11:17:20 -08:00
|
|
|
{
|
|
|
|
SYSTEM_INFO sinfo;
|
|
|
|
GetSystemInfo(&sinfo);
|
2012-04-11 17:17:44 -07:00
|
|
|
if (region >= (uintptr_t)sinfo.lpMaximumApplicationAddress &&
|
|
|
|
region + size >= (uintptr_t)sinfo.lpMaximumApplicationAddress) {
|
2009-11-17 11:17:20 -08:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-11 17:17:44 -07:00
|
|
|
static uintptr_t
|
2009-11-17 11:17:20 -08:00
|
|
|
GetDesiredRegionSize()
|
|
|
|
{
|
|
|
|
SYSTEM_INFO sinfo;
|
|
|
|
GetSystemInfo(&sinfo);
|
|
|
|
return sinfo.dwAllocationGranularity;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RESERVE_FAILED 0
|
|
|
|
|
2011-02-15 14:10:16 -08:00
|
|
|
#elif defined(__OS2__)
|
|
|
|
static void *
|
2012-04-11 17:17:44 -07:00
|
|
|
ReserveRegion(uintptr_t region, uintptr_t size)
|
2011-02-15 14:10:16 -08:00
|
|
|
{
|
|
|
|
// OS/2 doesn't support allocation at an arbitrary address,
|
|
|
|
// so return an address that is known to be invalid.
|
|
|
|
return (void*)0xFFFD0000;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-04-11 17:17:44 -07:00
|
|
|
ReleaseRegion(void *region, uintptr_t size)
|
2011-02-15 14:10:16 -08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2012-04-11 17:17:44 -07:00
|
|
|
ProbeRegion(uintptr_t region, uintptr_t size)
|
2011-02-15 14:10:16 -08:00
|
|
|
{
|
|
|
|
// There's no reliable way to probe an address in the system
|
|
|
|
// arena other than by touching it and seeing if a trap occurs.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-04-11 17:17:44 -07:00
|
|
|
static uintptr_t
|
2011-02-15 14:10:16 -08:00
|
|
|
GetDesiredRegionSize()
|
|
|
|
{
|
|
|
|
// Page size is fixed at 4k.
|
|
|
|
return 0x1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RESERVE_FAILED 0
|
|
|
|
|
2009-11-17 11:17:20 -08:00
|
|
|
#else // Unix
|
|
|
|
|
|
|
|
static void *
|
2012-04-11 17:17:44 -07:00
|
|
|
ReserveRegion(uintptr_t region, uintptr_t size)
|
2009-11-17 11:17:20 -08:00
|
|
|
{
|
2012-10-18 12:04:20 -07:00
|
|
|
return mmap(reinterpret_cast<void*>(region), size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
|
2009-11-17 11:17:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-04-11 17:17:44 -07:00
|
|
|
ReleaseRegion(void *region, uintptr_t size)
|
2009-11-17 11:17:20 -08:00
|
|
|
{
|
2012-10-18 12:04:20 -07:00
|
|
|
munmap(region, size);
|
2009-11-17 11:17:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2012-04-11 17:17:44 -07:00
|
|
|
ProbeRegion(uintptr_t region, uintptr_t size)
|
2009-11-17 11:17:20 -08:00
|
|
|
{
|
2012-10-18 12:04:20 -07:00
|
|
|
if (madvise(reinterpret_cast<void*>(region), size, MADV_NORMAL)) {
|
2009-11-17 11:17:20 -08:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-11 17:17:44 -07:00
|
|
|
static uintptr_t
|
2009-11-17 11:17:20 -08:00
|
|
|
GetDesiredRegionSize()
|
|
|
|
{
|
|
|
|
return sysconf(_SC_PAGESIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RESERVE_FAILED MAP_FAILED
|
|
|
|
|
|
|
|
#endif // system dependencies
|
|
|
|
|
2012-04-11 17:17:44 -07:00
|
|
|
PR_STATIC_ASSERT(sizeof(uintptr_t) == 4 || sizeof(uintptr_t) == 8);
|
|
|
|
PR_STATIC_ASSERT(sizeof(uintptr_t) == sizeof(void *));
|
2009-11-17 11:17:20 -08:00
|
|
|
|
2012-04-11 17:17:44 -07:00
|
|
|
static uintptr_t
|
|
|
|
ReservePoisonArea(uintptr_t rgnsize)
|
2009-11-17 11:17:20 -08:00
|
|
|
{
|
2012-04-11 17:17:44 -07:00
|
|
|
if (sizeof(uintptr_t) == 8) {
|
2009-11-17 11:17:20 -08:00
|
|
|
// Use the hardware-inaccessible region.
|
|
|
|
// We have to avoid 64-bit constants and shifts by 32 bits, since this
|
|
|
|
// code is compiled in 32-bit mode, although it is never executed there.
|
2009-12-01 14:48:23 -08:00
|
|
|
return
|
2012-04-11 17:17:44 -07:00
|
|
|
(((uintptr_t(0x7FFFFFFFu) << 31) << 1 | uintptr_t(0xF0DEAFFFu))
|
2009-12-01 14:48:23 -08:00
|
|
|
& ~(rgnsize-1));
|
2009-11-17 11:17:20 -08:00
|
|
|
|
|
|
|
} else {
|
2009-11-30 08:51:07 -08:00
|
|
|
// First see if we can allocate the preferred poison address from the OS.
|
2012-04-11 17:17:44 -07:00
|
|
|
uintptr_t candidate = (0xF0DEAFFF & ~(rgnsize-1));
|
2009-11-30 08:51:07 -08:00
|
|
|
void *result = ReserveRegion(candidate, rgnsize);
|
|
|
|
if (result == (void *)candidate) {
|
|
|
|
// success - inaccessible page allocated
|
2009-12-01 14:48:23 -08:00
|
|
|
return candidate;
|
2009-11-30 08:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// That didn't work, so see if the preferred address is within a range
|
|
|
|
// of permanently inacessible memory.
|
|
|
|
if (ProbeRegion(candidate, rgnsize)) {
|
|
|
|
// success - selected page cannot be usable memory
|
|
|
|
if (result != RESERVE_FAILED)
|
|
|
|
ReleaseRegion(result, rgnsize);
|
2009-12-01 14:48:23 -08:00
|
|
|
return candidate;
|
2009-11-30 08:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// The preferred address is already in use. Did the OS give us a
|
|
|
|
// consolation prize?
|
|
|
|
if (result != RESERVE_FAILED) {
|
2012-04-11 17:17:44 -07:00
|
|
|
return uintptr_t(result);
|
2009-11-30 08:51:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// It didn't, so try to allocate again, without any constraint on
|
|
|
|
// the address.
|
|
|
|
result = ReserveRegion(0, rgnsize);
|
|
|
|
if (result != RESERVE_FAILED) {
|
2012-04-11 17:17:44 -07:00
|
|
|
return uintptr_t(result);
|
2009-11-17 11:17:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_RUNTIMEABORT("no usable poison region identified");
|
2009-12-01 14:48:23 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-11 17:17:44 -07:00
|
|
|
static uintptr_t ARENA_POISON;
|
2009-12-01 14:48:23 -08:00
|
|
|
static PRCallOnceType ARENA_POISON_guard;
|
|
|
|
|
|
|
|
static PRStatus
|
|
|
|
ARENA_POISON_init()
|
|
|
|
{
|
2012-04-11 17:17:44 -07:00
|
|
|
uintptr_t rgnsize = GetDesiredRegionSize();
|
|
|
|
uintptr_t rgnbase = ReservePoisonArea(rgnsize);
|
2009-12-01 14:48:23 -08:00
|
|
|
|
|
|
|
if (rgnsize == 0) // can't happen
|
2009-11-17 11:17:20 -08:00
|
|
|
return PR_FAILURE;
|
2009-12-01 14:48:23 -08:00
|
|
|
|
|
|
|
ARENA_POISON = rgnbase + rgnsize/2 - 1;
|
|
|
|
|
|
|
|
#ifdef MOZ_CRASHREPORTER
|
|
|
|
nsCOMPtr<nsICrashReporter> cr =
|
|
|
|
do_GetService("@mozilla.org/toolkit/crash-reporter;1");
|
2011-09-28 23:19:26 -07:00
|
|
|
bool enabled;
|
2009-12-01 14:48:23 -08:00
|
|
|
if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) {
|
|
|
|
cr->AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"),
|
2012-08-22 08:56:38 -07:00
|
|
|
nsPrintfCString("%.16llx", uint64_t(rgnbase)));
|
2009-12-01 14:48:23 -08:00
|
|
|
cr->AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"),
|
2012-08-22 08:56:38 -07:00
|
|
|
nsPrintfCString("%lu", uint32_t(rgnsize)));
|
2009-11-17 11:17:20 -08:00
|
|
|
}
|
2009-12-01 14:48:23 -08:00
|
|
|
#endif
|
|
|
|
return PR_SUCCESS;
|
2009-11-17 11:17:20 -08:00
|
|
|
}
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
nsPresArena::nsPresArena()
|
2009-09-15 15:00:04 -07:00
|
|
|
{
|
2013-04-15 13:00:06 -07:00
|
|
|
mFreeLists.Init();
|
|
|
|
PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
|
|
|
|
PR_CallOnce(&ARENA_POISON_guard, ARENA_POISON_init);
|
2009-11-17 11:17:20 -08:00
|
|
|
}
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
nsPresArena::~nsPresArena()
|
|
|
|
{
|
2013-02-14 15:50:11 -08:00
|
|
|
#if defined(MOZ_HAVE_MEM_CHECKS)
|
2013-04-15 13:00:06 -07:00
|
|
|
mFreeLists.EnumerateEntries(UnpoisonFreeList, nullptr);
|
2013-02-02 17:04:29 -08:00
|
|
|
#endif
|
2013-04-15 13:00:06 -07:00
|
|
|
PL_FinishArenaPool(&mPool);
|
|
|
|
}
|
2009-08-17 20:21:06 -07:00
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
NS_HIDDEN_(void*)
|
2013-04-15 13:00:06 -07:00
|
|
|
nsPresArena::Allocate(uint32_t aCode, size_t aSize)
|
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aSize > 0, "PresArena cannot allocate zero bytes");
|
2009-08-17 20:21:06 -07:00
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
// We only hand out aligned sizes
|
|
|
|
aSize = PL_ARENA_ALIGN(&mPool, aSize);
|
2009-08-17 20:21:06 -07:00
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
// If there is no free-list entry for this type already, we have
|
|
|
|
// to create one now, to record its size.
|
|
|
|
FreeList* list = mFreeLists.PutEntry(aCode);
|
2009-09-14 14:29:56 -07:00
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
nsTArray<void*>::index_type len = list->mEntries.Length();
|
|
|
|
if (list->mEntrySize == 0) {
|
|
|
|
NS_ABORT_IF_FALSE(len == 0, "list with entries but no recorded size");
|
|
|
|
list->mEntrySize = aSize;
|
|
|
|
} else {
|
|
|
|
NS_ABORT_IF_FALSE(list->mEntrySize == aSize,
|
|
|
|
"different sizes for same object type code");
|
|
|
|
}
|
2009-09-15 15:00:04 -07:00
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
void* result;
|
|
|
|
if (len > 0) {
|
|
|
|
// LIFO behavior for best cache utilization
|
|
|
|
result = list->mEntries.ElementAt(len - 1);
|
|
|
|
list->mEntries.RemoveElementAt(len - 1);
|
2013-02-14 15:50:11 -08:00
|
|
|
#if defined(DEBUG)
|
2013-04-15 13:00:06 -07:00
|
|
|
{
|
|
|
|
MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
|
|
|
|
char* p = reinterpret_cast<char*>(result);
|
|
|
|
char* limit = p + list->mEntrySize;
|
|
|
|
for (; p < limit; p += sizeof(uintptr_t)) {
|
|
|
|
uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
|
|
|
|
NS_ABORT_IF_FALSE(val == ARENA_POISON,
|
|
|
|
nsPrintfCString("PresArena: poison overwritten; "
|
|
|
|
"wanted %.16llx "
|
|
|
|
"found %.16llx "
|
|
|
|
"errors in bits %.16llx",
|
|
|
|
uint64_t(ARENA_POISON),
|
|
|
|
uint64_t(val),
|
|
|
|
uint64_t(ARENA_POISON ^ val)
|
|
|
|
).get());
|
2009-09-15 15:00:04 -07:00
|
|
|
}
|
2012-11-07 11:55:53 -08:00
|
|
|
}
|
2013-04-15 13:00:06 -07:00
|
|
|
#endif
|
|
|
|
MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
|
2009-08-17 20:21:06 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
// Allocate a new chunk from the arena
|
|
|
|
list->mEntriesEverAllocated++;
|
|
|
|
PL_ARENA_ALLOCATE(result, &mPool, aSize);
|
|
|
|
if (!result) {
|
|
|
|
NS_RUNTIMEABORT("out of memory");
|
2009-08-17 20:21:06 -07:00
|
|
|
}
|
2013-04-15 13:00:06 -07:00
|
|
|
return result;
|
|
|
|
}
|
2010-05-31 19:19:35 -07:00
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
NS_HIDDEN_(void)
|
2013-04-15 13:00:06 -07:00
|
|
|
nsPresArena::Free(uint32_t aCode, void* aPtr)
|
|
|
|
{
|
|
|
|
// Try to recycle this entry.
|
|
|
|
FreeList* list = mFreeLists.GetEntry(aCode);
|
|
|
|
NS_ABORT_IF_FALSE(list, "no free list for pres arena object");
|
|
|
|
NS_ABORT_IF_FALSE(list->mEntrySize > 0, "PresArena cannot free zero bytes");
|
|
|
|
|
|
|
|
char* p = reinterpret_cast<char*>(aPtr);
|
|
|
|
char* limit = p + list->mEntrySize;
|
|
|
|
for (; p < limit; p += sizeof(uintptr_t)) {
|
|
|
|
*reinterpret_cast<uintptr_t*>(p) = ARENA_POISON;
|
2012-06-05 09:33:54 -07:00
|
|
|
}
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
|
|
|
|
list->mEntries.AppendElement(aPtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ size_t
|
|
|
|
nsPresArena::SizeOfFreeListEntryExcludingThis(
|
|
|
|
FreeList* aEntry, nsMallocSizeOfFun aMallocSizeOf, void*)
|
|
|
|
{
|
|
|
|
return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct EnumerateData {
|
|
|
|
nsArenaMemoryStats* stats;
|
|
|
|
size_t total;
|
|
|
|
};
|
|
|
|
|
|
|
|
#if defined(MOZ_HAVE_MEM_CHECKS)
|
|
|
|
/* static */ PLDHashOperator
|
|
|
|
nsPresArena::UnpoisonFreeList(FreeList* aEntry, void*)
|
|
|
|
{
|
|
|
|
nsTArray<void*>::index_type len;
|
|
|
|
while ((len = aEntry->mEntries.Length())) {
|
|
|
|
void* result = aEntry->mEntries.ElementAt(len - 1);
|
|
|
|
aEntry->mEntries.RemoveElementAt(len - 1);
|
|
|
|
MOZ_MAKE_MEM_UNDEFINED(result, aEntry->mEntrySize);
|
2010-05-31 19:19:35 -07:00
|
|
|
}
|
2013-04-15 13:00:06 -07:00
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
#endif
|
2012-06-06 10:29:16 -07:00
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
/* static */ PLDHashOperator
|
|
|
|
nsPresArena::FreeListEnumerator(FreeList* aEntry, void* aData)
|
|
|
|
{
|
|
|
|
EnumerateData* data = static_cast<EnumerateData*>(aData);
|
|
|
|
// Note that we're not measuring the size of the entries on the free
|
|
|
|
// list here. The free list knows how many objects we've allocated
|
|
|
|
// ever (which includes any objects that may be on the FreeList's
|
|
|
|
// |mEntries| at this point) and we're using that to determine the
|
|
|
|
// total size of objects allocated with a given ID.
|
|
|
|
size_t totalSize = aEntry->mEntrySize * aEntry->mEntriesEverAllocated;
|
|
|
|
size_t* p;
|
|
|
|
|
|
|
|
switch (NS_PTR_TO_INT32(aEntry->mKey)) {
|
|
|
|
#define FRAME_ID(classname) \
|
|
|
|
case nsQueryFrame::classname##_id: \
|
|
|
|
p = &data->stats->FRAME_ID_STAT_FIELD(classname); \
|
|
|
|
break;
|
2012-06-06 10:29:16 -07:00
|
|
|
#include "nsFrameIdList.h"
|
|
|
|
#undef FRAME_ID
|
2013-04-15 13:00:06 -07:00
|
|
|
case nsLineBox_id:
|
|
|
|
p = &data->stats->mLineBoxes;
|
|
|
|
break;
|
|
|
|
case nsRuleNode_id:
|
|
|
|
p = &data->stats->mRuleNodes;
|
|
|
|
break;
|
|
|
|
case nsStyleContext_id:
|
|
|
|
p = &data->stats->mStyleContexts;
|
|
|
|
break;
|
|
|
|
default:
|
2012-06-06 10:29:16 -07:00
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
*p += totalSize;
|
|
|
|
data->total += totalSize;
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
2010-05-31 19:19:35 -07:00
|
|
|
|
2012-06-06 10:29:16 -07:00
|
|
|
void
|
|
|
|
nsPresArena::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
|
|
|
|
nsArenaMemoryStats* aArenaStats)
|
2011-12-08 21:01:52 -08:00
|
|
|
{
|
2013-04-15 13:00:06 -07:00
|
|
|
// We do a complicated dance here because we want to measure the
|
|
|
|
// space taken up by the different kinds of objects in the arena,
|
|
|
|
// but we don't have pointers to those objects. And even if we did,
|
|
|
|
// we wouldn't be able to use aMallocSizeOf on them, since they were
|
|
|
|
// allocated out of malloc'd chunks of memory. So we compute the
|
|
|
|
// size of the arena as known by malloc and we add up the sizes of
|
|
|
|
// all the objects that we care about. Subtracting these two
|
|
|
|
// quantities gives us a catch-all "other" number, which includes
|
|
|
|
// slop in the arena itself as well as the size of objects that
|
|
|
|
// we've not measured explicitly.
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
size_t mallocSize = PL_SizeOfArenaPoolExcludingPool(&mPool, aMallocSizeOf);
|
|
|
|
mallocSize += mFreeLists.SizeOfExcludingThis(SizeOfFreeListEntryExcludingThis,
|
|
|
|
aMallocSizeOf);
|
|
|
|
|
2013-04-15 13:00:06 -07:00
|
|
|
EnumerateData data = { aArenaStats, 0 };
|
|
|
|
mFreeLists.EnumerateEntries(FreeListEnumerator, &data);
|
|
|
|
aArenaStats->mOther = mallocSize - data.total;
|
2009-08-17 20:21:06 -07:00
|
|
|
}
|
|
|
|
|
2012-04-11 17:17:44 -07:00
|
|
|
/* static */ uintptr_t
|
2011-03-17 20:14:31 -07:00
|
|
|
nsPresArena::GetPoisonValue()
|
|
|
|
{
|
|
|
|
return ARENA_POISON;
|
|
|
|
}
|