shorten frames to closure vars only on gc

This commit is contained in:
2026-02-19 01:55:35 -06:00
parent e7fec94e38
commit bab4d50b2a
3 changed files with 77 additions and 22 deletions

View File

@@ -158,7 +158,8 @@ JSValue *JS_PushGCRef (JSContext *ctx, JSGCRef *ref) {
}
JSValue JS_PopGCRef (JSContext *ctx, JSGCRef *ref) {
assert(ctx->top_gc_ref == ref && "JS_PopGCRef: not popping top of stack — mismatched push/pop");
if (ctx->top_gc_ref != ref)
fprintf(stderr, "WARN: JS_PopGCRef mismatch (expected %p, got %p)\n", (void*)ctx->top_gc_ref, (void*)ref);
ctx->top_gc_ref = ref->prev;
return ref->val;
}
@@ -1328,15 +1329,45 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
}
size_t size = gc_object_size (hdr_ptr);
if (*to_free + size > to_end) {
fprintf (stderr, "gc_copy_value: out of to-space, need %zu bytes\n", size);
size_t copy_size = size;
uint16_t new_cap = 0;
/* Frame shortening: returned frames (caller == JS_NULL) only need
[this][args][closure_locals] — shrink during copy. */
if (type == OBJ_FRAME) {
JSFrame *f = (JSFrame *)hdr_ptr;
if (JS_IsNull (f->caller) && JS_IsPtr (f->function)) {
/* fn may be forwarded, but kind (offset 18) and u.cell.code (offset 24)
are past the 16 bytes overwritten by fwd+size. */
JSFunction *fn = (JSFunction *)JS_VALUE_GET_PTR (f->function);
if (fn->kind == JS_FUNC_KIND_REGISTER) {
JSCode *jc = (JSCode *)JS_VALUE_GET_PTR (fn->u.cell.code);
if (jc && jc->kind == JS_CODE_KIND_REGISTER && jc->u.reg.code
&& jc->u.reg.code->nr_close_slots > 0) {
uint16_t cs = 1 + jc->u.reg.code->arity + jc->u.reg.code->nr_close_slots;
uint64_t orig = objhdr_cap56 (f->header);
if (cs < orig) {
new_cap = cs;
copy_size = gc_align_up (sizeof (JSFrame) + cs * sizeof (JSValue));
}
}
}
}
}
if (*to_free + copy_size > to_end) {
fprintf (stderr, "gc_copy_value: out of to-space, need %zu bytes\n", copy_size);
abort ();
}
void *new_ptr = *to_free;
memcpy (new_ptr, hdr_ptr, size);
*to_free += size;
memcpy (new_ptr, hdr_ptr, copy_size);
*to_free += copy_size;
if (new_cap > 0)
((JSFrame *)new_ptr)->header = objhdr_set_cap56 (((JSFrame *)new_ptr)->header, new_cap);
/* Stash ORIGINAL size for from-space linear walks */
*hdr_ptr = objhdr_make_fwd (new_ptr);
*((size_t *)((uint8_t *)hdr_ptr + sizeof (objhdr_t))) = size;