From 1f94e188f9de57e4242084b6079192cda2210efc Mon Sep 17 00:00:00 2001 From: theMackabu Date: Sat, 2 May 2026 17:37:56 -0700 Subject: [PATCH] add temp code parse arena with rewinding --- include/runtime.h | 8 +++ src/ant.c | 4 ++ src/modules/abort.c | 29 ++++++++++- src/modules/builtin.c | 4 +- src/repl.c | 4 +- src/runtime.c | 117 ++++++++++++++++++++++++++++++++++-------- src/silver/ast.c | 8 +-- src/silver/compiler.c | 38 +++++++++++--- src/silver/lexer.c | 2 +- 9 files changed, 177 insertions(+), 37 deletions(-) diff --git a/include/runtime.h b/include/runtime.h index d298bff..75c4bf9 100644 --- a/include/runtime.h +++ b/include/runtime.h @@ -32,6 +32,14 @@ code_arena_mark_t code_arena_mark(void); void code_arena_rewind(code_arena_mark_t mark); void code_arena_reset(void); +size_t parse_arena_get_memory(void); + +code_arena_mark_t parse_arena_mark(void); +void parse_arena_rewind(code_arena_mark_t mark); + +void parse_arena_reset(void); +void *parse_arena_bump(size_t size); + void destroy_runtime(ant_t *js); void *code_arena_bump(size_t size); diff --git a/src/ant.c b/src/ant.c index 4c2caff..6c36732 100644 --- a/src/ant.c +++ b/src/ant.c @@ -15702,9 +15702,12 @@ bool js_chkargs(ant_value_t *args, int nargs, const char *spec) { static ant_value_t js_eval_bytecode_mode(ant_t *js, const char *buf, size_t len, sv_compile_mode_t mode, bool parse_strict) { if (len == (size_t)~0U) len = strlen(buf); + + code_arena_mark_t parse_mark = parse_arena_mark(); sv_ast_t *program = sv_parse(js, buf, (ant_offset_t)len, parse_strict); if (!program) { + parse_arena_rewind(parse_mark); if (js->thrown_exists) return mkval(T_ERR, 0); return js_mkerr_typed(js, JS_ERR_INTERNAL | JS_ERR_NO_STACK, "Unexpected parse error"); } @@ -15715,6 +15718,7 @@ static ant_value_t js_eval_bytecode_mode(ant_t *js, const char *buf, size_t len, } sv_func_t *func = sv_compile(js, program, mode, buf, (ant_offset_t)len); + parse_arena_rewind(parse_mark); if (!func) { if (js->thrown_exists) return mkval(T_ERR, 0); return js_mkerr_typed(js, JS_ERR_INTERNAL | JS_ERR_NO_STACK, "Unexpected compile error"); diff --git a/src/modules/abort.c b/src/modules/abort.c index dc0131b..8073c57 100644 --- a/src/modules/abort.c +++ b/src/modules/abort.c @@ -61,6 +61,20 @@ static abort_signal_data_t *get_signal_data_if_signal_object(ant_value_t obj) { return get_signal_data(obj); } +static void abort_signal_data_free(abort_signal_data_t *data) { + if (!data) return; + if (data->listeners) utarray_free(data->listeners); + if (data->followers) utarray_free(data->followers); + free(data); +} + +static void abort_signal_finalize(ant_t *js, ant_object_t *obj) { + ant_value_t value = js_obj_from_ptr(obj); + abort_signal_data_t *data = get_signal_data(value); + js_clear_native(value, ABORT_SIGNAL_NATIVE_TAG); + abort_signal_data_free(data); +} + static ant_value_t make_abort_error(ant_t *js) { return make_dom_exception(js, "signal is aborted without reason", "AbortError"); } @@ -188,6 +202,7 @@ static ant_value_t make_new_signal(ant_t *js) { ant_value_t obj = js_mkobj(js); js_set_native(obj, data, ABORT_SIGNAL_NATIVE_TAG); + js_set_finalizer(obj, abort_signal_finalize); js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_ABORT_SIGNAL)); if (g_initialized) js_set_slot_wb(js, obj, SLOT_PROTO, g_signal_proto); @@ -331,7 +346,19 @@ ant_value_t abort_signal_create_dependent(ant_t *js, ant_value_t source) { static void abort_timeout_close_cb(uv_handle_t *h) { abort_timeout_entry_t *entry = (abort_timeout_entry_t *)h->data; - if (entry) entry->closed = 1; + if (!entry) return; + + abort_timeout_entry_t **it = &timeout_entries; + while (*it) { + if (*it == entry) { + *it = entry->next; + break; + } + it = &(*it)->next; + } + + entry->closed = 1; + free(entry); } static void abort_timeout_fire_cb(uv_timer_t *handle) { diff --git a/src/modules/builtin.c b/src/modules/builtin.c index c35cbae..bfe844f 100644 --- a/src/modules/builtin.c +++ b/src/modules/builtin.c @@ -289,11 +289,13 @@ static ant_value_t js_stats_fn(ant_t *js, ant_value_t *args, int nargs) { size_t buffer_mem = buffer_get_external_memory(); size_t code_mem = code_arena_get_memory(); - size_t external_total = buffer_mem + code_mem; + size_t parse_mem = parse_arena_get_memory(); + size_t external_total = buffer_mem + code_mem + parse_mem; ant_value_t ext = js_newobj(js); js_set(js, ext, "buffers", js_mknum((double)buffer_mem)); js_set(js, ext, "code", js_mknum((double)code_mem)); + js_set(js, ext, "parse", js_mknum((double)parse_mem)); js_set(js, ext, "total", js_mknum((double)external_total)); js_set(js, result, "external", ext); diff --git a/src/repl.c b/src/repl.c index 5a49566..f84b5c5 100644 --- a/src/repl.c +++ b/src/repl.c @@ -231,7 +231,7 @@ static bool repl_precheck_and_commit_lexicals( ) { if (!js || !reg || !code || len == 0) return true; - code_arena_mark_t mark = code_arena_mark(); + code_arena_mark_t mark = parse_arena_mark(); repl_decl_pending_t pending = {0}; bool ok = true; @@ -268,7 +268,7 @@ static bool repl_precheck_and_commit_lexicals( } done: - code_arena_rewind(mark); + parse_arena_rewind(mark); repl_decl_pending_free(&pending); if (ok && js->thrown_exists) diff --git a/src/runtime.c b/src/runtime.c index d348a08..54d72cd 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -31,11 +31,13 @@ typedef struct code_block { static struct ant_runtime runtime = {0}; struct ant_runtime *const rt = &runtime; - -static code_block_t *code_arena_head = NULL; -static code_block_t *code_arena_current = NULL; static intern_entry_t *code_interns = NULL; +static code_block_t *code_arena_head = NULL; +static code_block_t *code_arena_current = NULL; +static code_block_t *parse_arena_head = NULL; +static code_block_t *parse_arena_current = NULL; + static void code_interns_prune_for_block_range( const code_block_t *block, size_t start_offset @@ -74,6 +76,72 @@ static code_block_t *code_arena_new_block(size_t min_size) { return block; } +static void *arena_bump( + code_block_t **head, + code_block_t **current, + size_t size +) { + size = (size + 7) & ~(size_t)7; + if (!*current || (*current)->used + size > (*current)->capacity) { + code_block_t *new_block = code_arena_new_block(size); + if (!new_block) return NULL; + if (!*head) *head = new_block; + else if (*current) (*current)->next = new_block; + *current = new_block; + } + + void *ptr = &(*current)->data[(*current)->used]; + (*current)->used += size; + return ptr; +} + +static size_t arena_get_memory(code_block_t *head) { + size_t total = 0; + for (code_block_t *b = head; b; b = b->next) + total += sizeof(code_block_t) + b->capacity; + return total; +} + +static code_arena_mark_t arena_mark(code_block_t *current) { + code_arena_mark_t mark = {0}; + mark.block = current; + mark.used = current ? current->used : 0; + return mark; +} + +static void arena_rewind_plain( + code_block_t **head, + code_block_t **current, + code_arena_mark_t mark +) { + code_block_t *target = (code_block_t *)mark.block; + + if (!target) { + code_block_t *block = *head; + while (block) { + code_block_t *next = block->next; + free(block); + block = next; + } + *head = NULL; + *current = NULL; + return; + } + + size_t clamped_used = mark.used <= target->capacity ? mark.used : target->capacity; + target->used = clamped_used; + + code_block_t *b = target->next; + while (b) { + code_block_t *next = b->next; + free(b); + b = next; + } + + target->next = NULL; + *current = target; +} + const char *code_arena_alloc(const char *code, size_t len) { if (!code || len == 0) return NULL; @@ -106,31 +174,15 @@ const char *code_arena_alloc(const char *code, size_t len) { } void *code_arena_bump(size_t size) { - size = (size + 7) & ~(size_t)7; - if (!code_arena_current || code_arena_current->used + size > code_arena_current->capacity) { - code_block_t *new_block = code_arena_new_block(size); - if (!new_block) return NULL; - if (!code_arena_head) code_arena_head = new_block; - else if (code_arena_current) code_arena_current->next = new_block; - code_arena_current = new_block; - } - void *ptr = &code_arena_current->data[code_arena_current->used]; - code_arena_current->used += size; - return ptr; + return arena_bump(&code_arena_head, &code_arena_current, size); } size_t code_arena_get_memory(void) { - size_t total = 0; - for (code_block_t *b = code_arena_head; b; b = b->next) - total += sizeof(code_block_t) + b->capacity; - return total; + return arena_get_memory(code_arena_head); } code_arena_mark_t code_arena_mark(void) { - code_arena_mark_t mark = {0}; - mark.block = code_arena_current; - mark.used = code_arena_current ? code_arena_current->used : 0; - return mark; + return arena_mark(code_arena_current); } void code_arena_rewind(code_arena_mark_t mark) { @@ -167,6 +219,26 @@ void code_arena_rewind(code_arena_mark_t mark) { code_arena_current = target; } +void *parse_arena_bump(size_t size) { + return arena_bump(&parse_arena_head, &parse_arena_current, size); +} + +size_t parse_arena_get_memory(void) { + return arena_get_memory(parse_arena_head); +} + +code_arena_mark_t parse_arena_mark(void) { + return arena_mark(parse_arena_current); +} + +void parse_arena_rewind(code_arena_mark_t mark) { + arena_rewind_plain(&parse_arena_head, &parse_arena_current, mark); +} + +void parse_arena_reset(void) { + parse_arena_rewind((code_arena_mark_t){0}); +} + void code_arena_reset(void) { intern_entry_t *entry, *tmp; HASH_ITER(hh, code_interns, entry, tmp) { @@ -184,6 +256,7 @@ void code_arena_reset(void) { code_arena_head = NULL; code_arena_current = NULL; + parse_arena_reset(); } void destroy_runtime(ant_t *js) { diff --git a/src/silver/ast.c b/src/silver/ast.c index bf8e8c9..fbbcad5 100644 --- a/src/silver/ast.c +++ b/src/silver/ast.c @@ -14,7 +14,7 @@ #include sv_ast_t *sv_ast_new(sv_node_type_t type) { - sv_ast_t *n = code_arena_bump(sizeof(sv_ast_t)); + sv_ast_t *n = parse_arena_bump(sizeof(sv_ast_t)); if (!n) return NULL; memset(n, 0, sizeof(sv_ast_t)); n->type = type; @@ -24,7 +24,7 @@ sv_ast_t *sv_ast_new(sv_node_type_t type) { void sv_ast_list_push(sv_ast_list_t *list, sv_ast_t *node) { if (list->count >= list->cap) { int new_cap = list->cap ? list->cap * 2 : 4; - sv_ast_t **new_items = code_arena_bump((size_t)new_cap * sizeof(sv_ast_t *)); + sv_ast_t **new_items = parse_arena_bump((size_t)new_cap * sizeof(sv_ast_t *)); if (!new_items) return; if (list->items) memcpy(new_items, list->items, (size_t)list->count * sizeof(sv_ast_t *)); @@ -167,7 +167,7 @@ static inline const char *decode_ident_into_arena(const char *src, uint32_t len, return src; } - char *dst = code_arena_bump((size_t)len + 1); + char *dst = parse_arena_bump((size_t)len + 1); if (!dst) { if (out_len) *out_len = len; return src; @@ -371,7 +371,7 @@ static sv_tpl_cooked_t decode_template_segment(P, const uint8_t *in, size_t star return outv; } - uint8_t *out = code_arena_bump(raw_len); + uint8_t *out = parse_arena_bump(raw_len); if (!out) { (void)SV_MKERR(JS, "oom"); outv.ok = false; diff --git a/src/silver/compiler.c b/src/silver/compiler.c index b7ddaec..3beec36 100644 --- a/src/silver/compiler.c +++ b/src/silver/compiler.c @@ -5579,8 +5579,14 @@ sv_func_t *sv_compile_function(ant_t *js, const char *source, size_t len, bool i wrapped[wrapped_len] = '\0'; bool parse_strict = sv_vm_is_strict(js->vm); + code_arena_mark_t parse_mark = parse_arena_mark(); sv_ast_t *program = sv_parse(js, wrapped, (ant_offset_t)wrapped_len, parse_strict); - if (!program) { free(wrapped); return NULL; } + + if (!program) { + parse_arena_rewind(parse_mark); + free(wrapped); + return NULL; + } sv_ast_t *func_node = NULL; if (program->args.count > 0) { @@ -5589,7 +5595,11 @@ sv_func_t *sv_compile_function(ant_t *js, const char *source, size_t len, bool i else if (stmt && stmt->left && stmt->left->type == N_FUNC) func_node = stmt->left; } - if (!func_node) { free(wrapped); return NULL; } + if (!func_node) { + parse_arena_rewind(parse_mark); + free(wrapped); + return NULL; + } sv_compiler_t root; sv_compile_ctx_init_root( @@ -5601,7 +5611,9 @@ sv_func_t *sv_compile_function(ant_t *js, const char *source, size_t len, bool i root.line_table = sv_compile_ctx_build_line_table(root.source, (ant_offset_t)wrapped_len); sv_func_t *func = compile_function_body(&root, func_node, SV_COMPILE_SCRIPT); + sv_compile_ctx_free_line_table(root.line_table); + parse_arena_rewind(parse_mark); free(wrapped); if (sv_compile_trace_unlikely) fprintf( @@ -5632,8 +5644,13 @@ sv_func_t *sv_compile_function_with_params( } bool parse_strict = sv_vm_is_strict(js->vm); + code_arena_mark_t parse_mark = parse_arena_mark(); sv_ast_t *program = sv_parse(js, body, (ant_offset_t)body_len, parse_strict); - if (!program) return NULL; + + if (!program) { + parse_arena_rewind(parse_mark); + return NULL; + } static const char *k_top_name_function = ""; static const char *k_top_name_async_function = ""; @@ -5658,7 +5675,10 @@ sv_func_t *sv_compile_function_with_params( } sv_ast_t *ident = sv_ast_new(N_IDENT); - if (!ident) return NULL; + if (!ident) { + parse_arena_rewind(parse_mark); + return NULL; + } ident->str = name; ident->len = (uint32_t)name_len; @@ -5668,10 +5688,14 @@ sv_func_t *sv_compile_function_with_params( } top_fn.body = sv_ast_new(N_BLOCK); - if (!top_fn.body) return NULL; + if (!top_fn.body) { + parse_arena_rewind(parse_mark); + return NULL; + } + top_fn.body->args = program->args; - sv_compiler_t root; + sv_compile_ctx_init_root( &root, js, js->filename, pin_source_text(body, (ant_offset_t)body_len), @@ -5681,7 +5705,9 @@ sv_func_t *sv_compile_function_with_params( root.line_table = sv_compile_ctx_build_line_table(root.source, (ant_offset_t)body_len); sv_func_t *func = compile_function_body(&root, &top_fn, SV_COMPILE_SCRIPT); + sv_compile_ctx_free_line_table(root.line_table); + parse_arena_rewind(parse_mark); if (sv_compile_trace_unlikely) fprintf( stderr, "[compile] end kind=function-with-params thrown=%d func=%p\n", diff --git a/src/silver/lexer.c b/src/silver/lexer.c index 29d45fc..748bbe6 100644 --- a/src/silver/lexer.c +++ b/src/silver/lexer.c @@ -74,7 +74,7 @@ sv_lex_string_t sv_lexer_str_literal(sv_lexer_t *lx) { outv.ok = true; return outv; } - uint8_t *out = code_arena_bump(cap); + uint8_t *out = parse_arena_bump(cap); if (!out) { (void)js_mkerr(js, "oom"); return outv; -- 2.51.2