|
|
|
@ -67,6 +67,19 @@ static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static uint32_t *upb_cleanup_pointer(uintptr_t cleanup_metadata) { |
|
|
|
|
return (uint32_t *)(cleanup_metadata & ~0x1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool upb_cleanup_has_initial_block(uintptr_t cleanup_metadata) { |
|
|
|
|
return cleanup_metadata & 0x1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static uintptr_t upb_cleanup_metadata(uint32_t *cleanup, |
|
|
|
|
bool has_initial_block) { |
|
|
|
|
return (uintptr_t)cleanup | has_initial_block; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
upb_alloc upb_alloc_global = {&upb_global_allocfunc}; |
|
|
|
|
|
|
|
|
|
/* upb_arena ******************************************************************/ |
|
|
|
@ -112,7 +125,8 @@ static void upb_arena_addblock(upb_arena *a, upb_arena *root, void *ptr, |
|
|
|
|
|
|
|
|
|
a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); |
|
|
|
|
a->head.end = UPB_PTR_AT(block, size, char); |
|
|
|
|
a->cleanups = &block->cleanups; |
|
|
|
|
a->cleanup_metadata = upb_cleanup_metadata( |
|
|
|
|
&block->cleanups, upb_cleanup_has_initial_block(a->cleanup_metadata)); |
|
|
|
|
|
|
|
|
|
UPB_POISON_MEMORY_REGION(a->head.ptr, a->head.end - a->head.ptr); |
|
|
|
|
} |
|
|
|
@ -160,6 +174,7 @@ upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) { |
|
|
|
|
a->refcount = 1; |
|
|
|
|
a->freelist = NULL; |
|
|
|
|
a->freelist_tail = NULL; |
|
|
|
|
a->cleanup_metadata = upb_cleanup_metadata(NULL, false); |
|
|
|
|
|
|
|
|
|
upb_arena_addblock(a, a, mem, n); |
|
|
|
|
|
|
|
|
@ -187,7 +202,7 @@ upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) { |
|
|
|
|
a->head.ptr = mem; |
|
|
|
|
a->head.end = UPB_PTR_AT(mem, n - sizeof(*a), char); |
|
|
|
|
a->freelist = NULL; |
|
|
|
|
a->cleanups = NULL; |
|
|
|
|
a->cleanup_metadata = upb_cleanup_metadata(NULL, true); |
|
|
|
|
|
|
|
|
|
return a; |
|
|
|
|
} |
|
|
|
@ -222,15 +237,17 @@ void upb_arena_free(upb_arena *a) { |
|
|
|
|
|
|
|
|
|
bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { |
|
|
|
|
cleanup_ent *ent; |
|
|
|
|
uint32_t* cleanups = upb_cleanup_pointer(a->cleanup_metadata); |
|
|
|
|
|
|
|
|
|
if (!a->cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) { |
|
|
|
|
if (!cleanups || _upb_arenahas(a) < sizeof(cleanup_ent)) { |
|
|
|
|
if (!upb_arena_allocblock(a, 128)) return false; /* Out of memory. */ |
|
|
|
|
UPB_ASSERT(_upb_arenahas(a) >= sizeof(cleanup_ent)); |
|
|
|
|
cleanups = upb_cleanup_pointer(a->cleanup_metadata); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
a->head.end -= sizeof(cleanup_ent); |
|
|
|
|
ent = (cleanup_ent*)a->head.end; |
|
|
|
|
(*a->cleanups)++; |
|
|
|
|
(*cleanups)++; |
|
|
|
|
UPB_UNPOISON_MEMORY_REGION(ent, sizeof(cleanup_ent)); |
|
|
|
|
|
|
|
|
|
ent->cleanup = func; |
|
|
|
@ -239,11 +256,18 @@ bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { |
|
|
|
|
bool upb_arena_fuse(upb_arena *a1, upb_arena *a2) { |
|
|
|
|
upb_arena *r1 = arena_findroot(a1); |
|
|
|
|
upb_arena *r2 = arena_findroot(a2); |
|
|
|
|
|
|
|
|
|
if (r1 == r2) return; /* Already fused. */ |
|
|
|
|
if (r1 == r2) return true; /* Already fused. */ |
|
|
|
|
|
|
|
|
|
/* Do not fuse initial blocks since we cannot lifetime extend them. */ |
|
|
|
|
if (upb_cleanup_has_initial_block(r1->cleanup_metadata)) return false; |
|
|
|
|
if (upb_cleanup_has_initial_block(r2->cleanup_metadata)) return false; |
|
|
|
|
|
|
|
|
|
/* Only allow fuse with a common allocator */ |
|
|
|
|
if (r1->block_alloc != r2->block_alloc) return false; |
|
|
|
|
|
|
|
|
|
/* We want to join the smaller tree to the larger tree.
|
|
|
|
|
* So swap first if they are backwards. */ |
|
|
|
@ -261,4 +285,5 @@ void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { |
|
|
|
|
r1->freelist = r2->freelist; |
|
|
|
|
} |
|
|
|
|
r2->parent = r1; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|