Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbd27e0783 |
@@ -190,6 +190,8 @@ else
|
|||||||
deps += chipmunk_dep
|
deps += chipmunk_dep
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
deps += dependency('libffi', static:true)
|
||||||
|
|
||||||
if host_machine.system() != 'emscripten'
|
if host_machine.system() != 'emscripten'
|
||||||
# Try to find system-installed enet first
|
# Try to find system-installed enet first
|
||||||
enet_dep = dependency('enet', static: true, required: false)
|
enet_dep = dependency('enet', static: true, required: false)
|
||||||
@@ -271,7 +273,7 @@ src += [
|
|||||||
'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c',
|
'anim.c', 'config.c', 'datastream.c','font.c','HandmadeMath.c','jsffi.c','model.c',
|
||||||
'render.c','simplex.c','spline.c', 'transform.c','cell.c', 'wildmatch.c',
|
'render.c','simplex.c','spline.c', 'transform.c','cell.c', 'wildmatch.c',
|
||||||
'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c',
|
'sprite.c', 'rtree.c', 'qjs_nota.c', 'qjs_soloud.c', 'qjs_sdl.c', 'qjs_sdl_input.c', 'qjs_sdl_video.c', 'qjs_sdl_surface.c', 'qjs_math.c', 'qjs_geometry.c', 'qjs_transform.c', 'qjs_sprite.c', 'qjs_io.c', 'qjs_fd.c', 'qjs_os.c', 'qjs_actor.c',
|
||||||
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'qjs_num.c', 'timer.c', 'qjs_socket.c', 'qjs_kim.c', 'qjs_utf8.c', 'qjs_fit.c', 'qjs_text.c'
|
'qjs_qr.c', 'qjs_wota.c', 'monocypher.c', 'qjs_blob.c', 'qjs_crypto.c', 'qjs_time.c', 'qjs_http.c', 'qjs_rtree.c', 'qjs_spline.c', 'qjs_js.c', 'qjs_debug.c', 'picohttpparser.c', 'qjs_miniz.c', 'qjs_num.c', 'timer.c', 'qjs_socket.c', 'qjs_kim.c', 'qjs_utf8.c', 'qjs_fit.c', 'qjs_text.c', 'point.c', 'qjs_ffi.c'
|
||||||
]
|
]
|
||||||
# quirc src
|
# quirc src
|
||||||
src += [
|
src += [
|
||||||
|
|||||||
@@ -1546,6 +1546,7 @@ JSC_CCALL(os_value_id,
|
|||||||
#include "qjs_wota.h"
|
#include "qjs_wota.h"
|
||||||
#include "qjs_socket.h"
|
#include "qjs_socket.h"
|
||||||
#include "qjs_nota.h"
|
#include "qjs_nota.h"
|
||||||
|
#include "qjs_ffi.h"
|
||||||
|
|
||||||
//JSValue js_imgui_use(JSContext *js);
|
//JSValue js_imgui_use(JSContext *js);
|
||||||
#define MISTLINE(NAME) (ModuleEntry){#NAME, js_##NAME##_use}
|
#define MISTLINE(NAME) (ModuleEntry){#NAME, js_##NAME##_use}
|
||||||
@@ -1581,6 +1582,7 @@ void ffi_load(JSContext *js)
|
|||||||
arrput(rt->module_registry, MISTLINE(text));
|
arrput(rt->module_registry, MISTLINE(text));
|
||||||
arrput(rt->module_registry, MISTLINE(wota));
|
arrput(rt->module_registry, MISTLINE(wota));
|
||||||
arrput(rt->module_registry, MISTLINE(nota));
|
arrput(rt->module_registry, MISTLINE(nota));
|
||||||
|
arrput(rt->module_registry, MISTLINE(ffi));
|
||||||
|
|
||||||
// power user
|
// power user
|
||||||
arrput(rt->module_registry, MISTLINE(js));
|
arrput(rt->module_registry, MISTLINE(js));
|
||||||
|
|||||||
413
source/qjs_ffi.c
Normal file
413
source/qjs_ffi.c
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
* qjs_ffi.c – QuickJS ↔ libffi bridge
|
||||||
|
*
|
||||||
|
* Works on macOS / Linux / Windows. See examples/ffi_test.js.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qjs_ffi.h"
|
||||||
|
#include <ffi.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef countof
|
||||||
|
#define countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* internal structs */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ffi_cif cif;
|
||||||
|
ffi_type **arg_types;
|
||||||
|
ffi_type *ret_type;
|
||||||
|
void *fn_ptr;
|
||||||
|
int nargs;
|
||||||
|
} ffi_func;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *ptr;
|
||||||
|
int is_library; /* 1 => real dlopen/LoadLibrary handle */
|
||||||
|
} ffi_pointer;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* QuickJS class plumbing */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static JSClassID js_ffi_func_id;
|
||||||
|
static JSClassID js_ffi_pointer_id;
|
||||||
|
|
||||||
|
static void ffi_func_free(ffi_func *f)
|
||||||
|
{
|
||||||
|
if (!f) return;
|
||||||
|
|
||||||
|
if (f->arg_types) {
|
||||||
|
for (int i = 0; i < f->nargs; i++) {
|
||||||
|
ffi_type *t = f->arg_types[i];
|
||||||
|
if (t && t != &ffi_type_void && t != &ffi_type_pointer &&
|
||||||
|
t != &ffi_type_sint8 && t != &ffi_type_uint8 &&
|
||||||
|
t != &ffi_type_sint16 && t != &ffi_type_uint16 &&
|
||||||
|
t != &ffi_type_sint32 && t != &ffi_type_uint32 &&
|
||||||
|
t != &ffi_type_sint64 && t != &ffi_type_uint64 &&
|
||||||
|
t != &ffi_type_float && t != &ffi_type_double)
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
free(f->arg_types);
|
||||||
|
}
|
||||||
|
|
||||||
|
ffi_type *rtp = f->ret_type;
|
||||||
|
if (rtp && rtp != &ffi_type_void && rtp != &ffi_type_pointer &&
|
||||||
|
rtp != &ffi_type_sint8 && rtp != &ffi_type_uint8 &&
|
||||||
|
rtp != &ffi_type_sint16 && rtp != &ffi_type_uint16 &&
|
||||||
|
rtp != &ffi_type_sint32 && rtp != &ffi_type_uint32 &&
|
||||||
|
rtp != &ffi_type_sint64 && rtp != &ffi_type_uint64 &&
|
||||||
|
rtp != &ffi_type_float && rtp != &ffi_type_double)
|
||||||
|
free(rtp);
|
||||||
|
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ffi_func_finalizer(JSRuntime *rt, JSValue val)
|
||||||
|
{
|
||||||
|
ffi_func *f = JS_GetOpaque(val, js_ffi_func_id);
|
||||||
|
if (f) ffi_func_free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ffi_pointer_free(ffi_pointer *p)
|
||||||
|
{
|
||||||
|
if (p->is_library && p->ptr) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
FreeLibrary((HMODULE)p->ptr);
|
||||||
|
#else
|
||||||
|
dlclose(p->ptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ffi_pointer_finalizer(JSRuntime *rt, JSValue val)
|
||||||
|
{
|
||||||
|
ffi_pointer *f = JS_GetOpaque(val, js_ffi_pointer_id);
|
||||||
|
if (!f) return;
|
||||||
|
ffi_pointer_free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSClassDef js_ffi_func_class = { "FFIFunction", .finalizer = ffi_func_finalizer };
|
||||||
|
static JSClassDef js_ffi_pointer_class = { "FFIPointer", .finalizer = ffi_pointer_finalizer };
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* helpers */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static JSValue
|
||||||
|
js_new_ffi_pointer(JSContext *ctx, void *ptr, int is_library)
|
||||||
|
{
|
||||||
|
JSValue obj = JS_NewObjectClass(ctx, js_ffi_pointer_id);
|
||||||
|
if (JS_IsException(obj)) return obj;
|
||||||
|
|
||||||
|
ffi_pointer *p = malloc(sizeof *p);
|
||||||
|
if (!p) { JS_FreeValue(ctx, obj); return JS_ThrowOutOfMemory(ctx); }
|
||||||
|
|
||||||
|
p->ptr = ptr;
|
||||||
|
p->is_library = is_library;
|
||||||
|
JS_SetOpaque(obj, p);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
js_get_ffi_pointer(JSContext *ctx, JSValueConst val)
|
||||||
|
{
|
||||||
|
ffi_pointer *p = JS_GetOpaque2(ctx, val, js_ffi_pointer_id);
|
||||||
|
return p ? p->ptr : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ffi_type *
|
||||||
|
js_to_ffi_type(JSContext *ctx, const char *name)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, "void")) return &ffi_type_void;
|
||||||
|
if (!strcmp(name, "pointer")) return &ffi_type_pointer;
|
||||||
|
if (!strcmp(name, "float")) return &ffi_type_float;
|
||||||
|
if (!strcmp(name, "double")) return &ffi_type_double;
|
||||||
|
if (!strcmp(name, "int8")) return &ffi_type_sint8;
|
||||||
|
if (!strcmp(name, "uint8")) return &ffi_type_uint8;
|
||||||
|
if (!strcmp(name, "int16")) return &ffi_type_sint16;
|
||||||
|
if (!strcmp(name, "uint16")) return &ffi_type_uint16;
|
||||||
|
if (!strcmp(name, "int32")) return &ffi_type_sint32;
|
||||||
|
if (!strcmp(name, "uint32")) return &ffi_type_uint32;
|
||||||
|
if (!strcmp(name, "int64")) return &ffi_type_sint64;
|
||||||
|
if (!strcmp(name, "uint64")) return &ffi_type_uint64;
|
||||||
|
|
||||||
|
/* synonyms */
|
||||||
|
if (!strcmp(name, "int")) return &ffi_type_sint32;
|
||||||
|
if (!strcmp(name, "uint")) return &ffi_type_uint32;
|
||||||
|
if (!strcmp(name, "char*") || !strcmp(name, "string"))
|
||||||
|
return &ffi_type_pointer;
|
||||||
|
|
||||||
|
JS_ThrowTypeError(ctx, "unknown FFI type \"%s\"", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* ffi.dlopen */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static JSValue
|
||||||
|
js_ffi_dlopen(JSContext *ctx, JSValueConst this_val,
|
||||||
|
int argc, JSValueConst *argv)
|
||||||
|
{
|
||||||
|
if (argc < 1)
|
||||||
|
return JS_ThrowTypeError(ctx, "dlopen: expected path or null");
|
||||||
|
|
||||||
|
const char *path = NULL;
|
||||||
|
if (!JS_IsNull(argv[0])) {
|
||||||
|
path = JS_ToCString(ctx, argv[0]);
|
||||||
|
if (!path) return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *h;
|
||||||
|
#ifdef _WIN32
|
||||||
|
h = path ? (void *)LoadLibraryA(path)
|
||||||
|
: (void *)GetModuleHandle(NULL);
|
||||||
|
#else
|
||||||
|
h = path ? dlopen(path, RTLD_LAZY | RTLD_LOCAL)
|
||||||
|
: dlopen(NULL, RTLD_LAZY | RTLD_LOCAL);
|
||||||
|
#endif
|
||||||
|
if (path) JS_FreeCString(ctx, path);
|
||||||
|
if (!h) return JS_ThrowInternalError(ctx, "dlopen failed");
|
||||||
|
|
||||||
|
/* ------------- FIX: only real libraries get is_library = 1 ------------- */
|
||||||
|
int is_library = (path != NULL); /* self handle must not be closed */
|
||||||
|
return js_new_ffi_pointer(ctx, h, is_library);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* ffi.prepare (unchanged from previous answer) */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static JSValue
|
||||||
|
js_ffi_prepare(JSContext *ctx, JSValueConst this_val,
|
||||||
|
int argc, JSValueConst *argv)
|
||||||
|
{
|
||||||
|
if (argc < 4)
|
||||||
|
return JS_ThrowTypeError(ctx,
|
||||||
|
"prepare: expected (lib, symbol, ret_type, arg_type_array)");
|
||||||
|
|
||||||
|
void *lib = js_get_ffi_pointer(ctx, argv[0]);
|
||||||
|
if (!lib) return JS_ThrowTypeError(ctx, "invalid library handle");
|
||||||
|
|
||||||
|
const char *sym = JS_ToCString(ctx, argv[1]);
|
||||||
|
if (!sym) return JS_EXCEPTION;
|
||||||
|
|
||||||
|
void *fn;
|
||||||
|
#ifdef _WIN32
|
||||||
|
fn = (void *)GetProcAddress((HMODULE)lib, sym);
|
||||||
|
#else
|
||||||
|
fn = dlsym(lib, sym);
|
||||||
|
#endif
|
||||||
|
if (!fn) {
|
||||||
|
JS_FreeCString(ctx, sym);
|
||||||
|
return JS_ThrowTypeError(ctx, "symbol \"%s\" not found", sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *rt_name = JS_ToCString(ctx, argv[2]);
|
||||||
|
if (!rt_name) { JS_FreeCString(ctx, sym); return JS_EXCEPTION; }
|
||||||
|
ffi_type *ret_type = js_to_ffi_type(ctx, rt_name);
|
||||||
|
JS_FreeCString(ctx, rt_name);
|
||||||
|
if (!ret_type) { JS_FreeCString(ctx, sym); return JS_EXCEPTION; }
|
||||||
|
|
||||||
|
if (!JS_IsArray(ctx, argv[3])) {
|
||||||
|
JS_FreeCString(ctx, sym);
|
||||||
|
return JS_ThrowTypeError(ctx, "arg_types must be an array");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t nargs = JS_ArrayLength(ctx, argv[3]);
|
||||||
|
|
||||||
|
ffi_func *f = calloc(1, sizeof *f);
|
||||||
|
if (!f) { JS_FreeCString(ctx, sym); return JS_ThrowOutOfMemory(ctx); }
|
||||||
|
|
||||||
|
f->fn_ptr = fn;
|
||||||
|
f->ret_type = ret_type;
|
||||||
|
f->nargs = (int)nargs;
|
||||||
|
|
||||||
|
if (nargs) {
|
||||||
|
f->arg_types = calloc(nargs, sizeof(ffi_type *));
|
||||||
|
if (!f->arg_types) {
|
||||||
|
JS_FreeCString(ctx, sym);
|
||||||
|
ffi_func_free(f);
|
||||||
|
return JS_ThrowOutOfMemory(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < nargs; i++) {
|
||||||
|
JSValue v = JS_GetPropertyUint32(ctx, argv[3], i);
|
||||||
|
const char *tn = JS_ToCString(ctx, v);
|
||||||
|
JS_FreeValue(ctx, v);
|
||||||
|
if (!tn) { JS_FreeCString(ctx, sym); ffi_func_free(f); return JS_EXCEPTION; }
|
||||||
|
|
||||||
|
f->arg_types[i] = js_to_ffi_type(ctx, tn);
|
||||||
|
JS_FreeCString(ctx, tn);
|
||||||
|
if (!f->arg_types[i]) {
|
||||||
|
JS_FreeCString(ctx, sym);
|
||||||
|
ffi_func_free(f);
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeCString(ctx, sym);
|
||||||
|
|
||||||
|
if (ffi_prep_cif(&f->cif, FFI_DEFAULT_ABI,
|
||||||
|
f->nargs, f->ret_type, f->arg_types) != FFI_OK) {
|
||||||
|
ffi_func_free(f);
|
||||||
|
return JS_ThrowInternalError(ctx, "ffi_prep_cif failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue obj = JS_NewObjectClass(ctx, js_ffi_func_id);
|
||||||
|
JS_SetOpaque(obj, f);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* box_result + js_ffi_call (unchanged) */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static JSValue
|
||||||
|
box_result(JSContext *ctx, ffi_type *t, void *data)
|
||||||
|
{
|
||||||
|
if (t == &ffi_type_void) return JS_NULL;
|
||||||
|
if (t == &ffi_type_pointer) return data ? js_new_ffi_pointer(ctx, *(void **)data, 0)
|
||||||
|
: JS_NULL;
|
||||||
|
|
||||||
|
if (t == &ffi_type_double) return JS_NewFloat64(ctx, *(double *)data);
|
||||||
|
if (t == &ffi_type_float) return JS_NewFloat64(ctx, (double)*(float *)data);
|
||||||
|
|
||||||
|
if (t == &ffi_type_sint8) return JS_NewInt32(ctx, *(int8_t *)data);
|
||||||
|
if (t == &ffi_type_uint8) return JS_NewUint32(ctx, *(uint8_t *)data);
|
||||||
|
if (t == &ffi_type_sint16) return JS_NewInt32(ctx, *(int16_t *)data);
|
||||||
|
if (t == &ffi_type_uint16) return JS_NewUint32(ctx, *(uint16_t *)data);
|
||||||
|
if (t == &ffi_type_sint32) return JS_NewInt32(ctx, *(int32_t *)data);
|
||||||
|
if (t == &ffi_type_uint32) return JS_NewUint32(ctx, *(uint32_t *)data);
|
||||||
|
if (t == &ffi_type_sint64) return JS_NewFloat64(ctx, (double)*(int64_t *)data);
|
||||||
|
if (t == &ffi_type_uint64) return JS_NewFloat64(ctx, (double)*(uint64_t *)data);
|
||||||
|
|
||||||
|
return JS_ThrowTypeError(ctx, "unsupported return type");
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue
|
||||||
|
js_ffi_call(JSContext *ctx, JSValueConst this_val,
|
||||||
|
int argc, JSValueConst *argv)
|
||||||
|
{
|
||||||
|
ffi_func *f = JS_GetOpaque2(ctx, this_val, js_ffi_func_id);
|
||||||
|
if (!f) return JS_EXCEPTION;
|
||||||
|
if (argc != f->nargs)
|
||||||
|
return JS_ThrowTypeError(ctx, "expected %d arguments, got %d",
|
||||||
|
f->nargs, argc);
|
||||||
|
|
||||||
|
/* one fixed stack block per argument ----------------------------------- */
|
||||||
|
typedef union {
|
||||||
|
double d;
|
||||||
|
float f;
|
||||||
|
int8_t i8; uint8_t u8;
|
||||||
|
int16_t i16; uint16_t u16;
|
||||||
|
int32_t i32; uint32_t u32;
|
||||||
|
int64_t i64; uint64_t u64;
|
||||||
|
void *p;
|
||||||
|
} arg_data_t;
|
||||||
|
|
||||||
|
arg_data_t data[f->nargs];
|
||||||
|
void *values[f->nargs];
|
||||||
|
const char *tmp_cstr[f->nargs]; /* only for JS strings */
|
||||||
|
memset(tmp_cstr, 0, sizeof tmp_cstr);
|
||||||
|
|
||||||
|
/* ---------- marshal JS → C (no malloc for scalars) ------------------- */
|
||||||
|
for (int i = 0; i < f->nargs; i++) {
|
||||||
|
ffi_type *t = f->arg_types[i];
|
||||||
|
|
||||||
|
/* numbers ------------------------------------------------------------ */
|
||||||
|
if (t != &ffi_type_pointer) {
|
||||||
|
double d;
|
||||||
|
if (JS_ToFloat64(ctx, &d, argv[i]))
|
||||||
|
goto arg_error;
|
||||||
|
|
||||||
|
if (t == &ffi_type_double) data[i].d = d;
|
||||||
|
else if (t == &ffi_type_float) data[i].f = (float)d;
|
||||||
|
else if (t == &ffi_type_sint8) data[i].i8 = (int8_t)d;
|
||||||
|
else if (t == &ffi_type_uint8) data[i].u8 = (uint8_t)d;
|
||||||
|
else if (t == &ffi_type_sint16) data[i].i16= (int16_t)d;
|
||||||
|
else if (t == &ffi_type_uint16) data[i].u16= (uint16_t)d;
|
||||||
|
else if (t == &ffi_type_sint32) data[i].i32= (int32_t)d;
|
||||||
|
else if (t == &ffi_type_uint32) data[i].u32= (uint32_t)d;
|
||||||
|
else if (t == &ffi_type_sint64) data[i].i64= (int64_t)d;
|
||||||
|
else if (t == &ffi_type_uint64) data[i].u64= (uint64_t)d;
|
||||||
|
else goto arg_error; /* should be unreachable */
|
||||||
|
|
||||||
|
values[i] = &data[i];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pointers ----------------------------------------------------------- */
|
||||||
|
if (JS_IsString(argv[i])) {
|
||||||
|
const char *s = JS_ToCString(ctx, argv[i]);
|
||||||
|
if (!s) goto arg_error;
|
||||||
|
tmp_cstr[i] = s; /* remember to free */
|
||||||
|
data[i].p = (void *)s;
|
||||||
|
} else {
|
||||||
|
data[i].p = js_get_ffi_pointer(ctx, argv[i]);
|
||||||
|
}
|
||||||
|
values[i] = &data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------- call ---------------------------------- */
|
||||||
|
uint8_t ret_space[16] = {0};
|
||||||
|
void *ret_buf = f->ret_type == &ffi_type_void ? NULL : (void *)ret_space;
|
||||||
|
|
||||||
|
ffi_call(&f->cif, FFI_FN(f->fn_ptr), ret_buf, values);
|
||||||
|
JSValue js_ret = box_result(ctx, f->ret_type, ret_buf);
|
||||||
|
|
||||||
|
/* --------------------------- cleanup ---------------------------------- */
|
||||||
|
for (int i = 0; i < f->nargs; i++)
|
||||||
|
if (tmp_cstr[i]) JS_FreeCString(ctx, tmp_cstr[i]);
|
||||||
|
|
||||||
|
return js_ret;
|
||||||
|
|
||||||
|
arg_error:
|
||||||
|
for (int i = 0; i < f->nargs; i++)
|
||||||
|
if (tmp_cstr[i]) JS_FreeCString(ctx, tmp_cstr[i]);
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* module init */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static const JSCFunctionListEntry js_ffi_funcs[] = {
|
||||||
|
JS_CFUNC_DEF("dlopen", 1, js_ffi_dlopen),
|
||||||
|
JS_CFUNC_DEF("prepare", 4, js_ffi_prepare),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const JSCFunctionListEntry js_ffi_func_funcs[] = {
|
||||||
|
JS_CFUNC_DEF("call", 1, js_ffi_call),
|
||||||
|
};
|
||||||
|
|
||||||
|
JSValue
|
||||||
|
js_ffi_use(JSContext *ctx)
|
||||||
|
{
|
||||||
|
JS_NewClassID(&js_ffi_func_id);
|
||||||
|
JS_NewClass(JS_GetRuntime(ctx), js_ffi_func_id, &js_ffi_func_class);
|
||||||
|
|
||||||
|
JSValue fn_proto = JS_NewObject(ctx);
|
||||||
|
JS_SetPropertyFunctionList(ctx, fn_proto, js_ffi_func_funcs, countof(js_ffi_func_funcs));
|
||||||
|
JS_SetClassProto(ctx, js_ffi_func_id, fn_proto);
|
||||||
|
|
||||||
|
JS_NewClassID(&js_ffi_pointer_id);
|
||||||
|
JS_NewClass(JS_GetRuntime(ctx), js_ffi_pointer_id, &js_ffi_pointer_class);
|
||||||
|
|
||||||
|
JSValue mod = JS_NewObject(ctx);
|
||||||
|
JS_SetPropertyFunctionList(ctx, mod, js_ffi_funcs, countof(js_ffi_funcs));
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
8
source/qjs_ffi.h
Normal file
8
source/qjs_ffi.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef QJS_FFI_H
|
||||||
|
#define QJS_FFI_H
|
||||||
|
|
||||||
|
#include "cell.h"
|
||||||
|
|
||||||
|
JSValue js_ffi_use(JSContext *ctx);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user