diff --git a/include/vm/heap.h b/include/vm/heap.h index 5c0f06d..b692745 100644 --- a/include/vm/heap.h +++ b/include/vm/heap.h @@ -58,10 +58,21 @@ void exit_unref(int slot); bool heap_index_valid(int index); bool page_index_valid(int index); +bool string_index_valid(int index); struct page *heap_get_page(int index); +struct string *heap_get_string(int index); void heap_set_page(int slot, struct page *page); +/* + * Guarantee `headroom` free slots are available on the heap. + * + * XXX: this is a hack to fix an issue with HLL calls where a pointer into the + * heap can be made invalid by a heap reallocation triggered within the + * body of the HLL function. + */ +void heap_guarantee(unsigned headroom); + #ifdef VM_PRIVATE extern int32_t *heap_free_stack; diff --git a/src/ffi.c b/src/ffi.c index 7403f09..2f8c03b 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -54,6 +54,11 @@ void hll_call(int libno, int fno) if (!fun->fun) VM_ERROR("Unimplemented HLL function: %s.%s", ain->libraries[libno].name, f->name); + // XXX: Try to prevent the heap from being reallocated mid-call. + // This only works to the extent that HLL functions can guarantee + // no more than 64 heap allocations occur within the call... + heap_guarantee(64); + void *args[HLL_MAX_ARGS]; void *ptrs[HLL_MAX_ARGS]; for (int i = f->nr_arguments - 1; i >= 0; i--) { diff --git a/src/heap.c b/src/heap.c index 3c28896..4f7c60a 100644 --- a/src/heap.c +++ b/src/heap.c @@ -45,6 +45,30 @@ static const char *vm_ptrtype_string(enum vm_pointer_type type) { return "INVALID POINTER TYPE"; } +static void heap_grow(size_t new_size) +{ + heap = xrealloc(heap, sizeof(struct vm_pointer) * new_size); + heap_free_stack = xrealloc(heap_free_stack, sizeof(int32_t) * new_size); + for (size_t i = heap_size; i < new_size; i++) { + heap[i].ref = 0; + heap_free_stack[i] = i; + } + heap_size = new_size; +} + +void heap_guarantee(unsigned headroom) +{ + if (heap_size - heap_free_ptr >= headroom) + return; + + size_t new_size = heap_size; + while (new_size - heap_free_ptr < headroom) { + new_size += HEAP_ALLOC_STEP; + } + + heap_grow(new_size); +} + void heap_init(void) { if (!heap) { @@ -63,15 +87,8 @@ void heap_init(void) int32_t heap_alloc_slot(enum vm_pointer_type type) { - // grow heap if needed if (heap_free_ptr >= heap_size) { - heap = xrealloc(heap, sizeof(struct vm_pointer) * (heap_size+HEAP_ALLOC_STEP)); - heap_free_stack = xrealloc(heap_free_stack, sizeof(int32_t) * (heap_size+HEAP_ALLOC_STEP)); - for (size_t i = heap_size; i < heap_size+HEAP_ALLOC_STEP; i++) { - heap[i].ref = 0; - heap_free_stack[i] = i; - } - heap_size += HEAP_ALLOC_STEP; + heap_grow(heap_size+HEAP_ALLOC_STEP); } int32_t slot = heap_free_stack[heap_free_ptr++]; @@ -80,6 +97,7 @@ int32_t heap_alloc_slot(enum vm_pointer_type type) #ifdef DEBUG_HEAP heap[slot].alloc_addr = instr_ptr; heap[slot].ref_addr = 0; + heap[slot].free_addr = 0; #endif return slot; } @@ -183,6 +201,11 @@ bool page_index_valid(int index) return heap_index_valid(index) && heap[index].type == VM_PAGE; } +bool string_index_valid(int index) +{ + return heap_index_valid(index) && heap[index].type == VM_STRING; +} + struct page *heap_get_page(int index) { if (!page_index_valid(index)) @@ -190,6 +213,13 @@ struct page *heap_get_page(int index) return heap[index].page; } +struct string *heap_get_string(int index) +{ + if (!string_index_valid(index)) + VM_ERROR("Invalid string index: %d", index); + return heap[index].s; +} + void heap_set_page(int slot, struct page *page) { heap[slot].page = page;