diff --git a/src/runtime.c b/src/runtime.c index 9473eb4..0d1f45d 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -83,9 +83,6 @@ static const char* info_runtime = "runtime"; #define POOL_GET1(offset) \ u6a_vm_pool_get1(offset).fn; \ u6a_vm_pool_free(offset) -#define POOL_GET2(offset) \ - u6a_vm_pool_get2(offset); \ - u6a_vm_pool_free(offset) static inline bool read_bc_header(struct u6a_bc_header* restrict header, FILE* restrict input_stream) { @@ -108,6 +105,13 @@ read_bc_header(struct u6a_bc_header* restrict header, FILE* restrict input_strea return true; } +static inline void +vm_var_fn_addref(struct u6a_vm_var_fn var) { + if (var.token.fn & U6A_VM_FN_REF) { + u6a_vm_pool_addref(var.ref); + } +} + static inline void vm_var_fn_free(struct u6a_vm_var_fn var) { if (var.token.fn & U6A_VM_FN_REF) { @@ -221,16 +225,15 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { case u6a_vf_s1: ACC_FN_REF(u6a_vf_s2, u6a_vm_pool_fill2(func.ref, arg)); break; - ACC_FN_REF(u6a_vf_d1_c, u6a_vm_pool_alloc1(arg)); case u6a_vf_s2: if (ins++ - text == 0x03) { STACK_PUSH3(arg, u6a_vm_pool_get2(func.ref)); } else { STACK_PUSH4(U6A_VM_VAR_FN_REF(u6a_vf_j, ins - text), arg, u6a_vm_pool_get2(func.ref)); } - u6a_vm_pool_free(func.ref); + vm_var_fn_addref(arg); ins = text; - goto do_apply; + continue; case u6a_vf_k: ACC_FN_REF(u6a_vf_k1, u6a_vm_pool_alloc1(arg)); break; @@ -271,8 +274,9 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { ACC_FN_REF(u6a_vf_d1_c, u6a_vm_pool_alloc1(arg)); break; case u6a_vf_c1: - tuple = POOL_GET2(func.ref); + tuple = u6a_vm_pool_get2_separate(func.ref); u6a_vm_stack_resume(tuple.v1.ptr); + u6a_vm_pool_free(func.ref); ins = tuple.v2.ptr; acc = arg; break; @@ -280,7 +284,8 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { func = POOL_GET1(func.ref); goto do_apply; case u6a_vf_d1_s: - tuple = POOL_GET2(func.ref); + tuple = u6a_vm_pool_get2(func.ref); + u6a_vm_pool_free(func.ref); STACK_PUSH1(tuple.v1.fn); acc = tuple.v2.fn; ins = text + 0x03; @@ -310,7 +315,7 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { case u6a_vf_pipe: func = arg; if (UNLIKELY(current_char == EOF)) { - arg.token.fn = u6a_vf_v;acc = u6a_vm_stack_xch(acc); + arg.token.fn = u6a_vf_v; } else { arg.token = U6A_TOKEN(u6a_vf_out, current_char); } @@ -339,7 +344,7 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { break; case u6a_vo_del: delay: - STACK_PUSH1(U6A_VM_VAR_FN_REF(u6a_vf_d1_d, ins + 1 - text)); + acc = U6A_VM_VAR_FN_REF(u6a_vf_d1_d, ins + 1 - text); ins = text + text_subst_len + ins->operand.offset; continue; case u6a_vo_lc: diff --git a/src/vm_pool.c b/src/vm_pool.c index fdba9b9..42e3c2e 100644 --- a/src/vm_pool.c +++ b/src/vm_pool.c @@ -85,7 +85,7 @@ free_stack_pop() { if (fstack_top == UINT32_MAX) { return NULL; } - return fstack[--fstack_top]; + return fstack[fstack_top--]; } bool @@ -176,6 +176,22 @@ u6a_vm_pool_get2(uint32_t offset) { return (active_pool->elems + offset)->values; } +U6A_HOT struct u6a_vm_var_tuple +u6a_vm_pool_get2_separate(uint32_t offset) { + struct vm_pool_elem* elem = active_pool->elems + offset; + struct u6a_vm_var_tuple values = elem->values; + if (elem->refcnt > 1) { + // Continuation having more than 1 reference should be separated before reinstatement + values.v1.ptr = u6a_vm_stack_dup(values.v1.ptr); + } + return values; +} + +U6A_HOT void +u6a_vm_pool_addref(uint32_t offset) { + ++active_pool->elems[offset].refcnt; +} + U6A_HOT void u6a_vm_pool_free(uint32_t offset) { struct vm_pool_elem* elem = active_pool->elems; diff --git a/src/vm_pool.h b/src/vm_pool.h index 6d40c8f..701198b 100644 --- a/src/vm_pool.h +++ b/src/vm_pool.h @@ -47,6 +47,12 @@ u6a_vm_pool_get1(uint32_t offset); struct u6a_vm_var_tuple u6a_vm_pool_get2(uint32_t offset); +struct u6a_vm_var_tuple +u6a_vm_pool_get2_separate(uint32_t offset); + +void +u6a_vm_pool_addref(uint32_t offset); + void u6a_vm_pool_free(uint32_t offset); diff --git a/src/vm_stack.c b/src/vm_stack.c index c39b27b..3ff9e2b 100644 --- a/src/vm_stack.c +++ b/src/vm_stack.c @@ -18,6 +18,7 @@ */ #include "vm_stack.h" +#include "vm_pool.h" #include #include @@ -47,8 +48,7 @@ vm_stack_create(struct vm_stack* prev, uint32_t top) { } static inline struct vm_stack* -vm_stack_dup() { - struct vm_stack* vs = active_stack; +vm_stack_dup(struct vm_stack* vs) { const uint32_t size = sizeof(struct vm_stack) + stack_seg_len * sizeof(struct u6a_vm_var_fn); struct vm_stack* dup_stack = malloc(size); if (UNLIKELY(dup_stack == NULL)) { @@ -56,6 +56,15 @@ vm_stack_dup() { } memcpy(dup_stack, vs, sizeof(struct vm_stack) + (vs->top + 1) * sizeof(struct u6a_vm_var_fn)); dup_stack->refcnt = 1; + for (uint32_t idx = vs->top; idx < UINT32_MAX; --idx) { + struct u6a_vm_var_fn elem = vs->elems[idx]; + if (elem.token.fn & U6A_VM_FN_REF) { + u6a_vm_pool_addref(elem.ref); + } + } + if (vs->prev) { + ++vs->prev->refcnt; + } return dup_stack; } @@ -65,11 +74,18 @@ vm_stack_free(struct vm_stack* vs) { do { prev = vs->prev; if (--vs->refcnt == 0) { + for (uint32_t idx = vs->top; idx < UINT32_MAX; --idx) { + struct u6a_vm_var_fn elem = vs->elems[idx]; + if (elem.token.fn & U6A_VM_FN_REF) { + u6a_vm_pool_free(elem.ref); + } + } free(vs); + vs = prev; } else { break; } - } while (prev); + } while (vs); } bool @@ -186,7 +202,7 @@ u6a_vm_stack_pop() { return false; } if (active_stack->refcnt-- > 1) { - active_stack = vm_stack_dup(); + active_stack = vm_stack_dup(active_stack); } if (UNLIKELY(active_stack == NULL)) { active_stack = vs; @@ -206,7 +222,12 @@ u6a_vm_stack_xch(struct u6a_vm_var_fn v0) { void* u6a_vm_stack_save() { - return vm_stack_dup(); + return vm_stack_dup(active_stack); +} + +void* +u6a_vm_stack_dup(void* ptr) { + return vm_stack_dup(ptr); } void diff --git a/src/vm_stack.h b/src/vm_stack.h index cc4f10e..60ff66e 100644 --- a/src/vm_stack.h +++ b/src/vm_stack.h @@ -55,6 +55,9 @@ u6a_vm_stack_xch(struct u6a_vm_var_fn v1); void* u6a_vm_stack_save(); +void* +u6a_vm_stack_dup(void* ptr); + void u6a_vm_stack_resume(void* ptr);