diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-07-09 19:06:29 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-07-11 15:49:14 +0200 |
commit | 48f33ad70bf584a97a2e2d3870b04bbc970194b7 (patch) | |
tree | 96158523674777c7990c41cc948c88bfee5ecb34 | |
parent | 0f69f099dba58e23e6438023619c002cd82eacf2 (diff) |
vm: make root exception handler configurable
So far, the VM simply printed exception information to stderr if the
exception was not catched in managed code. Host programs embedding
ucode might want to customize that behaviour, so refactor the current
defualt behaviour into a callback function and add a public getter
and setter to allow changing the exception handler callback.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | types.h | 3 | ||||
-rw-r--r-- | vm.c | 32 | ||||
-rw-r--r-- | vm.h | 3 |
3 files changed, 31 insertions, 7 deletions
@@ -241,6 +241,8 @@ uc_declare_vector(uc_stack, uc_value_t *); typedef struct printbuf uc_stringbuf_t; +typedef void (uc_exception_handler_t)(uc_vm *, uc_exception *); + struct uc_vm { uc_stack stack; uc_exception exception; @@ -262,6 +264,7 @@ struct uc_vm { size_t spread_values; uint8_t trace; uc_stringbuf_t *strbuf; + uc_exception_handler_t *exhandler; FILE *output; }; @@ -132,6 +132,9 @@ uc_vm_alloc_global_scope(uc_vm *vm) return scope; } +static void +uc_vm_output_exception(uc_vm *vm, uc_exception *ex); + void uc_vm_init(uc_vm *vm, uc_parse_config *config) { char *s = getenv("TRACE"); @@ -155,6 +158,8 @@ void uc_vm_init(uc_vm *vm, uc_parse_config *config) uc_vm_reset_stack(vm); uc_vm_alloc_global_scope(vm); + + uc_vm_exception_handler_set(vm, uc_vm_output_exception); } void uc_vm_free(uc_vm *vm) @@ -2010,18 +2015,18 @@ uc_vm_callframe_pop(uc_vm *vm) } static void -uc_vm_output_exception(uc_vm *vm) +uc_vm_output_exception(uc_vm *vm, uc_exception *ex) { uc_value_t *ctx; - if (vm->exception.type == EXCEPTION_USER) - fprintf(stderr, "%s\n", vm->exception.message); + if (ex->type == EXCEPTION_USER) + fprintf(stderr, "%s\n", ex->message); else fprintf(stderr, "%s: %s\n", - exception_type_strings[vm->exception.type] ? exception_type_strings[vm->exception.type] : "Error", - vm->exception.message); + exception_type_strings[ex->type] ? exception_type_strings[ex->type] : "Error", + ex->message); - ctx = ucv_object_get(ucv_array_get(vm->exception.stacktrace, 0), "context", NULL); + ctx = ucv_object_get(ucv_array_get(ex->stacktrace, 0), "context", NULL); if (ctx) fprintf(stderr, "%s\n", ucv_string_get(ctx)); @@ -2276,7 +2281,8 @@ uc_vm_execute_chunk(uc_vm *vm, uc_value_t **retvalp) while (!uc_vm_handle_exception(vm)) { /* no further callframe to pop, report unhandled exception and terminate */ if (vm->callframes.count <= 1) { - uc_vm_output_exception(vm); + if (vm->exhandler) + vm->exhandler(vm, &vm->exception); return ERROR_RUNTIME; } @@ -2391,3 +2397,15 @@ uc_vm_invoke(uc_vm *vm, const char *fname, size_t nargs, ...) return uc_vm_stack_pop(vm); } + +uc_exception_handler_t * +uc_vm_exception_handler_get(uc_vm *vm) +{ + return vm->exhandler; +} + +void +uc_vm_exception_handler_set(uc_vm *vm, uc_exception_handler_t *exhandler) +{ + vm->exhandler = exhandler; +} @@ -120,6 +120,9 @@ void uc_vm_stack_push(uc_vm *vm, uc_value_t *value); uc_value_t *uc_vm_stack_pop(uc_vm *vm); uc_value_t *uc_vm_stack_peek(uc_vm *vm, size_t offset); +uc_exception_handler_t *uc_vm_exception_handler_get(uc_vm *vm); +void uc_vm_exception_handler_set(uc_vm *vm, uc_exception_handler_t *exhandler); + uc_exception_type_t uc_vm_call(uc_vm *vm, bool mcall, size_t nargs); void __attribute__((format(printf, 3, 0))) |