197 lines
5.0 KiB
C++
197 lines
5.0 KiB
C++
/* -*- 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;
|
|
}
|