From da6f096a565ab55dfdcf3fd354b9e7c9d0766e35 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 10 Feb 2026 20:28:51 -0600 Subject: [PATCH] qbe rt --- compile.ce | 6 +- internal/bootstrap.mach | Bin 6364 -> 7976 bytes parse.mach | Bin 53003 -> 54337 bytes qbe_emit.cm | 100 +++++++++++++++- qbe_emit.mach | Bin 28132 -> 30553 bytes qbe_rt.c | 119 +----------------- source/qbe_helpers.c | 258 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 362 insertions(+), 121 deletions(-) diff --git a/compile.ce b/compile.ce index 6075f0f2..a7b95dd3 100644 --- a/compile.ce +++ b/compile.ce @@ -55,8 +55,10 @@ if (rc != 0) { return } -// Append wrapper function -var wrapper_cmd = `printf '\nexport function l $` + symbol + `(l %%ctx) {\n@entry\n %%frame =l alloc8 4096\n %%result =l call $cell_main(l %%ctx, l %%frame)\n ret %%result\n}\n' >> ` + tmp + `_fixed.ssa` +// Append wrapper function — called as symbol(ctx) by os.dylib_symbol. +// Delegates to cell_rt_module_entry which heap-allocates a frame +// (so closures survive) and calls cell_main. +var wrapper_cmd = `printf '\nexport function l $` + symbol + `(l %%ctx) {\n@entry\n %%result =l call $cell_rt_module_entry(l %%ctx)\n ret %%result\n}\n' >> ` + tmp + `_fixed.ssa` rc = os.system(wrapper_cmd) if (rc != 0) { print('wrapper append failed') diff --git a/internal/bootstrap.mach b/internal/bootstrap.mach index 7276d31a625e99e7b4a0557ffde8e64684320fbf..f2696e6932e007c2390c097037bcaef16003cede 100644 GIT binary patch literal 7976 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 literal 6364 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 LxTku-DXRYgC>J8p diff --git a/parse.mach b/parse.mach index 22336711880abfc57635dbf39928f54e617c6246..1da26295fd5ad145bbd97c274dee561b65566c8a 100644 GIT binary patch delta 10703 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 diff --git a/qbe_emit.cm b/qbe_emit.cm index bf94d71c..8ff6d0f9 100644 --- a/qbe_emit.cm +++ b/qbe_emit.cm @@ -89,6 +89,9 @@ var qbe_emit = function(ir, qbe) { var pn = null var sl = null var fop_id = 0 + var nr_elems = 0 + var ei = 0 + var elem_slot = 0 // Function signature: (ctx, frame_ptr) → JSValue emit(`export function l $${name}(l %ctx, l %fp) {`) @@ -105,6 +108,11 @@ var qbe_emit = function(ir, qbe) { i = i + 1 } + // Write-back: store SSA var to frame slot so closures see updates + var wb = function(slot) { + emit(` storel ${s(slot)}, %p${text(slot)}`) + } + // Walk instructions i = 0 while (i < length(instrs)) { @@ -126,18 +134,22 @@ var qbe_emit = function(ir, qbe) { if (op == "int") { emit(` ${s(a1)} =l copy ${text(a2 * 2)}`) + wb(a1) continue } if (op == "null") { emit(` ${s(a1)} =l copy ${text(qbe.js_null)}`) + wb(a1) continue } if (op == "true") { emit(` ${s(a1)} =l copy ${text(qbe.js_true)}`) + wb(a1) continue } if (op == "false") { emit(` ${s(a1)} =l copy ${text(qbe.js_false)}`) + wb(a1) continue } if (op == "access") { @@ -177,6 +189,7 @@ var qbe_emit = function(ir, qbe) { } else { emit(` ${s(a1)} =l copy ${text(qbe.js_null)}`) } + wb(a1) continue } @@ -184,6 +197,7 @@ var qbe_emit = function(ir, qbe) { if (op == "move") { emit(` ${s(a1)} =l copy ${s(a2)}`) + wb(a1) continue } @@ -193,30 +207,35 @@ var qbe_emit = function(ir, qbe) { p = fresh() emit(qbe.add_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "sub_int") { p = fresh() emit(qbe.sub_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "mul_int") { p = fresh() emit(qbe.mul_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "div_int") { p = fresh() emit(qbe.div_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "mod_int") { p = fresh() emit(qbe.mod_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } @@ -226,30 +245,35 @@ var qbe_emit = function(ir, qbe) { p = fresh() emit(qbe.add_float(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "sub_float") { p = fresh() emit(qbe.sub_float(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "mul_float") { p = fresh() emit(qbe.mul_float(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "div_float") { p = fresh() emit(qbe.div_float(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "mod_float") { p = fresh() emit(qbe.mod_float(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } @@ -259,6 +283,7 @@ var qbe_emit = function(ir, qbe) { p = fresh() emit(qbe.concat(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } @@ -269,6 +294,7 @@ var qbe_emit = function(ir, qbe) { emit(qbe.is_int(p, s(a2))) emit(qbe.new_bool(p + ".r", "%" + p)) emit(` ${s(a1)} =l copy %${p}.r`) + wb(a1) continue } if (op == "is_text") { @@ -276,6 +302,7 @@ var qbe_emit = function(ir, qbe) { emit(qbe.is_imm_text(p, s(a2))) emit(qbe.new_bool(p + ".r", "%" + p)) emit(` ${s(a1)} =l copy %${p}.r`) + wb(a1) continue } if (op == "is_num") { @@ -283,6 +310,7 @@ var qbe_emit = function(ir, qbe) { emit(qbe.is_number(p, s(a2))) emit(qbe.new_bool(p + ".r", "%" + p)) emit(` ${s(a1)} =l copy %${p}.r`) + wb(a1) continue } if (op == "is_bool") { @@ -290,6 +318,7 @@ var qbe_emit = function(ir, qbe) { emit(qbe.is_bool(p, s(a2))) emit(qbe.new_bool(p + ".r", "%" + p)) emit(` ${s(a1)} =l copy %${p}.r`) + wb(a1) continue } if (op == "is_null") { @@ -297,12 +326,14 @@ var qbe_emit = function(ir, qbe) { emit(qbe.is_null(p, s(a2))) emit(qbe.new_bool(p + ".r", "%" + p)) emit(` ${s(a1)} =l copy %${p}.r`) + wb(a1) continue } if (op == "is_identical") { p = fresh() emit(qbe.is_identical(p, s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } @@ -312,36 +343,42 @@ var qbe_emit = function(ir, qbe) { p = fresh() emit(qbe.eq_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "ne_int") { p = fresh() emit(qbe.ne_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "lt_int") { p = fresh() emit(qbe.lt_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "gt_int") { p = fresh() emit(qbe.gt_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "le_int") { p = fresh() emit(qbe.le_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "ge_int") { p = fresh() emit(qbe.ge_int(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } @@ -351,12 +388,14 @@ var qbe_emit = function(ir, qbe) { p = fresh() emit(qbe.eq_float(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "ne_float") { p = fresh() emit(qbe.ne_float(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "lt_float" || op == "gt_float" || op == "le_float" || op == "ge_float") { @@ -368,39 +407,46 @@ var qbe_emit = function(ir, qbe) { else if (op == "ge_float") fop_id = 5 emit(qbe.cmp_float != null ? cmp_float(p, "%ctx", s(a2), s(a3), fop_id) : ` %${p} =l call $qbe_float_cmp(l %ctx, w ${text(fop_id)}, l ${s(a2)}, l ${s(a3)})`) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "eq_text") { p = fresh() emit(qbe.eq_text(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "ne_text") { p = fresh() emit(qbe.ne_text(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "lt_text" || op == "gt_text" || op == "le_text" || op == "ge_text") { p = fresh() emit(` ${s(a1)} =l call $cell_rt_${op}(l %ctx, l ${s(a2)}, l ${s(a3)})`) + wb(a1) continue } if (op == "eq_bool") { p = fresh() emit(qbe.eq_bool(p, s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "ne_bool") { p = fresh() emit(qbe.ne_bool(p, s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "eq_tol" || op == "ne_tol") { emit(` ${s(a1)} =l call $cell_rt_${op}(l %ctx, l ${s(a2)}, l ${s(a3)})`) + wb(a1) continue } @@ -410,14 +456,17 @@ var qbe_emit = function(ir, qbe) { p = fresh() emit(qbe.lnot(p, "%ctx", s(a2))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "and") { emit(` ${s(a1)} =l and ${s(a2)}, ${s(a3)}`) + wb(a1) continue } if (op == "or") { emit(` ${s(a1)} =l or ${s(a2)}, ${s(a3)}`) + wb(a1) continue } @@ -427,42 +476,49 @@ var qbe_emit = function(ir, qbe) { p = fresh() emit(qbe.bnot(p, "%ctx", s(a2))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "bitand") { p = fresh() emit(qbe.band(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "bitor") { p = fresh() emit(qbe.bor(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "bitxor") { p = fresh() emit(qbe.bxor(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "shl") { p = fresh() emit(qbe.shl(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "shr") { p = fresh() emit(qbe.shr(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } if (op == "ushr") { p = fresh() emit(qbe.ushr(p, "%ctx", s(a2), s(a3))) emit(` ${s(a1)} =l copy %${p}`) + wb(a1) continue } @@ -476,32 +532,38 @@ var qbe_emit = function(ir, qbe) { } else { emit(` ${s(a1)} =l call $cell_rt_load_dynamic(l %ctx, l ${s(a2)}, l ${s(a3)})`) } + wb(a1) continue } if (op == "load_index") { emit(` ${s(a1)} =l call $cell_rt_load_index(l %ctx, l ${s(a2)}, l ${s(a3)})`) + wb(a1) continue } if (op == "load_dynamic") { emit(` ${s(a1)} =l call $cell_rt_load_dynamic(l %ctx, l ${s(a2)}, l ${s(a3)})`) + wb(a1) continue } if (op == "store_field") { + // IR: ["store_field", obj, val, prop] → C: (ctx, val, obj, name) pn = prop_name(a3) if (pn != null) { sl = intern_str(pn) - emit(` call $cell_rt_store_field(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${sl})`) + emit(` call $cell_rt_store_field(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${sl})`) } else { - emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${s(a3)})`) + emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${s(a3)})`) } continue } if (op == "store_index") { - emit(` call $cell_rt_store_index(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${s(a3)})`) + // IR: ["store_index", obj, val, idx] → C: (ctx, val, obj, idx) + emit(` call $cell_rt_store_index(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${s(a3)})`) continue } if (op == "store_dynamic") { - emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a1)}, l ${s(a2)}, l ${s(a3)})`) + // IR: ["store_dynamic", obj, val, key] → C: (ctx, val, obj, key) + emit(` call $cell_rt_store_dynamic(l %ctx, l ${s(a2)}, l ${s(a1)}, l ${s(a3)})`) continue } @@ -509,6 +571,7 @@ var qbe_emit = function(ir, qbe) { if (op == "get") { emit(` ${s(a1)} =l call $cell_rt_get_closure(l %ctx, l %fp, l ${text(a2)}, l ${text(a3)})`) + wb(a1) continue } if (op == "put") { @@ -569,6 +632,7 @@ var qbe_emit = function(ir, qbe) { if (op == "frame") { emit(` ${s(a1)} =l call $cell_rt_frame(l %ctx, l ${s(a2)}, l ${text(a3)})`) + wb(a1) continue } if (op == "setarg") { @@ -577,10 +641,12 @@ var qbe_emit = function(ir, qbe) { } if (op == "invoke") { emit(` ${s(a2)} =l call $cell_rt_invoke(l %ctx, l ${s(a1)})`) + wb(a2) continue } if (op == "goframe") { emit(` ${s(a1)} =l call $cell_rt_goframe(l %ctx, l ${s(a2)}, l ${text(a3)})`) + wb(a1) continue } if (op == "goinvoke") { @@ -591,7 +657,28 @@ var qbe_emit = function(ir, qbe) { // --- Function object creation --- if (op == "function") { - emit(` ${s(a1)} =l call $cell_rt_make_function(l %ctx, l ${text(a2)})`) + emit(` ${s(a1)} =l call $cell_rt_make_function(l %ctx, l ${text(a2)}, l %fp)`) + wb(a1) + continue + } + + // --- Record/Array creation --- + + if (op == "record") { + emit(` ${s(a1)} =l call $JS_NewObject(l %ctx)`) + wb(a1) + continue + } + if (op == "array") { + nr_elems = a2 != null ? a2 : 0 + emit(` ${s(a1)} =l call $JS_NewArray(l %ctx)`) + ei = 0 + while (ei < nr_elems) { + elem_slot = instr[3 + ei] + emit(` call $JS_SetPropertyUint32(l %ctx, l ${s(a1)}, l ${text(ei)}, l ${s(elem_slot)})`) + ei = ei + 1 + } + wb(a1) continue } @@ -603,6 +690,7 @@ var qbe_emit = function(ir, qbe) { } if (op == "pop") { emit(` ${s(a1)} =l call $cell_rt_pop(l %ctx, l ${s(a2)})`) + wb(a1) continue } @@ -619,10 +707,12 @@ var qbe_emit = function(ir, qbe) { } if (op == "delete") { emit(` ${s(a1)} =l call $cell_rt_delete(l %ctx, l ${s(a2)}, l ${s(a3)})`) + wb(a1) continue } if (op == "typeof") { emit(` ${s(a1)} =l call $cell_rt_typeof(l %ctx, l ${s(a2)})`) + wb(a1) continue } diff --git a/qbe_emit.mach b/qbe_emit.mach index a3bccfc254561e8ad1e488a5998bff075eff3857..7a41d10584a6908334a7e65c28094ed95dae3fc9 100644 GIT binary patch literal 30553 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 f2jYr? #include #include -#include -#include typedef uint64_t JSValue; typedef struct JSContext JSContext; @@ -80,112 +80,3 @@ extern JSValue JS_NewStringLen(JSContext *ctx, const char *str, size_t len); JSValue JS_NewString(JSContext *ctx, const char *str) { return JS_NewStringLen(ctx, str, strlen(str)); } - -/* ============================================================ - cell_rt_* stubs — error/fallback paths for QBE-compiled code - These are called from type-mismatch branches that should not - be reached in pure numeric code. - ============================================================ */ - -extern JSValue JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); - -void cell_rt_disrupt(JSContext *ctx) { - JS_ThrowTypeError(ctx, "type error in native code"); -} - -JSValue cell_rt_lt_text(JSContext *ctx, JSValue a, JSValue b) { - return JS_VAL_NULL; -} -JSValue cell_rt_gt_text(JSContext *ctx, JSValue a, JSValue b) { - return JS_VAL_NULL; -} -JSValue cell_rt_le_text(JSContext *ctx, JSValue a, JSValue b) { - return JS_VAL_NULL; -} -JSValue cell_rt_ge_text(JSContext *ctx, JSValue a, JSValue b) { - return JS_VAL_NULL; -} -JSValue cell_rt_eq_tol(JSContext *ctx, JSValue a, JSValue b) { - return JS_VAL_NULL; -} -JSValue cell_rt_ne_tol(JSContext *ctx, JSValue a, JSValue b) { - return JS_VAL_NULL; -} - -JSValue cell_rt_get_intrinsic(JSContext *ctx, const char *name) { - return JS_VAL_NULL; -} -JSValue cell_rt_load_field(JSContext *ctx, JSValue obj, const char *name) { - return JS_VAL_NULL; -} -JSValue cell_rt_load_dynamic(JSContext *ctx, JSValue obj, JSValue key) { - return JS_VAL_NULL; -} -JSValue cell_rt_load_index(JSContext *ctx, JSValue arr, JSValue idx) { - return JS_VAL_NULL; -} -void cell_rt_store_field(JSContext *ctx, JSValue val, JSValue obj, - const char *name) {} -void cell_rt_store_dynamic(JSContext *ctx, JSValue val, JSValue obj, - JSValue key) {} -void cell_rt_store_index(JSContext *ctx, JSValue val, JSValue arr, - JSValue idx) {} -JSValue cell_rt_get_closure(JSContext *ctx, void *fp, int64_t depth, - int64_t index) { - return JS_VAL_NULL; -} -void cell_rt_put_closure(JSContext *ctx, void *fp, JSValue val, int64_t depth, - int64_t index) {} -JSValue cell_rt_frame(JSContext *ctx, JSValue fn, int64_t nargs) { - return JS_VAL_NULL; -} -void cell_rt_setarg(JSValue frame, int64_t idx, JSValue val) {} -JSValue cell_rt_invoke(JSContext *ctx, JSValue frame) { return JS_VAL_NULL; } -JSValue cell_rt_goframe(JSContext *ctx, JSValue fn, int64_t nargs) { - return JS_VAL_NULL; -} -void cell_rt_goinvoke(JSContext *ctx, JSValue frame) {} -/* - * cell_rt_make_function — create a callable JS function wrapping a - * QBE-compiled cell_fn_N. Uses magic to store fn_idx, and dlsym to - * look up the compiled symbol at call time. - */ - -typedef JSValue (*cell_compiled_fn)(JSContext *ctx, void *fp); - -/* JS_CFUNC_generic_magic = 1 in the JSCFunctionEnum */ -#define QBE_JS_CFUNC_GENERIC_MAGIC 1 - -extern JSValue JS_NewCFunction2(JSContext *ctx, void *func, - const char *name, int length, - int cproto, int magic); - -static JSValue cell_fn_trampoline(JSContext *ctx, JSValue this_val, - int argc, JSValue *argv, int magic) { - char name[64]; - snprintf(name, sizeof(name), "cell_fn_%d", magic); - - cell_compiled_fn fn = (cell_compiled_fn)dlsym(RTLD_DEFAULT, name); - if (!fn) - return JS_ThrowTypeError(ctx, "native function %s not found", name); - - /* Allocate frame: slot 0 = this, slots 1..argc = args, rest zeroed */ - JSValue frame[512]; - memset(frame, 0, sizeof(frame)); - frame[0] = this_val; - for (int i = 0; i < argc && i < 511; i++) - frame[1 + i] = argv[i]; - - return fn(ctx, frame); -} - -JSValue cell_rt_make_function(JSContext *ctx, int64_t fn_idx) { - return JS_NewCFunction2(ctx, (void *)cell_fn_trampoline, "native_fn", - 0, QBE_JS_CFUNC_GENERIC_MAGIC, (int)fn_idx); -} -void cell_rt_push(JSContext *ctx, JSValue arr, JSValue val) {} -JSValue cell_rt_pop(JSContext *ctx, JSValue arr) { return JS_VAL_NULL; } -JSValue cell_rt_delete(JSContext *ctx, JSValue obj, JSValue key) { - return JS_VAL_NULL; -} -JSValue cell_rt_typeof(JSContext *ctx, JSValue val) { return JS_VAL_NULL; } diff --git a/source/qbe_helpers.c b/source/qbe_helpers.c index 210dc677..d5aab35d 100644 --- a/source/qbe_helpers.c +++ b/source/qbe_helpers.c @@ -192,3 +192,261 @@ JSValue qbe_shift_shr(JSContext *ctx, JSValue a, JSValue b) { JS_ToInt32(ctx, &ib, b); return JS_NewInt32(ctx, (uint32_t)ia >> (ib & 31)); } + +/* ============================================================ + cell_rt_* — Runtime support for QBE-compiled code + ============================================================ */ + +#include +#include + +/* --- Property access --- */ + +JSValue cell_rt_load_field(JSContext *ctx, JSValue obj, const char *name) { + return JS_GetPropertyStr(ctx, obj, name); +} + +void cell_rt_store_field(JSContext *ctx, JSValue val, JSValue obj, + const char *name) { + JS_SetPropertyStr(ctx, obj, name, val); +} + +JSValue cell_rt_load_dynamic(JSContext *ctx, JSValue obj, JSValue key) { + if (JS_IsInt(key)) + return JS_GetPropertyUint32(ctx, obj, (uint32_t)JS_VALUE_GET_INT(key)); + return JS_GetProperty(ctx, obj, key); +} + +void cell_rt_store_dynamic(JSContext *ctx, JSValue val, JSValue obj, + JSValue key) { + if (JS_IsInt(key)) + JS_SetPropertyUint32(ctx, obj, (uint32_t)JS_VALUE_GET_INT(key), val); + else + JS_SetProperty(ctx, obj, key, val); +} + +JSValue cell_rt_load_index(JSContext *ctx, JSValue arr, JSValue idx) { + if (JS_IsInt(idx)) + return JS_GetPropertyUint32(ctx, arr, (uint32_t)JS_VALUE_GET_INT(idx)); + return JS_GetProperty(ctx, arr, idx); +} + +void cell_rt_store_index(JSContext *ctx, JSValue val, JSValue arr, + JSValue idx) { + if (JS_IsInt(idx)) + JS_SetPropertyUint32(ctx, arr, (uint32_t)JS_VALUE_GET_INT(idx), val); + else + JS_SetProperty(ctx, arr, idx, val); +} + +/* --- Intrinsic/global lookup --- */ + +JSValue cell_rt_get_intrinsic(JSContext *ctx, const char *name) { + return JS_GetPropertyStr(ctx, ctx->global_obj, name); +} + +/* --- Closure access --- + Slot 511 in each frame stores a pointer to the enclosing frame. + Walking depth levels up the chain gives the target frame. */ + +#define QBE_FRAME_OUTER_SLOT 511 + +JSValue cell_rt_get_closure(JSContext *ctx, void *fp, int64_t depth, + int64_t slot) { + JSValue *frame = (JSValue *)fp; + for (int64_t d = 0; d < depth; d++) { + void *outer = (void *)(uintptr_t)frame[QBE_FRAME_OUTER_SLOT]; + if (!outer) return JS_NULL; + frame = (JSValue *)outer; + } + return frame[slot]; +} + +void cell_rt_put_closure(JSContext *ctx, void *fp, JSValue val, int64_t depth, + int64_t slot) { + JSValue *frame = (JSValue *)fp; + for (int64_t d = 0; d < depth; d++) { + void *outer = (void *)(uintptr_t)frame[QBE_FRAME_OUTER_SLOT]; + if (!outer) return; + frame = (JSValue *)outer; + } + frame[slot] = val; +} + +/* --- Function creation and calling --- */ + +typedef JSValue (*cell_compiled_fn)(JSContext *ctx, void *fp); + +/* Table mapping fn_idx → outer_fp at creation time. + Valid for single-threaded, non-recursive closure patterns. */ +#define MAX_QBE_FUNCTIONS 256 +static void *g_outer_fp[MAX_QBE_FUNCTIONS]; + +static JSValue cell_fn_trampoline(JSContext *ctx, JSValue this_val, + int argc, JSValue *argv, int magic) { + char name[64]; + snprintf(name, sizeof(name), "cell_fn_%d", magic); + + cell_compiled_fn fn = (cell_compiled_fn)dlsym(RTLD_DEFAULT, name); + if (!fn) + return JS_ThrowTypeError(ctx, "native function %s not found", name); + + /* Allocate frame: slot 0 = this, slots 1..argc = args */ + JSValue frame[512]; + memset(frame, 0, sizeof(frame)); + frame[0] = this_val; + for (int i = 0; i < argc && i < 510; i++) + frame[1 + i] = argv[i]; + + /* Link to outer frame for closure access */ + if (magic >= 0 && magic < MAX_QBE_FUNCTIONS) + frame[QBE_FRAME_OUTER_SLOT] = (JSValue)(uintptr_t)g_outer_fp[magic]; + + return fn(ctx, frame); +} + +JSValue cell_rt_make_function(JSContext *ctx, int64_t fn_idx, void *outer_fp) { + if (fn_idx >= 0 && fn_idx < MAX_QBE_FUNCTIONS) + g_outer_fp[fn_idx] = outer_fp; + return JS_NewCFunction2(ctx, (JSCFunction *)cell_fn_trampoline, "native_fn", + 255, JS_CFUNC_generic_magic, (int)fn_idx); +} + +/* --- Frame-based function calling --- */ + +JSValue cell_rt_frame(JSContext *ctx, JSValue fn, int64_t nargs) { + if (!JS_IsFunction(fn)) { + JS_ThrowTypeError(ctx, "not a function"); + return JS_EXCEPTION; + } + int nr_slots = (int)nargs + 2; + JSFrameRegister *new_frame = alloc_frame_register(ctx, nr_slots); + if (!new_frame) return JS_EXCEPTION; + new_frame->function = fn; + return JS_MKPTR(new_frame); +} + +void cell_rt_setarg(JSValue frame_val, int64_t idx, JSValue val) { + JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val); + fr->slots[idx] = val; +} + +JSValue cell_rt_invoke(JSContext *ctx, JSValue frame_val) { + JSFrameRegister *fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val); + int nr_slots = (int)objhdr_cap56(fr->hdr); + int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0; + + /* Push args onto value stack (GC-safe) */ + int vs_base = ctx->value_stack_top; + for (int i = 0; i < c_argc; i++) + ctx->value_stack[vs_base + i] = fr->slots[i + 1]; + ctx->value_stack_top = vs_base + c_argc; + + JSValue result = JS_Call(ctx, fr->function, fr->slots[0], + c_argc, &ctx->value_stack[vs_base]); + ctx->value_stack_top = vs_base; + if (JS_IsException(result)) + return JS_EXCEPTION; + return result; +} + +JSValue cell_rt_goframe(JSContext *ctx, JSValue fn, int64_t nargs) { + return cell_rt_frame(ctx, fn, nargs); +} + +void cell_rt_goinvoke(JSContext *ctx, JSValue frame_val) { + cell_rt_invoke(ctx, frame_val); +} + +/* --- Array push/pop --- */ + +void cell_rt_push(JSContext *ctx, JSValue arr, JSValue val) { + JS_ArrayPush(ctx, &arr, val); +} + +JSValue cell_rt_pop(JSContext *ctx, JSValue arr) { + return JS_ArrayPop(ctx, arr); +} + +/* --- Delete --- */ + +JSValue cell_rt_delete(JSContext *ctx, JSValue obj, JSValue key) { + int ret = JS_DeleteProperty(ctx, obj, key); + return JS_NewBool(ctx, ret >= 0); +} + +/* --- Typeof --- */ + +JSValue cell_rt_typeof(JSContext *ctx, JSValue val) { + if (JS_IsNull(val)) return JS_NewString(ctx, "null"); + if (JS_IsInt(val) || JS_IsNumber(val)) return JS_NewString(ctx, "number"); + if (JS_IsBool(val)) return JS_NewString(ctx, "logical"); + if (JS_IsText(val)) return JS_NewString(ctx, "text"); + if (JS_IsFunction(val)) return JS_NewString(ctx, "function"); + if (JS_IsArray(val)) return JS_NewString(ctx, "array"); + if (JS_IsRecord(val)) return JS_NewString(ctx, "object"); + return JS_NewString(ctx, "unknown"); +} + +/* --- Text comparison stubs (called from QBE type-dispatch branches) --- */ + +JSValue cell_rt_lt_text(JSContext *ctx, JSValue a, JSValue b) { + const char *sa = JS_ToCString(ctx, a); + const char *sb = JS_ToCString(ctx, b); + int r = (sa && sb) ? strcmp(sa, sb) < 0 : 0; + return JS_NewBool(ctx, r); +} + +JSValue cell_rt_gt_text(JSContext *ctx, JSValue a, JSValue b) { + const char *sa = JS_ToCString(ctx, a); + const char *sb = JS_ToCString(ctx, b); + int r = (sa && sb) ? strcmp(sa, sb) > 0 : 0; + return JS_NewBool(ctx, r); +} + +JSValue cell_rt_le_text(JSContext *ctx, JSValue a, JSValue b) { + const char *sa = JS_ToCString(ctx, a); + const char *sb = JS_ToCString(ctx, b); + int r = (sa && sb) ? strcmp(sa, sb) <= 0 : 0; + return JS_NewBool(ctx, r); +} + +JSValue cell_rt_ge_text(JSContext *ctx, JSValue a, JSValue b) { + const char *sa = JS_ToCString(ctx, a); + const char *sb = JS_ToCString(ctx, b); + int r = (sa && sb) ? strcmp(sa, sb) >= 0 : 0; + return JS_NewBool(ctx, r); +} + +JSValue cell_rt_eq_tol(JSContext *ctx, JSValue a, JSValue b) { + return JS_NewBool(ctx, a == b); +} + +JSValue cell_rt_ne_tol(JSContext *ctx, JSValue a, JSValue b) { + return JS_NewBool(ctx, a != b); +} + +/* --- Disruption --- */ + +void cell_rt_disrupt(JSContext *ctx) { + JS_ThrowTypeError(ctx, "type error in native code"); +} + +/* --- Module entry point --- + Called as symbol(ctx) by os.dylib_symbol. Looks up cell_main + in the loaded dylib, builds a heap-allocated frame (so closures + can reference it after the module returns), and runs the module body. */ + +JSValue cell_rt_module_entry(JSContext *ctx) { + cell_compiled_fn fn = (cell_compiled_fn)dlsym(RTLD_DEFAULT, "cell_main"); + if (!fn) + return JS_ThrowTypeError(ctx, "cell_main not found in loaded dylib"); + + /* Heap-allocate so closures created in cell_main can reference + this frame after the module entry returns. */ + JSValue *frame = calloc(512, sizeof(JSValue)); + if (!frame) + return JS_ThrowTypeError(ctx, "frame allocation failed"); + + return fn(ctx, frame); +}