diff --git a/include/vm/heap.h b/include/vm/heap.h index 9eed1a3..6da37b7 100644 --- a/include/vm/heap.h +++ b/include/vm/heap.h @@ -78,15 +78,6 @@ int32_t heap_alloc_string(struct string *s); void heap_describe_slot(int slot); -/* - * 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 uint32_t heap_next_seq; diff --git a/src/ffi.c b/src/ffi.c index 5215b4b..28a2a59 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -303,13 +303,13 @@ 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]; + // Copy reference arguments to the stack to protect against heap + // reallocation during HLL calls. + void *heap_ptrs[HLL_MAX_ARGS]; + int heap_slots[HLL_MAX_ARGS]; + for (int i = f->nr_arguments - 1; i >= 0; i--) { switch (f->arguments[i].type.data) { case AIN_REF_INT: @@ -330,7 +330,9 @@ void hll_call(int libno, int fno) break; case AIN_REF_STRING: stack_ptr--; - ptrs[i] = &heap[stack[stack_ptr].i].s; + heap_slots[i] = stack[stack_ptr].i; + heap_ptrs[i] = heap[stack[stack_ptr].i].s; + ptrs[i] = &heap_ptrs[i]; args[i] = &ptrs[i]; break; case AIN_STRUCT: @@ -341,7 +343,9 @@ void hll_call(int libno, int fno) case AIN_REF_STRUCT: case AIN_REF_ARRAY_TYPE: stack_ptr--; - ptrs[i] = &heap[stack[stack_ptr].i].page; + heap_slots[i] = stack[stack_ptr].i; + heap_ptrs[i] = heap[stack[stack_ptr].i].page; + ptrs[i] = &heap_ptrs[i]; args[i] = &ptrs[i]; break; default: @@ -370,9 +374,13 @@ void hll_call(int libno, int fno) j++; break; case AIN_REF_STRING: + heap[heap_slots[i]].s = heap_ptrs[i]; + break; case AIN_REF_STRUCT: - case AIN_REF_FUNC_TYPE: case AIN_REF_ARRAY_TYPE: + heap[heap_slots[i]].page = heap_ptrs[i]; + break; + case AIN_REF_FUNC_TYPE: break; case AIN_ARRAY_TYPE: // Sys41VM doesn't make a copy when passing an array by value. diff --git a/src/heap.c b/src/heap.c index 5f371ab..99ebb4d 100644 --- a/src/heap.c +++ b/src/heap.c @@ -60,19 +60,6 @@ void heap_grow(size_t new_size) 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) {