quicker fn call
This commit is contained in:
3
mcode.cm
3
mcode.cm
@@ -706,9 +706,6 @@ var mcode = function(ast) {
|
|||||||
var argc = length(args)
|
var argc = length(args)
|
||||||
var frame_slot = alloc_slot()
|
var frame_slot = alloc_slot()
|
||||||
emit_3("frame", frame_slot, func_slot, argc)
|
emit_3("frame", frame_slot, func_slot, argc)
|
||||||
var null_slot = alloc_slot()
|
|
||||||
emit_1("null", null_slot)
|
|
||||||
emit_3("setarg", frame_slot, 0, null_slot)
|
|
||||||
var arg_idx = 1
|
var arg_idx = 1
|
||||||
var _i = 0
|
var _i = 0
|
||||||
while (_i < argc) {
|
while (_i < argc) {
|
||||||
|
|||||||
@@ -2567,7 +2567,15 @@ vm_dispatch:
|
|||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
goto disrupt;
|
goto disrupt;
|
||||||
}
|
}
|
||||||
int nr = c + 2; /* argc + this + func overhead */
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
|
||||||
|
int nr;
|
||||||
|
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||||
|
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||||
|
nr = fn_code->nr_slots;
|
||||||
|
if (nr < c + 2) nr = c + 2; /* safety: never smaller than argc+2 */
|
||||||
|
} else {
|
||||||
|
nr = c + 2;
|
||||||
|
}
|
||||||
JSFrameRegister *call_frame = alloc_frame_register(ctx, nr);
|
JSFrameRegister *call_frame = alloc_frame_register(ctx, nr);
|
||||||
if (!call_frame) {
|
if (!call_frame) {
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
@@ -2576,6 +2584,7 @@ vm_dispatch:
|
|||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||||
func_val = frame->slots[b]; /* re-read after GC */
|
func_val = frame->slots[b]; /* re-read after GC */
|
||||||
call_frame->function = func_val;
|
call_frame->function = func_val;
|
||||||
|
call_frame->address = JS_NewInt32(ctx, c); /* store actual argc */
|
||||||
frame->slots[a] = JS_MKPTR(call_frame);
|
frame->slots[a] = JS_MKPTR(call_frame);
|
||||||
VM_BREAK();
|
VM_BREAK();
|
||||||
}
|
}
|
||||||
@@ -2588,36 +2597,19 @@ vm_dispatch:
|
|||||||
VM_CASE(MACH_INVOKE): {
|
VM_CASE(MACH_INVOKE): {
|
||||||
/* A=frame_slot, B=result_slot */
|
/* A=frame_slot, B=result_slot */
|
||||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||||
int nr = (int)objhdr_cap56(fr->header);
|
int c_argc = JS_VALUE_GET_INT(fr->address); /* actual argc stored by FRAME */
|
||||||
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
|
||||||
JSValue fn_val = fr->function;
|
JSValue fn_val = fr->function;
|
||||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||||
if (!mach_check_call_arity(ctx, fn, c_argc))
|
if (!mach_check_call_arity(ctx, fn, c_argc))
|
||||||
goto disrupt;
|
goto disrupt;
|
||||||
|
|
||||||
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||||
/* Register function: switch frames inline (fast path) */
|
/* Register function: FRAME already allocated nr_slots — just switch */
|
||||||
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||||
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);
|
|
||||||
fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
|
||||||
fn_val = fr->function;
|
|
||||||
fn = JS_VALUE_GET_FUNCTION(fn_val);
|
|
||||||
fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->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];
|
|
||||||
/* Save return info */
|
/* Save return info */
|
||||||
frame->address = JS_NewInt32(ctx, (pc << 16) | b);
|
frame->address = JS_NewInt32(ctx, (pc << 16) | b);
|
||||||
new_frame->caller = JS_MKPTR(frame);
|
fr->caller = JS_MKPTR(frame);
|
||||||
frame = new_frame;
|
frame = fr;
|
||||||
frame_ref.val = JS_MKPTR(frame);
|
frame_ref.val = JS_MKPTR(frame);
|
||||||
code = fn_code;
|
code = fn_code;
|
||||||
env = fn->u.cell.env_record;
|
env = fn->u.cell.env_record;
|
||||||
@@ -2661,8 +2653,7 @@ vm_dispatch:
|
|||||||
VM_CASE(MACH_GOINVOKE): {
|
VM_CASE(MACH_GOINVOKE): {
|
||||||
/* Tail call: replace current frame with callee */
|
/* Tail call: replace current frame with callee */
|
||||||
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||||
int nr = (int)objhdr_cap56(fr->header);
|
int c_argc = JS_VALUE_GET_INT(fr->address); /* actual argc stored by FRAME */
|
||||||
int c_argc = (nr >= 2) ? nr - 2 : 0;
|
|
||||||
JSValue fn_val = fr->function;
|
JSValue fn_val = fr->function;
|
||||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||||
if (!mach_check_call_arity(ctx, fn, c_argc))
|
if (!mach_check_call_arity(ctx, fn, c_argc))
|
||||||
@@ -2687,25 +2678,10 @@ vm_dispatch:
|
|||||||
env = fn->u.cell.env_record;
|
env = fn->u.cell.env_record;
|
||||||
pc = code->entry_point;
|
pc = code->entry_point;
|
||||||
} else {
|
} else {
|
||||||
/* SLOW PATH: callee needs more slots, must allocate */
|
/* SLOW PATH: GOFRAME already allocated nr_slots — use fr directly */
|
||||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
|
fr->caller = frame->caller;
|
||||||
if (!new_frame) {
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
goto disrupt;
|
|
||||||
}
|
|
||||||
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 = JS_VALUE_GET_CODE(fn->u.cell.code)->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->caller = JS_NULL;
|
||||||
frame = new_frame;
|
frame = fr;
|
||||||
frame_ref.val = JS_MKPTR(frame);
|
frame_ref.val = JS_MKPTR(frame);
|
||||||
code = fn_code;
|
code = fn_code;
|
||||||
env = fn->u.cell.env_record;
|
env = fn->u.cell.env_record;
|
||||||
|
|||||||
Reference in New Issue
Block a user