This commit is contained in:
2026-02-19 00:33:16 -06:00
parent e59bfe19f7
commit 19132c1517
4 changed files with 161 additions and 84 deletions

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;