aboutsummaryrefslogtreecommitdiff
path: root/src/ejit.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-06-28 19:33:03 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-06-28 19:33:03 +0300
commit29718f2e84478b296c3198ae6d35cfd5d79efb14 (patch)
tree5261fe6e369f27f66a48c6f307870fc854c693c8 /src/ejit.c
parent2fc4f728643f78577c26e548619bc7db90a7c6ae (diff)
downloadejit-29718f2e84478b296c3198ae6d35cfd5d79efb14.tar.gz
ejit-29718f2e84478b296c3198ae6d35cfd5d79efb14.zip
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
Diffstat (limited to 'src/ejit.c')
-rw-r--r--src/ejit.c38
1 files changed, 35 insertions, 3 deletions
diff --git a/src/ejit.c b/src/ejit.c
index 1fcae9d..b059c88 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -74,7 +74,7 @@ void ejit_select_compile_func(struct ejit_func *f, size_t gpr, size_t fpr, bool
void **labels;
/* just get labels, don't actually run anything yet */
- ejit_interp(f, 0, NULL, false, &labels);
+ ejit_interp(f, 0, NULL, NULL, false, &labels);
foreach_vec(ii, f->insns) {
struct ejit_insn i = vect_at(struct ejit_insn, f->insns, ii);
void *addr = labels[i.op];
@@ -292,6 +292,32 @@ struct ejit_reloc ejit_jmp(struct ejit_func *s)
return (struct ejit_reloc){.insn = addr};
}
+static struct interp_state create_interp_state()
+{
+ struct interp_state state;
+ state.gprs = vec_create(sizeof(long));
+ state.gprs = vec_create(sizeof(double));
+ state.args = vec_create(sizeof(struct ejit_arg));
+ return state;
+}
+
+static void destroy_interp_state(struct interp_state state)
+{
+ vec_destroy(&state.gprs);
+ vec_destroy(&state.fprs);
+ vec_destroy(&state.args);
+}
+
+long ejit_run_interp(struct ejit_func *f, size_t argc, struct ejit_arg args[argc], struct interp_state *state)
+{
+ assert(f->gpr && "trying to run a function that hasn't been compiled");
+ assert(f->rtype == EJIT_VOID || ejit_int_type(f->rtype));
+ if (f->arena)
+ return ((ejit_escape_t)f->arena)(argc, args);
+
+ return ejit_interp(f, argc, args, state, true, NULL).r;
+}
+
long ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
{
assert(f->gpr && "trying to run a function that hasn't been compiled");
@@ -299,7 +325,10 @@ long ejit_run_func(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
if (f->arena)
return ((ejit_escape_t)f->arena)(argc, args);
- return ejit_interp(f, argc, args, true, NULL).r;
+ struct interp_state state = create_interp_state();
+ long r = ejit_interp(f, argc, args, &state, true, NULL).r;
+ destroy_interp_state(state);
+ return r;
}
double ejit_run_func_f(struct ejit_func *f, size_t argc, struct ejit_arg args[argc])
@@ -309,5 +338,8 @@ double ejit_run_func_f(struct ejit_func *f, size_t argc, struct ejit_arg args[ar
if (f->arena)
return ((ejit_escape_f_t)f->arena)(argc, args);
- return ejit_interp(f, argc, args, true, NULL).d;
+ struct interp_state state = create_interp_state();
+ double r = ejit_interp(f, argc, args, &state, true, NULL).d;
+ destroy_interp_state(state);
+ return r;
}