From 504e268b9d3502b94e7f4be35608e6d23672fa1f Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Tue, 10 Feb 2026 18:52:11 -0600 Subject: [PATCH] run native modules --- qbe_rt.c | 39 ++++++++++++++++++++++++++++++++++++++- run_native.ce | 26 ++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/qbe_rt.c b/qbe_rt.c index be2f9421..e6f50529 100644 --- a/qbe_rt.c +++ b/qbe_rt.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include typedef uint64_t JSValue; typedef struct JSContext JSContext; @@ -143,8 +145,43 @@ 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_VAL_NULL; + 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; } diff --git a/run_native.ce b/run_native.ce index ae7fc656..df3267a6 100644 --- a/run_native.ce +++ b/run_native.ce @@ -24,11 +24,25 @@ var symbol = 'js_' + safe + '_use' var dylib_path = './' + name + '.dylib' var fd = use('fd') +// --- Test argument for function-returning modules --- +var test_arg = 5000000 +if (length(args) > 1) { + test_arg = number(args[1]) +} + // --- Interpreted run --- print('--- interpreted ---') var t1 = os.now() -var result_interp = use(name) +var mod_interp = use(name) var t2 = os.now() +var result_interp = null +if (is_function(mod_interp)) { + print('module returns a function, calling with ' + text(test_arg)) + t1 = os.now() + result_interp = mod_interp(test_arg) + t2 = os.now() +} +result_interp = result_interp != null ? result_interp : mod_interp var ms_interp = (t2 - t1) / 1000000 print('result: ' + text(result_interp)) print('time: ' + text(ms_interp) + ' ms') @@ -43,8 +57,16 @@ print('\n--- native ---') var t3 = os.now() var lib = os.dylib_open(dylib_path) var t4 = os.now() -var result_native = os.dylib_symbol(lib, symbol) +var mod_native = os.dylib_symbol(lib, symbol) var t5 = os.now() +var result_native = null +if (is_function(mod_native)) { + print('module returns a function, calling with ' + text(test_arg)) + t4 = os.now() + result_native = mod_native(test_arg) + t5 = os.now() +} +result_native = result_native != null ? result_native : mod_native var ms_load = (t4 - t3) / 1000000 var ms_exec = (t5 - t4) / 1000000 var ms_native = (t5 - t3) / 1000000