summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-07-09 19:06:29 +0200
committerJo-Philipp Wich <jo@mein.io>2021-07-11 15:49:14 +0200
commit48f33ad70bf584a97a2e2d3870b04bbc970194b7 (patch)
tree96158523674777c7990c41cc948c88bfee5ecb34
parent0f69f099dba58e23e6438023619c002cd82eacf2 (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.h3
-rw-r--r--vm.c32
-rw-r--r--vm.h3
3 files changed, 31 insertions, 7 deletions
diff --git a/types.h b/types.h
index b4c33fc..349ae7e 100644
--- a/types.h
+++ b/types.h
@@ -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;
};
diff --git a/vm.c b/vm.c
index a5c4b8c..99e07bb 100644
--- a/vm.c
+++ b/vm.c
@@ -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;
+}
diff --git a/vm.h b/vm.h
index c4952a0..84b42fe 100644
--- a/vm.h
+++ b/vm.h
@@ -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)))