diff --git a/source/mach.c b/source/mach.c index 01a1c37b..ea08beda 100644 --- a/source/mach.c +++ b/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 */ diff --git a/source/qbe_helpers.c b/source/qbe_helpers.c index e12309c3..9f96f2b9 100644 --- a/source/qbe_helpers.c +++ b/source/qbe_helpers.c @@ -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; diff --git a/source/quickjs-internal.h b/source/quickjs-internal.h index 4688415d..73dcdad7 100644 --- a/source/quickjs-internal.h +++ b/source/quickjs-internal.h @@ -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; diff --git a/source/runtime.c b/source/runtime.c index 663d7900..8bc865a4 100644 --- a/source/runtime.c +++ b/source/runtime.c @@ -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;