This commit is contained in:
2026-02-19 03:12:58 -06:00
parent ab43ab0d2c
commit 65fa37cc03
7 changed files with 886 additions and 54 deletions

View File

@@ -779,6 +779,22 @@ static int cell_check_call_arity(JSContext *ctx, JSFunction *fn, int argc) {
return 1;
}
static inline void cell_copy_args_0_4(JSValue *fp, JSValue *argv, int copy) {
/* fp[0] is `this`; copy args into fp[1..4] */
switch (copy) {
case 4: fp[4] = argv[3];
case 3: fp[3] = argv[2];
case 2: fp[2] = argv[1];
case 1: fp[1] = argv[0];
case 0: break;
default: break;
}
}
static inline void cell_sync_dl_from_native_fn(NativeRTState *st, JSFunction *fn) {
st->current_dl_handle = JS_VALUE_GET_CODE(fn->u.cell.code)->u.native.dl_handle;
}
/* Entry point called from JS_CallInternal / JS_Call / MACH_INVOKE
for JS_FUNC_KIND_NATIVE functions. */
JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
@@ -822,8 +838,14 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
fp[0] = this_obj;
int copy = (argc < arity) ? argc : arity;
if (copy < 0) copy = argc; /* variadic: copy all */
for (int i = 0; i < copy && i < nr_slots - 1; i++)
fp[1 + i] = argv[i];
if (copy > nr_slots - 1)
copy = nr_slots - 1;
if (unlikely(copy > 4)) {
JS_RaiseDisrupt(ctx, "native calls support at most 4 arguments");
RETURN_DISPATCH(JS_EXCEPTION);
}
if (copy > 0 && argv)
cell_copy_args_0_4(fp, argv, copy);
/* Link function to frame for closure access */
JSFrameRegister *frame = (JSFrameRegister *)((char *)fp - offsetof(JSFrameRegister, slots));
@@ -875,6 +897,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
/* Resume caller with exception pending */
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, exc_fn);
JS_PopGCRef(ctx, &callee_ref);
continue;
}
@@ -883,6 +906,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
if (!cell_check_call_arity(ctx, callee_fn, callee_argc)) {
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, exc_fn);
JS_PopGCRef(ctx, &callee_ref);
continue;
}
@@ -910,6 +934,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(aot_gc_ref_at(st, st->aot_depth - 1)->val);
fp = (JSValue *)frame->slots;
fn = callee_ptr;
cell_sync_dl_from_native_fn(st, callee_fn);
} else {
/* Regular call: link caller and push prepared callee frame. */
int ret_info = JS_VALUE_GET_INT(frame->address);
@@ -931,12 +956,14 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
fp = (JSValue *)frame->slots;
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, exc_fn);
JS_PopGCRef(ctx, &callee_ref);
continue;
}
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(aot_gc_ref_at(st, st->aot_depth - 1)->val);
fp = (JSValue *)frame->slots;
fn = callee_ptr;
cell_sync_dl_from_native_fn(st, callee_fn);
}
} else {
/* Non-native callee (C function, register VM, etc.) —
@@ -968,6 +995,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
Just resume it — it will detect JS_EXCEPTION in the return slot. */
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, exc_fn);
JS_PopGCRef(ctx, &callee_ref);
continue;
}
@@ -999,6 +1027,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
/* Resume caller */
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, caller_fn);
} else {
/* Regular call: store result and resume current function */
int ret_info = JS_VALUE_GET_INT(frame->address);
@@ -1008,6 +1037,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
/* fn stays the same — we resume the same function at next segment */
JSFunction *cur_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(cur_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, cur_fn);
}
}
JS_PopGCRef(ctx, &callee_ref);
@@ -1041,6 +1071,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
JSFunction *exc_caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_caller_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, exc_caller_fn);
continue;
}
@@ -1065,6 +1096,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
cell_sync_dl_from_native_fn(st, caller_fn);
continue;
}

View File

@@ -150,7 +150,10 @@ int JS_IsPretext (JSValue v) {
}
JSValue *JS_PushGCRef (JSContext *ctx, JSGCRef *ref) {
assert(ref != ctx->top_gc_ref && "JS_ROOT used in a loop — same address pushed twice");
if (ref == ctx->top_gc_ref) {
fprintf(stderr, "[warn] JS_PushGCRef duplicate top ref (non-fatal)\n");
return &ref->val;
}
ref->prev = ctx->top_gc_ref;
ctx->top_gc_ref = ref;
ref->val = JS_NULL;
@@ -158,13 +161,20 @@ 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");
ctx->top_gc_ref = ref->prev;
if (ctx->top_gc_ref == ref) {
ctx->top_gc_ref = ref->prev;
return ref->val;
}
fprintf(stderr, "[warn] JS_PopGCRef mismatched pop (non-fatal)\n");
return ref->val;
}
JSValue *JS_AddGCRef (JSContext *ctx, JSGCRef *ref) {
assert(ref != ctx->last_gc_ref && "JS_AddGCRef: same address added twice — cycle in GC ref list");
if (ref == ctx->last_gc_ref) {
fprintf(stderr, "[warn] JS_AddGCRef duplicate tail ref (non-fatal)\n");
return &ref->val;
}
ref->prev = ctx->last_gc_ref;
ctx->last_gc_ref = ref;
ref->val = JS_NULL;
@@ -10362,6 +10372,8 @@ static JSValue js_cell_pop (JSContext *ctx, JSValue this_val, int argc, JSValue
if (!JS_IsArray (obj)) return JS_NULL;
JSArray *arr = JS_VALUE_GET_ARRAY (obj);
if (objhdr_s (arr->mist_hdr))
return JS_RaiseDisrupt (ctx, "cannot pop from a stoned array");
if (arr->len == 0) return JS_NULL;