From 0adeaa3543de4112f8a1b6e3a4730b57568d08ae Mon Sep 17 00:00:00 2001 From: theMackabu Date: Sun, 22 Mar 2026 12:38:07 -0700 Subject: [PATCH] fix crash with upvalues --- include/gc/objects.h | 7 ++++++- include/silver/engine.h | 6 +++++- src/ant.c | 8 ++++++-- src/gc/objects.c | 26 +++++++++++++++++--------- src/silver/ops/comparison.h | 2 +- src/silver/ops/upvalues.h | 11 +++++------ 6 files changed, 40 insertions(+), 20 deletions(-) diff --git a/include/gc/objects.h b/include/gc/objects.h index 7901e03..e84b39a 100644 --- a/include/gc/objects.h +++ b/include/gc/objects.h @@ -6,7 +6,12 @@ #define ANT_GC_DEAD 0xFF -typedef void (*gc_str_mark_fn)(ant_t *js, ant_value_t v); +typedef void (*gc_str_mark_fn)( + ant_t *js, + ant_value_t v +); + +uint64_t gc_get_epoch(void); bool gc_obj_is_marked(const ant_object_t *obj); void gc_mark_value(ant_t *js, ant_value_t v); diff --git a/include/silver/engine.h b/include/silver/engine.h index 4f61bb9..42bbcb9 100644 --- a/include/silver/engine.h +++ b/include/silver/engine.h @@ -5,6 +5,7 @@ #include "internal.h" #include "runtime.h" #include "errors.h" +#include "gc/objects.h" #include #include @@ -249,6 +250,7 @@ static inline sv_upvalue_t *js_upvalue_alloc(void) { #define SV_CALL_HAS_SUPER (1u << 1) #define SV_CALL_IS_ARROW (1u << 2) #define SV_CALL_IS_DEFAULT_CTOR (1u << 3) +#define SV_CALL_BORROWED_UPVALS (1u << 4) typedef struct sv_closure { uint32_t call_flags; @@ -266,7 +268,9 @@ typedef struct sv_closure { } sv_closure_t; static inline sv_closure_t *js_closure_alloc(ant_t *js) { - return (sv_closure_t *)fixed_arena_alloc(&js->closure_arena); + sv_closure_t *c = (sv_closure_t *)fixed_arena_alloc(&js->closure_arena); + if (c) c->gc_epoch = gc_get_epoch(); + return c; } static inline sv_closure_t *js_func_closure(ant_value_t func) { diff --git a/src/ant.c b/src/ant.c index 9386fb7..e7c7bcf 100644 --- a/src/ant.c +++ b/src/ant.c @@ -4564,6 +4564,7 @@ static ant_value_t build_dynamic_function(ant_t *js, ant_value_t *args, int narg ant_value_t func = mkval(T_FUNC, (uintptr_t)closure); ant_value_t proto_setup = setup_func_prototype(js, func); if (is_err(proto_setup)) return proto_setup; + return func; } @@ -4789,13 +4790,16 @@ static ant_value_t builtin_function_bind(ant_t *js, ant_value_t *args, int nargs sv_closure_t *orig = js_func_closure(func); sv_closure_t *bound_closure = js_closure_alloc(js); if (!bound_closure) return js_mkerr(js, "oom"); + bound_closure->func = orig->func; + bound_closure->call_flags = orig->call_flags; bound_closure->upvalues = orig->upvalues; + if (orig->upvalues) bound_closure->call_flags |= SV_CALL_BORROWED_UPVALS; bound_closure->bound_this = this_arg; bound_closure->bound_args = js_mkundef(); bound_closure->super_val = orig->super_val; bound_closure->func_obj = bound_func; - bound_closure->call_flags = orig->call_flags; + if (bound_argc > 0) bound_closure->call_flags |= SV_CALL_HAS_BOUND_ARGS; @@ -4840,8 +4844,8 @@ static ant_value_t builtin_function_bind(ant_t *js, ant_value_t *args, int nargs ant_value_t bound = mkval(T_FUNC, (uintptr_t)bound_closure); ant_value_t proto_setup = setup_func_prototype(js, bound); + if (is_err(proto_setup)) return proto_setup; - js_mark_constructor(bound_func, js_is_constructor(js, func)); return bound; diff --git a/src/gc/objects.c b/src/gc/objects.c index 756dd7d..b5a64fe 100644 --- a/src/gc/objects.c +++ b/src/gc/objects.c @@ -648,22 +648,26 @@ void gc_objects_run(ant_t *js, gc_str_mark_fn str_mark) { ant_ic_epoch_bump(); gc_promote_survivors(js); - ant_fixed_arena_t *ca = &js->closure_arena; ca->free_list = NULL; ca->live_count = 0; + for (size_t off = 0; off < ca->watermark; off += ca->elem_size) { - sv_closure_t *c = (sv_closure_t *)(ca->base + off); - if (c->gc_epoch == gc_epoch) ca->live_count++; - else { + sv_closure_t *c = (sv_closure_t *)(ca->base + off); + + if (c->gc_epoch == gc_epoch) ca->live_count++; + else { + if (!(c->call_flags & SV_CALL_BORROWED_UPVALS)) { free(c->upvalues); c->upvalues = NULL; - free(c->bound_argv); - c->bound_argv = NULL; - *(void **)c = ca->free_list; - ca->free_list = c; } - } + + free(c->bound_argv); + c->bound_argv = NULL; + + *(void **)c = ca->free_list; + ca->free_list = c; + }} ant_fixed_arena_t *ua = &js->upvalue_arena; ua->free_list = NULL; @@ -741,3 +745,7 @@ void gc_objects_run_minor(ant_t *js, gc_str_mark_fn str_mark) { // gc_epoch would not be updated and they would be incorrectly freed. // closure/upvalue arenas are only swept on major GC `gc_objects_run` } + +uint64_t gc_get_epoch(void) { + return gc_epoch; +} \ No newline at end of file diff --git a/src/silver/ops/comparison.h b/src/silver/ops/comparison.h index fe68b07..0edb7fe 100644 --- a/src/silver/ops/comparison.h +++ b/src/silver/ops/comparison.h @@ -1,8 +1,8 @@ #ifndef SV_COMPARISON_H #define SV_COMPARISON_H -#include "silver/engine.h" #include "shapes.h" +#include "silver/engine.h" #include "modules/bigint.h" static inline void sv_op_seq(sv_vm_t *vm, ant_t *js) { diff --git a/src/silver/ops/upvalues.h b/src/silver/ops/upvalues.h index b479fdc..528a647 100644 --- a/src/silver/ops/upvalues.h +++ b/src/silver/ops/upvalues.h @@ -109,17 +109,18 @@ static inline void sv_op_closure( } } + ant_value_t func_val = mkval(T_FUNC, (uintptr_t)closure); + vm->stack[vm->sp++] = func_val; + ant_value_t func_obj = mkobj(js, 0); closure->func_obj = func_obj; + js_mark_constructor(func_obj, !child->is_arrow && !child->is_method); js_setprop(js, func_obj, js->length_str, tov((double)child->param_count)); js_set_descriptor(js, func_obj, "length", 6, JS_DESC_C); - ant_value_t func_val = mkval(T_FUNC, (uintptr_t)closure); if (!child->is_arrow && !child->is_method) sv_setup_function_prototype(js, func_obj, func_val); - - if (child->is_strict) - js_set_slot(func_obj, SLOT_STRICT, js_true); + if (child->is_strict) js_set_slot(func_obj, SLOT_STRICT, js_true); if (child->is_async) { js_set_slot(func_obj, SLOT_ASYNC, js_true); @@ -129,8 +130,6 @@ static inline void sv_op_closure( ant_value_t func_proto = js_get_slot(js->global, SLOT_FUNC_PROTO); if (vtype(func_proto) == T_FUNC) js_set_proto_init(func_obj, func_proto); } - - vm->stack[vm->sp++] = func_val; } #endif -- 2.51.2