diff options
Diffstat (limited to 'xpcom/typelib/xpt/xpt_arena.cpp')
-rw-r--r-- | xpcom/typelib/xpt/xpt_arena.cpp | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/xpcom/typelib/xpt/xpt_arena.cpp b/xpcom/typelib/xpt/xpt_arena.cpp new file mode 100644 index 000000000..21be3c00b --- /dev/null +++ b/xpcom/typelib/xpt/xpt_arena.cpp @@ -0,0 +1,196 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/* Quick arena hack for xpt. */ + +/* XXX This exists because we don't want to drag in NSPR. It *seemed* +* to make more sense to write a quick and dirty arena than to clone +* plarena (like js/src did). This is not optimal, but it works. +*/ + +#include "xpt_arena.h" +#include "mozilla/MemoryReporting.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +/****************************************************/ + +/* Block header for each block in the arena */ +struct BLK_HDR +{ + BLK_HDR *next; +}; + +#define XPT_MIN_BLOCK_SIZE 32 + +/* XXX this is lame. Should clone the code to do this bitwise */ +#define ALIGN_RND(s,a) ((a)==1?(s):((((s)+(a)-1)/(a))*(a))) + +struct XPTSubArena +{ + BLK_HDR *first; + uint8_t *next; + size_t space; + size_t block_size; +}; + +struct XPTArena +{ + // We have one sub-arena with 8-byte alignment for most allocations, and + // one with 1-byte alignment for C string allocations. The latter sub-arena + // avoids significant amounts of unnecessary padding between C strings. + XPTSubArena subarena8; + XPTSubArena subarena1; +}; + +XPT_PUBLIC_API(XPTArena *) +XPT_NewArena(size_t block_size8, size_t block_size1) +{ + XPTArena *arena = static_cast<XPTArena*>(calloc(1, sizeof(XPTArena))); + if (arena) { + if (block_size8 < XPT_MIN_BLOCK_SIZE) + block_size8 = XPT_MIN_BLOCK_SIZE; + arena->subarena8.block_size = ALIGN_RND(block_size8, 8); + + if (block_size1 < XPT_MIN_BLOCK_SIZE) + block_size1 = XPT_MIN_BLOCK_SIZE; + arena->subarena1.block_size = block_size1; + } + return arena; +} + +static void +DestroySubArena(XPTSubArena *subarena) +{ + BLK_HDR* cur = subarena->first; + while (cur) { + BLK_HDR* next = cur->next; + free(cur); + cur = next; + } +} + +XPT_PUBLIC_API(void) +XPT_DestroyArena(XPTArena *arena) +{ + DestroySubArena(&arena->subarena8); + DestroySubArena(&arena->subarena1); + free(arena); +} + +/* +* Our alignment rule is that we always round up the size of each allocation +* so that the 'arena->next' pointer one will point to properly aligned space. +*/ + +XPT_PUBLIC_API(void *) +XPT_ArenaCalloc(XPTArena *arena, size_t size, size_t alignment) +{ + if (!size) + return NULL; + + if (!arena) { + XPT_ASSERT(0); + return NULL; + } + + XPTSubArena *subarena; + if (alignment == 8) { + subarena = &arena->subarena8; + } else if (alignment == 1) { + subarena = &arena->subarena1; + } else { + XPT_ASSERT(0); + return NULL; + } + + size_t bytes = ALIGN_RND(size, alignment); + + if (bytes > subarena->space) { + BLK_HDR* new_block; + size_t block_header_size = ALIGN_RND(sizeof(BLK_HDR), alignment); + size_t new_space = subarena->block_size; + + while (bytes > new_space - block_header_size) + new_space += subarena->block_size; + + new_block = + static_cast<BLK_HDR*>(calloc(new_space / alignment, alignment)); + if (!new_block) { + subarena->next = NULL; + subarena->space = 0; + return NULL; + } + + /* link block into the list of blocks for use when we destroy */ + new_block->next = subarena->first; + subarena->first = new_block; + + /* set info for current block */ + subarena->next = + reinterpret_cast<uint8_t*>(new_block) + block_header_size; + subarena->space = new_space - block_header_size; + +#ifdef DEBUG + /* mark block for corruption check */ + memset(subarena->next, 0xcd, subarena->space); +#endif + } + +#ifdef DEBUG + { + /* do corruption check */ + size_t i; + for (i = 0; i < bytes; ++i) { + XPT_ASSERT(subarena->next[i] == 0xcd); + } + /* we guarantee that the block will be filled with zeros */ + memset(subarena->next, 0, bytes); + } +#endif + + uint8_t* p = subarena->next; + subarena->next += bytes; + subarena->space -= bytes; + + return p; +} + +/***************************************************************************/ + +#ifdef DEBUG +XPT_PUBLIC_API(void) +XPT_AssertFailed(const char *s, const char *file, uint32_t lineno) +{ + fprintf(stderr, "Assertion failed: %s, file %s, line %d\n", + s, file, lineno); + abort(); +} +#endif + +static size_t +SizeOfSubArenaExcludingThis(XPTSubArena *subarena, MozMallocSizeOf mallocSizeOf) +{ + size_t n = 0; + + BLK_HDR* cur = subarena->first; + while (cur) { + BLK_HDR* next = cur->next; + n += mallocSizeOf(cur); + cur = next; + } + + return n; +} + +XPT_PUBLIC_API(size_t) +XPT_SizeOfArenaIncludingThis(XPTArena *arena, MozMallocSizeOf mallocSizeOf) +{ + size_t n = mallocSizeOf(arena); + n += SizeOfSubArenaExcludingThis(&arena->subarena8, mallocSizeOf); + n += SizeOfSubArenaExcludingThis(&arena->subarena1, mallocSizeOf); + return n; +} |