From aba45a64364457f20e84de4189500f4426e11d53 Mon Sep 17 00:00:00 2001 From: David Moc Date: Wed, 3 Jun 2026 04:14:59 +0200 Subject: Added ffap and fixed an eval memory leak --- src/eval.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 3 deletions(-) (limited to 'src/eval.c') diff --git a/src/eval.c b/src/eval.c index 34259eb..2bed8a8 100644 --- a/src/eval.c +++ b/src/eval.c @@ -446,6 +446,64 @@ static int remember_last_eval(ecex_t *ed, return ECEX_OK; } +static char *eval_module_key(const char *filename, int wrap_as_statements) { + const char *name = (filename && filename[0]) ? filename : ""; + int needed = snprintf(NULL, 0, "%d:%s", wrap_as_statements ? 1 : 0, name); + if (needed < 0) return NULL; + + char *key = malloc((size_t)needed + 1); + if (!key) return NULL; + + snprintf(key, (size_t)needed + 1, "%d:%s", wrap_as_statements ? 1 : 0, name); + return key; +} + +static void eval_remove_kept_module_ref(ecex_t *ed, void *module) { + if (!ed || !module) return; + + for (size_t i = 0; i < ed->jit_module_count; i++) { + if (ed->jit_modules[i] != module) continue; + + if (i + 1 < ed->jit_module_count) { + memmove(&ed->jit_modules[i], + &ed->jit_modules[i + 1], + (ed->jit_module_count - i - 1) * sizeof(ed->jit_modules[i])); + } + ed->jit_module_count--; + return; + } +} + +static int eval_remember_kept_module(ecex_t *ed, char *key, ccdjit_module *module) { + if (!ed || !key || !module) return ECEX_ERR; + + for (size_t i = 0; i < ed->eval_module_count; i++) { + if (!ed->eval_modules[i].key || strcmp(ed->eval_modules[i].key, key) != 0) continue; + + ccdjit_module *old = (ccdjit_module *)ed->eval_modules[i].module; + ed->eval_modules[i].module = module; + free(key); + + if (old && old != module) { + eval_remove_kept_module_ref(ed, old); + ccdjit_module_free(old); + } + return ECEX_OK; + } + + if (ECEX_GROW_ARRAY(ed->eval_modules, + ed->eval_module_count, + ed->eval_module_cap, + 8) != ECEX_OK) { + return ECEX_ERR; + } + + ed->eval_modules[ed->eval_module_count].key = key; + ed->eval_modules[ed->eval_module_count].module = module; + ed->eval_module_count++; + return ECEX_OK; +} + int ecex_eval_source(ecex_t *ed, const char *source, const char *filename, @@ -573,12 +631,36 @@ int ecex_eval_source(ecex_t *ed, buffer_append(out, line); /* - * Keep successful eval modules alive. This makes eval useful for live - * customization: code evaluated from a buffer may register commands whose - * function pointers remain valid after eval returns. + * Keep the latest successful eval module for each source key alive. A + * rerun of the same buffer replaces the old module after the new one has + * run, so normal eval-output `g` loops do not accumulate generated code. */ + char *module_key = eval_module_key(filename, wrap_as_statements); + if (!module_key) { + buffer_append(out, "failed to allocate eval module key\n"); + ccdjit_module_free(module); + g_eval_editor = NULL; + ccdjit_context_free(ctx); + free(eval_source); + ecex_switch_buffer(ed, "*eval-output*"); + return ECEX_ERR; + } + if (ecex_keep_jit_module(ed, module) != ECEX_OK) { buffer_append(out, "failed to keep eval module alive\n"); + free(module_key); + ccdjit_module_free(module); + g_eval_editor = NULL; + ccdjit_context_free(ctx); + free(eval_source); + ecex_switch_buffer(ed, "*eval-output*"); + return ECEX_ERR; + } + + if (eval_remember_kept_module(ed, module_key, module) != ECEX_OK) { + buffer_append(out, "failed to track eval module\n"); + free(module_key); + eval_remove_kept_module_ref(ed, module); ccdjit_module_free(module); g_eval_editor = NULL; ccdjit_context_free(ctx); -- cgit v1.2.3