summaryrefslogtreecommitdiff
path: root/src/stack-allocator.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stack-allocator.c')
-rw-r--r--src/stack-allocator.c354
1 files changed, 0 insertions, 354 deletions
diff --git a/src/stack-allocator.c b/src/stack-allocator.c
deleted file mode 100644
index 55aeda9a..00000000
--- a/src/stack-allocator.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright 2016 WebAssembly Community Group participants
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "stack-allocator.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-#define TRACE_ALLOCATOR 0
-
-#if TRACE_ALLOCATOR
-#define TRACEF(...) fprintf(stderr, __VA_ARGS__)
-#else
-#define TRACEF(...)
-#endif
-
-#if WABT_STACK_ALLOCATOR_STATS
-#include <stdio.h>
-#endif /* WABT_STACK_ALLOCATOR_STATS */
-
-#define CHUNK_ALIGN 8
-#define CHUNK_SIZE (1024 * 1024)
-#define CHUNK_MAX_AVAIL (CHUNK_SIZE - sizeof(WabtStackAllocatorChunk))
-
-typedef struct StackAllocatorMark {
- WabtStackAllocatorChunk* chunk;
- void* chunk_current;
- void* last_allocation;
-} StackAllocatorMark;
-
-#ifndef NDEBUG
-static WabtBool is_power_of_two(uint32_t x) {
- return x && ((x & (x - 1)) == 0);
-}
-#endif /* NDEBUG */
-
-static void* align_up(void* p, size_t align) {
- return (void*)(((intptr_t)p + align - 1) & ~(align - 1));
-}
-
-static WabtBool allocation_in_chunk(WabtStackAllocatorChunk* chunk, void* p) {
- return p >= (void*)chunk && p < chunk->end;
-}
-
-static WabtStackAllocatorChunk* allocate_chunk(
- WabtStackAllocator* stack_allocator,
- size_t max_avail,
- const char* file,
- int line) {
- assert(max_avail < SIZE_MAX - sizeof(WabtStackAllocatorChunk));
- size_t real_size = max_avail + sizeof(WabtStackAllocatorChunk);
- /* common case of allocating a chunk of exactly CHUNK_SIZE */
- if (real_size == CHUNK_SIZE) {
- if (stack_allocator->next_free) {
- WabtStackAllocatorChunk* chunk = stack_allocator->next_free;
- stack_allocator->next_free = stack_allocator->next_free->next_free;
- return chunk;
- }
- }
-
- WabtStackAllocatorChunk* chunk =
- wabt_alloc(stack_allocator->fallback, real_size, CHUNK_ALIGN);
- if (!chunk) {
- if (stack_allocator->has_jmpbuf)
- longjmp(stack_allocator->jmpbuf, 1);
- WABT_FATAL("%s:%d: memory allocation failed\n", file, line);
- }
- /* use the same allocation for the WabtStackAllocatorChunk and its data. + 1
- * skips over the WabtStackAllocatorChunk */
- chunk->start = chunk + 1;
- chunk->current = chunk->start;
- chunk->end = (void*)((intptr_t)chunk->start + max_avail);
- chunk->prev = NULL;
-#if WABT_STACK_ALLOCATOR_STATS
- stack_allocator->chunk_alloc_count++;
- stack_allocator->total_chunk_bytes += CHUNK_SIZE;
-#endif /* WABT_STACK_ALLOCATOR_STATS */
- return chunk;
-}
-
-static void* stack_alloc(WabtAllocator* allocator,
- size_t size,
- size_t align,
- const char* file,
- int line) {
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
- assert(is_power_of_two(align));
- WabtStackAllocatorChunk* chunk = stack_allocator->last;
- assert(size < SIZE_MAX - align + 1);
- size_t alloc_size = size + align - 1;
- void* result;
- if (alloc_size >= CHUNK_MAX_AVAIL) {
- chunk = allocate_chunk(stack_allocator, alloc_size, file, line);
- result = align_up(chunk->current, align);
- assert((void*)((intptr_t)result + size) <= chunk->end);
- chunk->current = chunk->end;
- /* thread this chunk before first. There's no available space, so it's not
- worth considering. */
- stack_allocator->first->prev = chunk;
- stack_allocator->first = chunk;
- } else {
- assert(chunk);
-
- chunk->current = align_up(chunk->current, align);
- void* new_current = (void*)((intptr_t)chunk->current + size);
- if (new_current < chunk->end) {
- result = chunk->current;
- chunk->current = new_current;
- } else {
- chunk = allocate_chunk(stack_allocator, CHUNK_MAX_AVAIL, file, line);
- chunk->prev = stack_allocator->last;
- stack_allocator->last = chunk;
- chunk->current = align_up(chunk->current, align);
- result = chunk->current;
- chunk->current = (void*)((intptr_t)chunk->current + size);
- assert(chunk->current <= chunk->end);
- }
-
- stack_allocator->last_allocation = result;
- }
-
-#if TRACE_ALLOCATOR
- if (file) {
- TRACEF("%s:%d: stack_alloc(%" PRIzd ", align=%" PRIzd ") => %p\n", file,
- line, size, align, result);
- }
-#endif /* TRACE_ALLOCATOR */
-
-#if WABT_STACK_ALLOCATOR_STATS
- stack_allocator->alloc_count++;
- stack_allocator->total_alloc_bytes += size;
-#endif /* WABT_STACK_ALLOCATOR_STATS */
- return result;
-}
-
-static void* stack_realloc(WabtAllocator* allocator,
- void* p,
- size_t size,
- size_t align,
- const char* file,
- int line) {
- if (!p)
- return stack_alloc(allocator, size, align, file, line);
-
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
- /* TODO(binji): optimize */
- WabtStackAllocatorChunk* chunk = stack_allocator->last;
- while (chunk) {
- if (allocation_in_chunk(chunk, p))
- break;
- chunk = chunk->prev;
- }
-
- assert(chunk);
- void* result = stack_alloc(allocator, size, align, NULL, 0);
-
-#if TRACE_ALLOCATOR
- if (file) {
- TRACEF("%s:%d: stack_realloc(%p, %" PRIzd ", align=%" PRIzd ") => %p\n",
- file, line, p, size, align, result);
- }
-#endif /* TRACE_ALLOCATOR */
-
- /* We know that the previously allocated data was at most extending from |p|
- to the end of the chunk. So we can copy at most that many bytes, or the
- new size, whichever is less. Use memmove because the regions may be
- overlapping. */
- size_t old_max_size = (size_t)chunk->end - (size_t)p;
- size_t copy_size = size > old_max_size ? old_max_size : size;
- memmove(result, p, copy_size);
-#if WABT_STACK_ALLOCATOR_STATS
- /* count this is as a realloc, not an alloc */
- stack_allocator->alloc_count--;
- stack_allocator->realloc_count++;
- stack_allocator->total_alloc_bytes -= size;
- stack_allocator->total_realloc_bytes += size;
-#endif /* WABT_STACK_ALLOCATOR_STATS */
- return result;
-}
-
-static void stack_free(WabtAllocator* allocator,
- void* p,
- const char* file,
- int line) {
- if (!p)
- return;
-
- TRACEF("%s:%d: stack_free(%p)\n", file, line, p);
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
-
-#if WABT_STACK_ALLOCATOR_STATS
- stack_allocator->free_count++;
-#endif /* WABT_STACK_ALLOCATOR_STATS */
-
- if (p != stack_allocator->last_allocation)
- return;
-
- WabtStackAllocatorChunk* chunk = stack_allocator->last;
- assert(allocation_in_chunk(chunk, p));
- chunk->current = p;
-}
-
-static void stack_destroy(WabtAllocator* allocator) {
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
- /* destroy the free chunks */
- WabtStackAllocatorChunk* chunk = stack_allocator->next_free;
- while (chunk) {
- WabtStackAllocatorChunk* next_free = chunk->next_free;
- wabt_free(stack_allocator->fallback, chunk);
- chunk = next_free;
- }
-
- /* destroy the used chunks */
- chunk = stack_allocator->last;
- while (chunk) {
- WabtStackAllocatorChunk* prev = chunk->prev;
- wabt_free(stack_allocator->fallback, chunk);
- chunk = prev;
- }
-}
-
-static WabtAllocatorMark stack_mark(WabtAllocator* allocator) {
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
-
- /* allocate the space for the mark, but copy the current stack state now, so
- * when we reset we reset before the mark was allocated */
- StackAllocatorMark mark;
- mark.chunk = stack_allocator->last;
- mark.chunk_current = mark.chunk->current;
- mark.last_allocation = stack_allocator->last_allocation;
-
- StackAllocatorMark* allocated_mark = stack_alloc(
- allocator, sizeof(StackAllocatorMark), WABT_DEFAULT_ALIGN, NULL, 0);
-#if WABT_STACK_ALLOCATOR_STATS
- /* don't count this allocation */
- stack_allocator->alloc_count--;
- stack_allocator->total_alloc_bytes -= sizeof(StackAllocatorMark);
-#endif /* WABT_STACK_ALLOCATOR_STATS */
-
- *allocated_mark = mark;
- return allocated_mark;
-}
-
-static void stack_reset_to_mark(WabtAllocator* allocator,
- WabtAllocatorMark mark) {
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
- StackAllocatorMark* stack_mark = (StackAllocatorMark*)mark;
- WabtStackAllocatorChunk* chunk = stack_allocator->last;
- while (chunk && chunk != stack_mark->chunk) {
- WabtStackAllocatorChunk* prev = chunk->prev;
- /* reset this chunk for future use, and thread it into the free list */
- chunk->current = chunk->start;
- chunk->next_free = stack_allocator->next_free;
- stack_allocator->next_free = chunk;
- chunk = prev;
- }
-
- assert(chunk == stack_mark->chunk);
- stack_allocator->last = chunk;
- chunk->current = stack_mark->chunk_current;
- stack_allocator->last_allocation = stack_mark->last_allocation;
-}
-
-#if WABT_STACK_ALLOCATOR_STATS
-static const char* human_readable(size_t count) {
- /* printing a size_t in decimal requires ceil(sizeof(size_t) * 8 / log2(10))
- * characters. We want to add one comma for each group of three digits, so
- * the total number of characters needed is 4/3 multiplied by that value. For
- * a 64-bit size_t, this comes out to 27 (including the null-terminator). */
- static char buffer[27];
- int next_comma_in = 3;
- memset(buffer, ' ', sizeof(buffer));
- char* p = &buffer[sizeof(buffer) - 1];
- *p-- = '\0';
- if (count) {
- while (count) {
- if (next_comma_in == 0) {
- *p-- = ',';
- next_comma_in = 3;
- }
- assert(p >= buffer);
- size_t digit = count % 10;
- *p-- = '0' + digit;
- count /= 10;
- next_comma_in--;
- }
- } else {
- *p-- = '0';
- }
- return buffer;
-}
-#endif /* WABT_STACK_ALLOCATOR_STATS */
-
-static void stack_print_stats(WabtAllocator* allocator) {
-#if WABT_STACK_ALLOCATOR_STATS
-#define VALUE(name) human_readable(stack_allocator->name)
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
- printf("STACK ALLOCATOR STATS:\n");
- printf("===============================================\n");
- printf("chunk_alloc_count: %s\n", VALUE(chunk_alloc_count));
- printf("alloc_count: %s\n", VALUE(alloc_count));
- printf("realloc_count: %s\n", VALUE(realloc_count));
- printf("free_count: %s\n", VALUE(free_count));
- printf("total_chunk_bytes: %s\n", VALUE(total_chunk_bytes));
- printf("total_alloc_bytes: %s\n", VALUE(total_alloc_bytes));
- printf("total_realloc_bytes: %s\n", VALUE(total_realloc_bytes));
-#undef VALUE
-#endif /* WABT_STACK_ALLOCATOR_STATS */
-}
-
-static int stack_setjmp_handler(WabtAllocator* allocator) {
- WabtStackAllocator* stack_allocator = (WabtStackAllocator*)allocator;
- stack_allocator->has_jmpbuf = WABT_TRUE;
- return setjmp(stack_allocator->jmpbuf);
-}
-
-WabtResult wabt_init_stack_allocator(WabtStackAllocator* stack_allocator,
- WabtAllocator* fallback) {
- WABT_ZERO_MEMORY(*stack_allocator);
- stack_allocator->allocator.alloc = stack_alloc;
- stack_allocator->allocator.realloc = stack_realloc;
- stack_allocator->allocator.free = stack_free;
- stack_allocator->allocator.destroy = stack_destroy;
- stack_allocator->allocator.mark = stack_mark;
- stack_allocator->allocator.reset_to_mark = stack_reset_to_mark;
- stack_allocator->allocator.print_stats = stack_print_stats;
- stack_allocator->allocator.setjmp_handler = stack_setjmp_handler;
- stack_allocator->fallback = fallback;
-
- WabtStackAllocatorChunk* chunk =
- allocate_chunk(stack_allocator, CHUNK_MAX_AVAIL, __FILE__, __LINE__);
- chunk->prev = NULL;
- stack_allocator->first = stack_allocator->last = chunk;
- return WABT_OK;
-}
-
-void wabt_destroy_stack_allocator(WabtStackAllocator* stack_allocator) {
- stack_destroy((WabtAllocator*)stack_allocator);
-}