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 */
|
||||
|
||||
Reference in New Issue
Block a user