diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-07-30 19:44:36 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-07-30 19:44:36 +0200 |
commit | 929c8627cf077c3e348fb12b02553d4a444c5e48 (patch) | |
tree | 72ef326e45a4934731c285d80b5ff2971d40060f /vm.c | |
parent | 8f34d70c00cb7c17140f920234f04af1ddbdfbf4 (diff) |
vm: fix toplevel function call protocol
In success case, always push the function return value onto the stack even
if no call frames are remaining after the function returned.
This is needed for host program code invoking ucode functions within a VM
context that already ran to completion.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 48 |
1 files changed, 32 insertions, 16 deletions
@@ -2032,7 +2032,7 @@ uc_vm_output_exception(uc_vm_t *vm, uc_exception_t *ex) } static uc_vm_status_t -uc_vm_execute_chunk(uc_vm_t *vm, uc_value_t **retvalp) +uc_vm_execute_chunk(uc_vm_t *vm) { uc_callframe_t *frame = uc_vm_current_frame(vm); uc_chunk_t *chunk = uc_vm_frame_chunk(frame); @@ -2234,16 +2234,10 @@ uc_vm_execute_chunk(uc_vm_t *vm, uc_value_t **retvalp) case I_RETURN: retval = uc_vm_callframe_pop(vm); - if (vm->callframes.count == 0) { - if (retvalp) - *retvalp = retval; - else - ucv_put(retval); + uc_vm_stack_push(vm, retval); + if (vm->callframes.count == 0) return STATUS_OK; - } - - uc_vm_stack_push(vm, retval); frame = uc_vector_last(&vm->callframes); chunk = uc_vm_frame_chunk(frame); @@ -2268,9 +2262,6 @@ uc_vm_execute_chunk(uc_vm_t *vm, uc_value_t **retvalp) if (vm->exception.type == EXCEPTION_EXIT) { uc_vm_reset_callframes(vm); - if (retvalp) - *retvalp = ucv_int64_new(vm->arg.s32); - return STATUS_EXIT; } @@ -2305,8 +2296,10 @@ uc_vm_status_t uc_vm_execute(uc_vm_t *vm, uc_function_t *fn, uc_value_t **retval) { uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, fn, false); + uc_vm_status_t status; uc_callframe_t *frame; uc_stringbuf_t *buf; + uc_value_t *val; uc_vector_grow(&vm->callframes); @@ -2330,10 +2323,33 @@ uc_vm_execute(uc_vm_t *vm, uc_function_t *fn, uc_value_t **retval) //uc_vm_stack_push(vm, closure->header.jso); uc_vm_stack_push(vm, NULL); - if (retval) - *retval = NULL; + status = uc_vm_execute_chunk(vm); + + switch (status) { + case STATUS_OK: + val = uc_vm_stack_pop(vm); + + if (retval) + *retval = val; + else + ucv_put(val); + + break; + + case STATUS_EXIT: + if (retval) + *retval = ucv_int64_new(vm->arg.s32); + + break; + + default: + if (retval) + *retval = NULL; + + break; + } - return uc_vm_execute_chunk(vm, retval); + return status; } uc_exception_type_t @@ -2344,7 +2360,7 @@ uc_vm_call(uc_vm_t *vm, bool mcall, size_t nargs) if (uc_vm_call_function(vm, ctx, fno, mcall, nargs & 0xffff)) { if (ucv_type(fno) != UC_CFUNCTION) - uc_vm_execute_chunk(vm, NULL); + uc_vm_execute_chunk(vm); } return vm->exception.type; |