From 29718f2e84478b296c3198ae6d35cfd5d79efb14 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Fri, 28 Jun 2024 19:33:03 +0300 Subject: optimize interpreter a bit + Use a gpr/fpr/arg stack shared between different functions to minimize amount of memory allocations done at runtime while still allowing interleaving bytecode/machine code functions during call, just with a bit of extra setup in between --- src/interp.c | 53 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 21 deletions(-) (limited to 'src/interp.c') diff --git a/src/interp.c b/src/interp.c index 25f723a..ed7e59c 100644 --- a/src/interp.c +++ b/src/interp.c @@ -2,7 +2,7 @@ #include "common.h" -union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], bool run, void ***labels_wb) +union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *state, bool run, void ***labels_wb) { static void *labels[OPCODE_COUNT] = { [MOVI] = &&MOVI, @@ -61,10 +61,16 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a return (union interp_ret){.r = 0}; } - long *gpr = malloc(f->gpr * sizeof(long)); - double *fpr = malloc(f->fpr * sizeof(double)); + size_t prev_gprs = vec_len(&state->gprs); + size_t prev_fprs = vec_len(&state->fprs); + size_t prev_argc = vec_len(&state->args); + + vec_reserve(&state->gprs, prev_gprs + f->gpr); + vec_reserve(&state->fprs, prev_fprs + f->fpr); + + long *gpr = ((long *)state->gprs.buf) + prev_gprs; + double *fpr = ((double *)state->fprs.buf) + prev_fprs; - struct vec call_args = vec_create(sizeof(struct ejit_arg)); struct ejit_insn *insns = f->insns.buf; /* retval is kind of an unfortunate extra bit of state to keep track of, @@ -190,40 +196,47 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a DO(ARG); struct ejit_arg a = ejit_build_arg(i.r1, gpr[i.r2]); - vec_append(&call_args, &a); + vec_append(&state->args, &a); DISPATCH(); DO(ARG_I); struct ejit_arg a = ejit_build_arg(i.r1, i.o); - vec_append(&call_args, &a); + vec_append(&state->args, &a); DISPATCH(); DO(ARG_F); struct ejit_arg a = ejit_build_arg_f(i.r1, fpr[i.r2]); - vec_append(&call_args, &a); + vec_append(&state->args, &a); DISPATCH(); DO(ARG_FI); struct ejit_arg a = ejit_build_arg_f(i.r1, i.d); - vec_append(&call_args, &a); + vec_append(&state->args, &a); DISPATCH(); DO(CALLI); struct ejit_func *f = i.p; - retval = ejit_run_func(f, vec_len(&call_args), call_args.buf); - vec_reset(&call_args); + size_t argc = vec_len(&state->args) - prev_argc; + struct ejit_arg *args = ((struct ejit_arg *)state->args.buf) + prev_argc; + + retval = ejit_run_interp(f, argc, args, state); + + gpr = ((long *)state->gprs.buf) + prev_gprs; + fpr = ((double *)state->fprs.buf) + prev_fprs; + vec_shrink(&state->args, prev_argc); DISPATCH(); DO(CALLI_F); - struct ejit_func *f = i.p; - retval_f = ejit_run_func_f(f, vec_len(&call_args), call_args.buf); - vec_reset(&call_args); DISPATCH(); DO(ESCAPEI); ejit_escape_t f = i.p; - retval = f(vec_len(&call_args), call_args.buf); - vec_reset(&call_args); + size_t argc = vec_len(&state->args) - prev_argc; + struct ejit_arg *args = ((struct ejit_arg *)state->args.buf) + prev_argc; + + retval = f(argc, args); + + vec_shrink(&state->args, prev_argc); DISPATCH(); /* dispatch is technically unnecessary for returns, but keep it for @@ -253,14 +266,12 @@ union interp_ret ejit_interp(struct ejit_func *f, size_t argc, struct ejit_arg a #undef DO out_int: - free(gpr); - free(fpr); - vec_destroy(&call_args); + vec_shrink(&state->gprs, prev_gprs); + vec_shrink(&state->fprs, prev_fprs); return (union interp_ret){.r = retval}; out_float: - free(gpr); - free(fpr); - vec_destroy(&call_args); + vec_shrink(&state->gprs, prev_gprs); + vec_shrink(&state->fprs, prev_fprs); return (union interp_ret){.d = retval_f}; } -- cgit v1.2.3