go reuses frames

This commit is contained in:
2026-02-15 19:45:17 -06:00
parent 23b201bdd7
commit 7fc4a205f6
2 changed files with 53 additions and 24 deletions

View File

@@ -1970,33 +1970,48 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
if (fn->kind == JS_FUNC_KIND_REGISTER) {
/* Register function: tail call by replacing current frame */
JSCodeRegister *fn_code = fn->u.reg.code;
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
if (!new_frame) {
int current_slots = (int)objhdr_cap56(frame->header);
if (fn_code->nr_slots <= current_slots) {
/* FAST PATH: reuse current frame — no allocation */
int copy_count = (c_argc < fn_code->arity) ? c_argc : fn_code->arity;
frame->slots[0] = fr->slots[0]; /* this */
for (int i = 0; i < copy_count; i++)
frame->slots[1 + i] = fr->slots[1 + i];
/* Null out remaining slots (locals/temps) */
for (int i = 1 + copy_count; i < current_slots; i++)
frame->slots[i] = JS_NULL;
frame->function = fn_val;
/* caller stays the same — we're reusing this frame */
code = fn_code;
env = fn->u.reg.env_record;
pc = code->entry_point;
} else {
/* SLOW PATH: callee needs more slots, must allocate */
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
if (!new_frame) {
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
}
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
goto disrupt;
fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
fn_val = fr->function;
fn = JS_VALUE_GET_FUNCTION(fn_val);
fn_code = fn->u.reg.code;
new_frame->function = fn_val;
int copy_count = (c_argc < fn_code->arity) ? c_argc : fn_code->arity;
new_frame->slots[0] = fr->slots[0]; /* this */
for (int i = 0; i < copy_count; i++)
new_frame->slots[1 + i] = fr->slots[1 + i];
new_frame->caller = frame->caller;
frame->caller = JS_NULL;
frame = new_frame;
frame_ref.val = JS_MKPTR(frame);
code = fn_code;
env = fn->u.reg.env_record;
pc = code->entry_point;
}
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
fn_val = fr->function;
fn = JS_VALUE_GET_FUNCTION(fn_val);
fn_code = fn->u.reg.code;
new_frame->function = fn_val;
/* Copy this + args from call frame to new frame */
int copy_count = (c_argc < fn_code->arity) ? c_argc : fn_code->arity;
new_frame->slots[0] = fr->slots[0]; /* this */
for (int i = 0; i < copy_count; i++)
new_frame->slots[1 + i] = fr->slots[1 + i];
/* Tail call: callee returns to OUR caller, not to us */
new_frame->caller = frame->caller;
frame->caller = JS_NULL; /* detach current frame */
/* Switch to callee */
frame = new_frame;
frame_ref.val = JS_MKPTR(frame);
code = fn_code;
env = fn->u.reg.env_record;
pc = code->entry_point;
} else {
/* C/bytecode function: call it, then return result to our caller */
ctx->reg_current_frame = frame_ref.val;