jscode
This commit is contained in:
141
source/mach.c
141
source/mach.c
@@ -460,6 +460,33 @@ JSFrameRegister *alloc_frame_register(JSContext *ctx, int slot_count) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
static JSValue js_new_register_code(JSContext *ctx, JSCodeRegister *code) {
|
||||
JSCode *jc;
|
||||
if (!code) return JS_EXCEPTION;
|
||||
jc = ct_alloc(ctx, sizeof(JSCode), 8);
|
||||
if (!jc) return JS_EXCEPTION;
|
||||
memset(jc, 0, sizeof(JSCode));
|
||||
jc->header = objhdr_make(0, OBJ_CODE, 0, 0, 0, 0);
|
||||
jc->kind = JS_CODE_KIND_REGISTER;
|
||||
jc->arity = (int16_t)code->arity;
|
||||
jc->u.reg.code = code;
|
||||
return JS_MKPTR(jc);
|
||||
}
|
||||
|
||||
static JSValue js_new_native_code(JSContext *ctx, void *fn_ptr, void *dl_handle,
|
||||
uint16_t nr_slots, int arity) {
|
||||
JSCode *jc = ct_alloc(ctx, sizeof(JSCode), 8);
|
||||
if (!jc) return JS_EXCEPTION;
|
||||
memset(jc, 0, sizeof(JSCode));
|
||||
jc->header = objhdr_make(0, OBJ_CODE, 0, 0, 0, 0);
|
||||
jc->kind = JS_CODE_KIND_NATIVE;
|
||||
jc->arity = (int16_t)arity;
|
||||
jc->u.native.fn_ptr = fn_ptr;
|
||||
jc->u.native.dl_handle = dl_handle;
|
||||
jc->u.native.nr_slots = nr_slots;
|
||||
return JS_MKPTR(jc);
|
||||
}
|
||||
|
||||
/* Create a register-based function from JSCodeRegister */
|
||||
JSValue js_new_register_function(JSContext *ctx, JSCodeRegister *code, JSValue env, JSValue outer_frame) {
|
||||
/* Protect env and outer_frame from GC — js_mallocz can trigger
|
||||
@@ -470,50 +497,84 @@ JSValue js_new_register_function(JSContext *ctx, JSCodeRegister *code, JSValue e
|
||||
JS_PushGCRef(ctx, &frame_ref);
|
||||
frame_ref.val = outer_frame;
|
||||
|
||||
JSFunction *fn = js_mallocz(ctx, sizeof(JSFunction));
|
||||
JSGCRef fn_ref;
|
||||
JSFunction *fn;
|
||||
JSValue code_obj;
|
||||
|
||||
JS_AddGCRef(ctx, &fn_ref);
|
||||
fn_ref.val = JS_NULL;
|
||||
|
||||
fn = js_mallocz(ctx, sizeof(JSFunction));
|
||||
if (!fn) {
|
||||
JS_DeleteGCRef(ctx, &fn_ref);
|
||||
JS_PopGCRef(ctx, &frame_ref);
|
||||
JS_PopGCRef(ctx, &env_ref);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
fn_ref.val = JS_MKPTR(fn);
|
||||
|
||||
fn->header = objhdr_make(0, OBJ_FUNCTION, 0, 0, 0, 0);
|
||||
fn->kind = JS_FUNC_KIND_REGISTER;
|
||||
fn->length = code->arity;
|
||||
fn->name = code->name;
|
||||
fn->u.reg.code = code;
|
||||
fn->u.reg.env_record = env_ref.val;
|
||||
fn->u.reg.outer_frame = frame_ref.val;
|
||||
code_obj = js_new_register_code(ctx, code);
|
||||
if (JS_IsException(code_obj)) {
|
||||
JS_DeleteGCRef(ctx, &fn_ref);
|
||||
JS_PopGCRef(ctx, &frame_ref);
|
||||
JS_PopGCRef(ctx, &env_ref);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
fn = JS_VALUE_GET_FUNCTION(fn_ref.val);
|
||||
fn->u.cell.code = code_obj;
|
||||
fn->u.cell.env_record = env_ref.val;
|
||||
fn->u.cell.outer_frame = frame_ref.val;
|
||||
|
||||
JSValue out = fn_ref.val;
|
||||
JS_DeleteGCRef(ctx, &fn_ref);
|
||||
JS_PopGCRef(ctx, &frame_ref);
|
||||
JS_PopGCRef(ctx, &env_ref);
|
||||
return JS_MKPTR(fn);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Create a native (QBE-compiled) function */
|
||||
JSValue js_new_native_function(JSContext *ctx, void *fn_ptr, void *dl_handle,
|
||||
uint16_t nr_slots, int arity, JSValue outer_frame) {
|
||||
JSGCRef frame_ref;
|
||||
JSGCRef fn_ref;
|
||||
JSFunction *fn;
|
||||
JSValue code_obj;
|
||||
JS_PushGCRef(ctx, &frame_ref);
|
||||
frame_ref.val = outer_frame;
|
||||
JS_AddGCRef(ctx, &fn_ref);
|
||||
fn_ref.val = JS_NULL;
|
||||
|
||||
JSFunction *fn = js_mallocz(ctx, sizeof(JSFunction));
|
||||
fn = js_mallocz(ctx, sizeof(JSFunction));
|
||||
if (!fn) {
|
||||
JS_DeleteGCRef(ctx, &fn_ref);
|
||||
JS_PopGCRef(ctx, &frame_ref);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
fn_ref.val = JS_MKPTR(fn);
|
||||
|
||||
fn->header = objhdr_make(0, OBJ_FUNCTION, 0, 0, 0, 0);
|
||||
fn->kind = JS_FUNC_KIND_NATIVE;
|
||||
fn->length = arity;
|
||||
fn->name = JS_NULL;
|
||||
fn->u.native.fn_ptr = fn_ptr;
|
||||
fn->u.native.dl_handle = dl_handle;
|
||||
fn->u.native.nr_slots = nr_slots;
|
||||
fn->u.native.outer_frame = frame_ref.val;
|
||||
code_obj = js_new_native_code(ctx, fn_ptr, dl_handle, nr_slots, arity);
|
||||
if (JS_IsException(code_obj)) {
|
||||
JS_DeleteGCRef(ctx, &fn_ref);
|
||||
JS_PopGCRef(ctx, &frame_ref);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
fn = JS_VALUE_GET_FUNCTION(fn_ref.val);
|
||||
fn->u.cell.code = code_obj;
|
||||
fn->u.cell.env_record = JS_NULL;
|
||||
fn->u.cell.outer_frame = frame_ref.val;
|
||||
|
||||
JSValue out = fn_ref.val;
|
||||
JS_DeleteGCRef(ctx, &fn_ref);
|
||||
JS_PopGCRef(ctx, &frame_ref);
|
||||
return JS_MKPTR(fn);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Binary operations helper */
|
||||
@@ -750,8 +811,8 @@ void __asan_on_error(void) {
|
||||
const char *file = NULL;
|
||||
uint16_t line = 0;
|
||||
uint32_t pc = is_first ? cur_pc : 0;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && fn->u.reg.code) {
|
||||
JSCodeRegister *code = fn->u.reg.code;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
file = code->filename_cstr;
|
||||
func_name = code->name_cstr;
|
||||
if (!is_first)
|
||||
@@ -787,8 +848,8 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
ctx->suspended_frame_ref.val = JS_NULL;
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = fn->u.reg.code;
|
||||
env = fn->u.reg.env_record;
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = ctx->suspended_pc;
|
||||
result = JS_NULL;
|
||||
#ifdef HAVE_ASAN
|
||||
@@ -1499,7 +1560,7 @@ vm_dispatch:
|
||||
/* Read env fresh from frame->function — C local env can go stale after GC */
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
JSValue key = code->cpool[bx];
|
||||
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
|
||||
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.cell.env_record;
|
||||
JSValue val = JS_GetProperty(ctx, cur_env, key);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
frame->slots[a] = val;
|
||||
@@ -1511,7 +1572,7 @@ vm_dispatch:
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
JSValue key = code->cpool[bx];
|
||||
JSValue val = JS_NULL;
|
||||
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
|
||||
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.cell.env_record;
|
||||
if (!JS_IsNull(cur_env)) {
|
||||
val = JS_GetProperty(ctx, cur_env, key);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
@@ -1528,7 +1589,7 @@ vm_dispatch:
|
||||
/* R(A) = outer_frame[B].slots[C] — walk lexical scope chain */
|
||||
int depth = b;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
JSFrameRegister *target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
JSFrameRegister *target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.cell.outer_frame);
|
||||
if (!target) {
|
||||
fprintf(stderr, "GETUP: NULL outer_frame at depth 0! pc=%d a=%d depth=%d slot=%d nr_slots=%d instr=0x%08x\n",
|
||||
pc-1, a, depth, c, code->nr_slots, instr);
|
||||
@@ -1537,7 +1598,7 @@ vm_dispatch:
|
||||
}
|
||||
for (int d = 1; d < depth; d++) {
|
||||
fn = JS_VALUE_GET_FUNCTION(target->function);
|
||||
JSFrameRegister *next = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
JSFrameRegister *next = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.cell.outer_frame);
|
||||
if (!next) {
|
||||
fprintf(stderr, "GETUP: NULL outer_frame at depth %d! pc=%d a=%d depth=%d slot=%d nr_slots=%d instr=0x%08x\n",
|
||||
d, pc-1, a, depth, c, code->nr_slots, instr);
|
||||
@@ -1554,10 +1615,10 @@ vm_dispatch:
|
||||
/* outer_frame[B].slots[C] = R(A) — walk lexical scope chain */
|
||||
int depth = b;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
JSFrameRegister *target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
JSFrameRegister *target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.cell.outer_frame);
|
||||
for (int d = 1; d < depth; d++) {
|
||||
fn = JS_VALUE_GET_FUNCTION(target->function);
|
||||
target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.reg.outer_frame);
|
||||
target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.cell.outer_frame);
|
||||
}
|
||||
target->slots[c] = frame->slots[a];
|
||||
VM_BREAK();
|
||||
@@ -1651,9 +1712,9 @@ vm_dispatch:
|
||||
const char *callee_file = "?";
|
||||
{
|
||||
JSFunction *callee_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
if (callee_fn->kind == JS_FUNC_KIND_REGISTER && callee_fn->u.reg.code) {
|
||||
if (callee_fn->u.reg.code->name_cstr) callee_name = callee_fn->u.reg.code->name_cstr;
|
||||
if (callee_fn->u.reg.code->filename_cstr) callee_file = callee_fn->u.reg.code->filename_cstr;
|
||||
if (callee_fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code) {
|
||||
if (JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->name_cstr) callee_name = JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->name_cstr;
|
||||
if (JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->filename_cstr) callee_file = JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->filename_cstr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1663,8 +1724,8 @@ vm_dispatch:
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = fn->u.reg.code;
|
||||
env = fn->u.reg.env_record;
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = ret_info >> 16;
|
||||
int ret_slot = ret_info & 0xFFFF;
|
||||
if (ret_slot != 0xFFFF) {
|
||||
@@ -1696,8 +1757,8 @@ vm_dispatch:
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = fn->u.reg.code;
|
||||
env = fn->u.reg.env_record;
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = ret_info >> 16;
|
||||
int ret_slot = ret_info & 0xFFFF;
|
||||
if (ret_slot != 0xFFFF) frame->slots[ret_slot] = result;
|
||||
@@ -1725,7 +1786,7 @@ vm_dispatch:
|
||||
if ((uint32_t)bx < code->func_count) {
|
||||
JSCodeRegister *fn_code = code->functions[bx];
|
||||
/* Read env fresh from frame->function — C local can be stale */
|
||||
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.reg.env_record;
|
||||
JSValue cur_env = JS_VALUE_GET_FUNCTION(frame->function)->u.cell.env_record;
|
||||
JSValue fn_val = js_new_register_function(ctx, fn_code, cur_env, frame_ref.val);
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
frame->slots[a] = fn_val;
|
||||
@@ -2112,7 +2173,7 @@ vm_dispatch:
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||
/* Register function: switch frames inline (fast path) */
|
||||
JSCodeRegister *fn_code = fn->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);
|
||||
@@ -2122,7 +2183,7 @@ vm_dispatch:
|
||||
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;
|
||||
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;
|
||||
@@ -2135,7 +2196,7 @@ vm_dispatch:
|
||||
frame = new_frame;
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
code = fn_code;
|
||||
env = fn->u.reg.env_record;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = code->entry_point;
|
||||
} else {
|
||||
/* C, native, or bytecode function */
|
||||
@@ -2182,7 +2243,7 @@ vm_dispatch:
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||
JSCodeRegister *fn_code = fn->u.reg.code;
|
||||
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
int current_slots = (int)objhdr_cap56(frame->header);
|
||||
|
||||
if (fn_code->nr_slots <= current_slots) {
|
||||
@@ -2197,7 +2258,7 @@ vm_dispatch:
|
||||
frame->function = fn_val;
|
||||
/* caller stays the same — we're reusing this frame */
|
||||
code = fn_code;
|
||||
env = fn->u.reg.env_record;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = code->entry_point;
|
||||
} else {
|
||||
/* SLOW PATH: callee needs more slots, must allocate */
|
||||
@@ -2210,7 +2271,7 @@ vm_dispatch:
|
||||
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;
|
||||
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 */
|
||||
@@ -2221,7 +2282,7 @@ vm_dispatch:
|
||||
frame = new_frame;
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
code = fn_code;
|
||||
env = fn->u.reg.env_record;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = code->entry_point;
|
||||
}
|
||||
} else {
|
||||
@@ -2249,8 +2310,8 @@ vm_dispatch:
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
JSFunction *ret_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = ret_fn->u.reg.code;
|
||||
env = ret_fn->u.reg.env_record;
|
||||
code = JS_VALUE_GET_CODE(ret_fn->u.cell.code)->u.reg.code;
|
||||
env = ret_fn->u.cell.env_record;
|
||||
pc = ret_info >> 16;
|
||||
int ret_slot = ret_info & 0xFFFF;
|
||||
if (ret_slot != 0xFFFF) frame->slots[ret_slot] = ret;
|
||||
@@ -2302,10 +2363,10 @@ vm_dispatch:
|
||||
uint32_t frame_pc = pc;
|
||||
for (;;) {
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = fn->u.reg.code;
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
/* Only enter handler if we're not already inside it */
|
||||
if (code->disruption_pc > 0 && frame_pc < code->disruption_pc) {
|
||||
env = fn->u.reg.env_record;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = code->disruption_pc;
|
||||
ctx->disruption_reported = FALSE;
|
||||
frame_ref.val = JS_MKPTR(frame); /* root handler frame for GC */
|
||||
|
||||
@@ -544,7 +544,7 @@ static JSValue *get_outer_frame_slots(JSValue *fp) {
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
if (fn->kind != JS_FUNC_KIND_NATIVE)
|
||||
return NULL;
|
||||
JSValue outer = fn->u.native.outer_frame;
|
||||
JSValue outer = fn->u.cell.outer_frame;
|
||||
if (JS_IsNull(outer))
|
||||
return NULL;
|
||||
JSFrameRegister *outer_frame = (JSFrameRegister *)JS_VALUE_GET_PTR(outer);
|
||||
@@ -780,11 +780,11 @@ void cell_rt_signal_tail_call(JSContext *ctx, void *fp, int64_t frame_slot) {
|
||||
JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
JSValue this_obj, int argc, JSValue *argv) {
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(func_obj);
|
||||
cell_compiled_fn fn = (cell_compiled_fn)f->u.native.fn_ptr;
|
||||
int nr_slots = f->u.native.nr_slots;
|
||||
cell_compiled_fn fn = (cell_compiled_fn)JS_VALUE_GET_CODE(f->u.cell.code)->u.native.fn_ptr;
|
||||
int nr_slots = JS_VALUE_GET_CODE(f->u.cell.code)->u.native.nr_slots;
|
||||
int arity = f->length;
|
||||
void *prev_dl_handle = g_current_dl_handle;
|
||||
g_current_dl_handle = f->u.native.dl_handle;
|
||||
g_current_dl_handle = JS_VALUE_GET_CODE(f->u.cell.code)->u.native.dl_handle;
|
||||
|
||||
#define RETURN_DISPATCH(v) \
|
||||
do { \
|
||||
@@ -832,7 +832,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
if (JS_IsFunction(frame->function)) {
|
||||
JSFunction *cur_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
if (cur_fn->kind == JS_FUNC_KIND_NATIVE)
|
||||
g_current_dl_handle = cur_fn->u.native.dl_handle;
|
||||
g_current_dl_handle = JS_VALUE_GET_CODE(cur_fn->u.cell.code)->u.native.dl_handle;
|
||||
}
|
||||
|
||||
JSValue result = fn(ctx, fp);
|
||||
@@ -865,7 +865,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
JS_RaiseDisrupt(ctx, "not a function");
|
||||
/* Resume caller with exception pending */
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)exc_fn->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -877,7 +877,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
|
||||
if (callee_fn->kind == JS_FUNC_KIND_NATIVE) {
|
||||
/* Native-to-native call — no C stack growth */
|
||||
cell_compiled_fn callee_ptr = (cell_compiled_fn)callee_fn->u.native.fn_ptr;
|
||||
cell_compiled_fn callee_ptr = (cell_compiled_fn)JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.native.fn_ptr;
|
||||
|
||||
if (pending_is_tail) {
|
||||
/* Tail call: replace current frame with the prepared callee frame. */
|
||||
@@ -921,7 +921,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val);
|
||||
fp = (JSValue *)frame->slots;
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)exc_fn->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
JS_PopGCRef(ctx, &callee_fn_ref);
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
@@ -959,7 +959,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
/* fn and fp still point to the calling native function's frame.
|
||||
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)exc_fn->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -990,7 +990,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = ret;
|
||||
/* Resume caller */
|
||||
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)caller_fn->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
} else {
|
||||
/* Regular call: store result and resume current function */
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
@@ -999,7 +999,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = ret;
|
||||
/* 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)cur_fn->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(cur_fn->u.cell.code)->u.native.fn_ptr;
|
||||
}
|
||||
}
|
||||
JS_PopGCRef(ctx, &callee_fn_ref);
|
||||
@@ -1033,7 +1033,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = JS_EXCEPTION;
|
||||
|
||||
JSFunction *exc_caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)exc_caller_fn->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1057,7 +1057,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = result;
|
||||
|
||||
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)caller_fn->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1098,8 +1098,8 @@ JSValue cell_rt_frame(JSContext *ctx, JSValue fn, int64_t nargs) {
|
||||
}
|
||||
int nr_slots = (int)nargs + 2;
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||
if (f->kind == JS_FUNC_KIND_NATIVE && f->u.native.nr_slots > nr_slots)
|
||||
nr_slots = f->u.native.nr_slots;
|
||||
if (f->kind == JS_FUNC_KIND_NATIVE && JS_VALUE_GET_CODE(f->u.cell.code)->u.native.nr_slots > nr_slots)
|
||||
nr_slots = JS_VALUE_GET_CODE(f->u.cell.code)->u.native.nr_slots;
|
||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, nr_slots);
|
||||
if (!new_frame) return JS_EXCEPTION;
|
||||
new_frame->function = fn;
|
||||
|
||||
@@ -120,8 +120,8 @@ typedef struct JSBlob JSBlob;
|
||||
typedef struct JSText JSText;
|
||||
typedef struct JSRecord JSRecord;
|
||||
typedef struct JSFunction JSFunction;
|
||||
typedef struct JSFrame JSFrame;
|
||||
typedef struct JSCode JSCode;
|
||||
typedef struct JSFrame JSFrame;
|
||||
|
||||
#define OBJHDR_CAP_SHIFT 8u
|
||||
#define OBJHDR_CAP_MASK (((objhdr_t)1ull << 56) - 1ull)
|
||||
@@ -278,7 +278,6 @@ typedef void (*JSLogCallback)(JSContext *ctx, const char *channel, const char *m
|
||||
/* Forward declaration for bytecode freeing */
|
||||
|
||||
#define JS_VALUE_GET_BLOB(v) ((JSBlob *)JS_VALUE_GET_PTR (v))
|
||||
#define JS_VALUE_GET_CODE(v) (JS_VALUE_GET_PTR (v))
|
||||
|
||||
#ifdef HEAP_CHECK
|
||||
void heap_check_fail(void *ptr, struct JSContext *ctx);
|
||||
@@ -286,6 +285,7 @@ void heap_check_fail(void *ptr, struct JSContext *ctx);
|
||||
#define JS_VALUE_GET_OBJ(v) ((JSRecord *)heap_check_chase(ctx, v))
|
||||
#define JS_VALUE_GET_TEXT(v) ((JSText *)heap_check_chase(ctx, v))
|
||||
#define JS_VALUE_GET_FUNCTION(v) ((JSFunction *)heap_check_chase(ctx, v))
|
||||
#define JS_VALUE_GET_CODE(v) ((JSCode *)heap_check_chase(ctx, v))
|
||||
#define JS_VALUE_GET_FRAME(v) ((JSFrame *)heap_check_chase(ctx, v))
|
||||
#define JS_VALUE_GET_STRING(v) ((JSText *)heap_check_chase(ctx, v))
|
||||
#define JS_VALUE_GET_RECORD(v) ((JSRecord *)heap_check_chase(ctx, v))
|
||||
@@ -294,6 +294,7 @@ void heap_check_fail(void *ptr, struct JSContext *ctx);
|
||||
#define JS_VALUE_GET_OBJ(v) ((JSRecord *)chase (v))
|
||||
#define JS_VALUE_GET_TEXT(v) ((JSText *)chase (v))
|
||||
#define JS_VALUE_GET_FUNCTION(v) ((JSFunction *)chase (v))
|
||||
#define JS_VALUE_GET_CODE(v) ((JSCode *)chase (v))
|
||||
#define JS_VALUE_GET_FRAME(v) ((JSFrame *)chase (v))
|
||||
#define JS_VALUE_GET_STRING(v) ((JSText *)chase (v))
|
||||
#define JS_VALUE_GET_RECORD(v) ((JSRecord *)chase (v))
|
||||
@@ -1341,6 +1342,27 @@ typedef enum {
|
||||
JS_FUNC_KIND_NATIVE, /* QBE-compiled native function */
|
||||
} JSFunctionKind;
|
||||
|
||||
typedef enum {
|
||||
JS_CODE_KIND_REGISTER = 1,
|
||||
JS_CODE_KIND_NATIVE = 2,
|
||||
} JSCodeKind;
|
||||
|
||||
typedef struct JSCode {
|
||||
objhdr_t header; /* OBJ_CODE */
|
||||
uint8_t kind;
|
||||
int16_t arity;
|
||||
union {
|
||||
struct {
|
||||
JSCodeRegister *code;
|
||||
} reg;
|
||||
struct {
|
||||
void *fn_ptr; /* compiled cell_fn_N pointer */
|
||||
void *dl_handle; /* dylib handle for dlsym lookups */
|
||||
uint16_t nr_slots; /* frame size for this function */
|
||||
} native;
|
||||
} u;
|
||||
} JSCode;
|
||||
|
||||
typedef struct JSFunction {
|
||||
objhdr_t header; /* must come first */
|
||||
JSValue name; /* function name as JSValue text */
|
||||
@@ -1353,16 +1375,10 @@ typedef struct JSFunction {
|
||||
int16_t magic;
|
||||
} cfunc;
|
||||
struct {
|
||||
JSCodeRegister *code; /* compiled register code (off-heap) */
|
||||
JSValue code; /* JSCode object (OBJ_CODE) */
|
||||
JSValue env_record; /* stone record, module environment */
|
||||
JSValue outer_frame; /* JSFrame JSValue, for closures */
|
||||
} reg;
|
||||
struct {
|
||||
void *fn_ptr; /* compiled cell_fn_N pointer */
|
||||
void *dl_handle; /* dylib handle for dlsym lookups */
|
||||
uint16_t nr_slots; /* frame size for this function */
|
||||
JSValue outer_frame; /* GC-traced, for closures */
|
||||
} native;
|
||||
} cell;
|
||||
} u;
|
||||
} JSFunction;
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ void heap_check_fail(void *ptr, JSContext *ctx) {
|
||||
JSFunction *fn = (JSFunction *)JS_VALUE_GET_PTR(frame->function);
|
||||
const char *name = NULL, *file = NULL;
|
||||
uint16_t line = 0;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && fn->u.reg.code) {
|
||||
JSCodeRegister *code = fn->u.reg.code;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
file = code->filename_cstr;
|
||||
name = code->name_cstr;
|
||||
if (!first)
|
||||
@@ -1394,14 +1394,14 @@ void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *fro
|
||||
JSFunction *fn = (JSFunction *)ptr;
|
||||
/* Scan the function name */
|
||||
fn->name = gc_copy_value (ctx, fn->name, from_base, from_end, to_base, to_free, to_end);
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && fn->u.reg.code) {
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
/* Scan code tree to arbitrary nesting depth */
|
||||
gc_scan_code_tree (ctx, fn->u.reg.code, from_base, from_end, to_base, to_free, to_end);
|
||||
gc_scan_code_tree (ctx, JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code, from_base, from_end, to_base, to_free, to_end);
|
||||
/* Scan outer_frame and env_record */
|
||||
fn->u.reg.outer_frame = gc_copy_value (ctx, fn->u.reg.outer_frame, from_base, from_end, to_base, to_free, to_end);
|
||||
fn->u.reg.env_record = gc_copy_value (ctx, fn->u.reg.env_record, from_base, from_end, to_base, to_free, to_end);
|
||||
fn->u.cell.outer_frame = gc_copy_value (ctx, fn->u.cell.outer_frame, from_base, from_end, to_base, to_free, to_end);
|
||||
fn->u.cell.env_record = gc_copy_value (ctx, fn->u.cell.env_record, from_base, from_end, to_base, to_free, to_end);
|
||||
} else if (fn->kind == JS_FUNC_KIND_NATIVE) {
|
||||
fn->u.native.outer_frame = gc_copy_value (ctx, fn->u.native.outer_frame, from_base, from_end, to_base, to_free, to_end);
|
||||
fn->u.cell.outer_frame = gc_copy_value (ctx, fn->u.cell.outer_frame, from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1434,10 +1434,10 @@ void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *fro
|
||||
objhdr_t fh = *(objhdr_t *)JS_VALUE_GET_PTR (frame->function);
|
||||
if (objhdr_type (fh) == OBJ_FUNCTION) {
|
||||
JSFunction *fn = (JSFunction *)JS_VALUE_GET_PTR (frame->function);
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && fn->u.reg.code) {
|
||||
if (fn->u.reg.code->name_cstr) fname = fn->u.reg.code->name_cstr;
|
||||
if (fn->u.reg.code->filename_cstr) ffile = fn->u.reg.code->filename_cstr;
|
||||
fnslots = fn->u.reg.code->nr_slots;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
if (JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->name_cstr) fname = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->name_cstr;
|
||||
if (JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->filename_cstr) ffile = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->filename_cstr;
|
||||
fnslots = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->nr_slots;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1543,8 +1543,8 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
}
|
||||
if (objhdr_type (fnh) == OBJ_FUNCTION) {
|
||||
JSFunction *fnp = (JSFunction *)JS_VALUE_GET_PTR (fn_v);
|
||||
if (fnp->kind == JS_FUNC_KIND_REGISTER && fnp->u.reg.code && fnp->u.reg.code->name_cstr)
|
||||
fn_name = fnp->u.reg.code->name_cstr;
|
||||
if (fnp->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fnp->u.cell.code)->u.reg.code && JS_VALUE_GET_CODE(fnp->u.cell.code)->u.reg.code->name_cstr)
|
||||
fn_name = JS_VALUE_GET_CODE(fnp->u.cell.code)->u.reg.code->name_cstr;
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "VALIDATE_GC: pre-gc frame %p slot[%llu] -> %p (chased %p) bad type %d (hdr=0x%llx) fn=%s\n",
|
||||
@@ -4740,8 +4740,8 @@ JSValue JS_CallInternal (JSContext *ctx, JSValue func_obj, JSValue this_obj,
|
||||
case JS_FUNC_KIND_C_DATA:
|
||||
return js_call_c_function (ctx, func_obj, this_obj, argc, argv);
|
||||
case JS_FUNC_KIND_REGISTER:
|
||||
return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv,
|
||||
f->u.reg.env_record, f->u.reg.outer_frame);
|
||||
return JS_CallRegisterVM (ctx, JS_VALUE_GET_CODE(f->u.cell.code)->u.reg.code, this_obj, argc, argv,
|
||||
f->u.cell.env_record, f->u.cell.outer_frame);
|
||||
case JS_FUNC_KIND_NATIVE:
|
||||
return cell_native_dispatch (ctx, func_obj, this_obj, argc, argv);
|
||||
default:
|
||||
@@ -4763,8 +4763,8 @@ JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, J
|
||||
case JS_FUNC_KIND_C:
|
||||
return js_call_c_function (ctx, func_obj, this_obj, argc, argv);
|
||||
case JS_FUNC_KIND_REGISTER:
|
||||
return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv,
|
||||
f->u.reg.env_record, f->u.reg.outer_frame);
|
||||
return JS_CallRegisterVM (ctx, JS_VALUE_GET_CODE(f->u.cell.code)->u.reg.code, this_obj, argc, argv,
|
||||
f->u.cell.env_record, f->u.cell.outer_frame);
|
||||
case JS_FUNC_KIND_NATIVE:
|
||||
return cell_native_dispatch (ctx, func_obj, this_obj, argc, argv);
|
||||
default:
|
||||
@@ -12751,8 +12751,8 @@ JSValue JS_GetStack(JSContext *ctx) {
|
||||
if (!JS_IsFunction(frame->function)) break;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && fn->u.reg.code) {
|
||||
JSCodeRegister *code = fn->u.reg.code;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
uint32_t pc = is_first ? cur_pc : (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
|
||||
frames[count].fn = code->name_cstr;
|
||||
frames[count].file = code->filename_cstr;
|
||||
|
||||
Reference in New Issue
Block a user