mach loading

This commit is contained in:
2026-02-13 07:26:49 -06:00
parent 4f18a0b524
commit 77fa058135
11 changed files with 7940 additions and 8637 deletions

View File

@@ -277,19 +277,37 @@ void cell_rt_put_closure(JSContext *ctx, void *fp, JSValue val, int64_t depth,
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];
/* Per-module function registry.
Each native .cm module gets its own dylib. When a module creates closures
via cell_rt_make_function, we record the dylib handle so the trampoline
can look up the correct cell_fn_N in the right dylib. */
#define MAX_NATIVE_FN 4096
static struct {
void *dl_handle;
int fn_idx;
void *outer_fp;
} g_native_fn_registry[MAX_NATIVE_FN];
static int g_native_fn_count = 0;
/* Set before executing a native module's cell_main */
static void *g_current_dl_handle = NULL;
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);
if (magic < 0 || magic >= g_native_fn_count)
return JS_ThrowTypeError(ctx, "invalid native function id %d", magic);
cell_compiled_fn fn = (cell_compiled_fn)dlsym(RTLD_DEFAULT, name);
void *handle = g_native_fn_registry[magic].dl_handle;
int fn_idx = g_native_fn_registry[magic].fn_idx;
char name[64];
snprintf(name, sizeof(name), "cell_fn_%d", fn_idx);
cell_compiled_fn fn = (cell_compiled_fn)dlsym(handle, name);
if (!fn)
return JS_ThrowTypeError(ctx, "native function %s not found", name);
return JS_ThrowTypeError(ctx, "native function %s not found in dylib", name);
/* Allocate frame: slot 0 = this, slots 1..argc = args */
JSValue frame[512];
@@ -299,17 +317,22 @@ static JSValue cell_fn_trampoline(JSContext *ctx, JSValue this_val,
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];
frame[QBE_FRAME_OUTER_SLOT] = (JSValue)(uintptr_t)g_native_fn_registry[magic].outer_fp;
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;
if (g_native_fn_count >= MAX_NATIVE_FN)
return JS_ThrowTypeError(ctx, "too many native functions (max %d)", MAX_NATIVE_FN);
int global_id = g_native_fn_count++;
g_native_fn_registry[global_id].dl_handle = g_current_dl_handle;
g_native_fn_registry[global_id].fn_idx = (int)fn_idx;
g_native_fn_registry[global_id].outer_fp = outer_fp;
return JS_NewCFunction2(ctx, (JSCFunction *)cell_fn_trampoline, "native_fn",
255, JS_CFUNC_generic_magic, (int)fn_idx);
255, JS_CFUNC_generic_magic, global_id);
}
/* --- Frame-based function calling --- */
@@ -430,20 +453,35 @@ void cell_rt_disrupt(JSContext *ctx) {
}
/* --- 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. */
Loads a native .cm module from a dylib handle.
Looks up cell_main, builds a heap-allocated frame, sets
g_current_dl_handle so closures register in the right module. */
JSValue cell_rt_module_entry(JSContext *ctx) {
cell_compiled_fn fn = (cell_compiled_fn)dlsym(RTLD_DEFAULT, "cell_main");
JSValue cell_rt_native_module_load(JSContext *ctx, void *dl_handle) {
cell_compiled_fn fn = (cell_compiled_fn)dlsym(dl_handle, "cell_main");
if (!fn)
return JS_ThrowTypeError(ctx, "cell_main not found in loaded dylib");
return JS_ThrowTypeError(ctx, "cell_main not found in native module dylib");
/* Set current handle so cell_rt_make_function registers closures
against this module's dylib */
void *prev_handle = g_current_dl_handle;
g_current_dl_handle = dl_handle;
/* 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)
if (!frame) {
g_current_dl_handle = prev_handle;
return JS_ThrowTypeError(ctx, "frame allocation failed");
}
return fn(ctx, frame);
JSValue result = fn(ctx, frame);
g_current_dl_handle = prev_handle;
return result;
}
/* Backward-compat: uses RTLD_DEFAULT (works when dylib opened with RTLD_GLOBAL) */
JSValue cell_rt_module_entry(JSContext *ctx) {
void *handle = dlopen(NULL, RTLD_LAZY);
return cell_rt_native_module_load(ctx, handle);
}