MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add ffi

+817 -2
+4
.gitignore
··· 2 2 .cache 3 3 .env 4 4 5 + *.so 6 + *.dylib 7 + *.dll 8 + 5 9 /build 6 10 /subprojects/*/ 7 11 /subprojects/.wraplock
+33
examples/ffi/basic/printf.js
··· 1 + import { dlopen, FFIType } from 'ant:ffi'; 2 + 3 + let libcName; 4 + if (process.platform === 'darwin') { 5 + libcName = 'libSystem.dylib'; 6 + } else if (process.platform === 'linux') { 7 + libcName = 'libc.so.6'; 8 + } else if (process.platform === 'win32') { 9 + libcName = 'msvcrt.dll'; 10 + } else { 11 + throw new Error(`Unsupported platform: ${process.platform}`); 12 + } 13 + 14 + const libc = dlopen(libcName); 15 + 16 + libc.define('putchar', { 17 + args: [FFIType.int], 18 + returns: FFIType.int 19 + }); 20 + 21 + libc.define('printf', { 22 + args: [FFIType.string, FFIType.spread], 23 + returns: FFIType.int 24 + }); 25 + 26 + console.log('calling putchar(65):'); 27 + libc.call('putchar', 65); // 'A' 28 + 29 + console.log('\ncalling printf:'); 30 + libc.call('printf', 'Hello FFI! I see %d\n', 42); 31 + 32 + console.log('calling putchar(66):'); 33 + libc.call('putchar', 66); // 'B'
+10
examples/ffi/basic/sqlite3.js
··· 1 + import { dlopen, suffix, FFIType } from 'ant:ffi'; 2 + 3 + const sqlite3 = dlopen(`libsqlite3.${suffix}`); 4 + 5 + sqlite3.define('sqlite3_libversion', { 6 + args: [], 7 + returns: FFIType.string 8 + }); 9 + 10 + console.log(`SQLite 3 version: ${sqlite3.call('sqlite3_libversion')}`);
+20
examples/ffi/custom/mathlib.c
··· 1 + #include <stdio.h> 2 + 3 + int add(int a, int b) { 4 + return a + b; 5 + } 6 + 7 + int multiply(int a, int b) { 8 + return a * b; 9 + } 10 + 11 + void greet(const char* name) { 12 + printf("Hello, %s!\n", name); 13 + } 14 + 15 + double divide(double a, double b) { 16 + if (b != 0.0) { 17 + return a / b; 18 + } 19 + return 0.0; 20 + }
+39
examples/ffi/custom/mathlib.js
··· 1 + import { join } from 'ant:path'; 2 + import { dlopen, suffix, FFIType } from 'ant:ffi'; 3 + 4 + // compile the C library first: 5 + // clang -shared -fPIC -o mathlib.(so/dylib/dll) mathlib.c 6 + 7 + const mathlib = dlopen(join(import.meta.dirname, `mathlib.${suffix}`)); 8 + 9 + mathlib.define('add', { 10 + args: [FFIType.int, FFIType.int], 11 + returns: FFIType.int 12 + }); 13 + mathlib.define('multiply', { 14 + args: [FFIType.int, FFIType.int], 15 + returns: FFIType.int 16 + }); 17 + mathlib.define('greet', { 18 + args: [FFIType.string], 19 + returns: FFIType.void 20 + }); 21 + mathlib.define('divide', { 22 + args: [FFIType.double, FFIType.double], 23 + returns: FFIType.double 24 + }); 25 + 26 + const result1 = mathlib.call('add', 5, 3); 27 + console.log(`add(5, 3) = ${result1}`); 28 + 29 + const result2 = mathlib.call('multiply', 4, 7); 30 + console.log(`multiply(4, 7) = ${result2}`); 31 + 32 + console.log('Calling greet function:'); 33 + mathlib.call('greet', 'World'); 34 + 35 + const result3 = mathlib.call('divide', 10.0, 2.0); 36 + console.log(`divide(10.0, 2.0) = ${result3}`); 37 + 38 + const result4 = mathlib.call('divide', 10.0, 0.0); 39 + console.log(`divide(10.0, 0.0) = ${result4}`);
+8
include/modules/ffi.h
··· 1 + #ifndef ANT_FFI_H 2 + #define ANT_FFI_H 3 + 4 + #include "ant.h" 5 + 6 + jsval_t ffi_library(struct js *js); 7 + 8 + #endif
+6 -2
meson.build
··· 49 49 argtable3_dep = subproject('argtable3').get_variable('argtable3_dep') 50 50 minicoro_dep = subproject('minicoro').get_variable('minicoro_dep') 51 51 52 + libffi_dep = subproject('libffi', default_options: [ 53 + 'tests=false' 54 + ]).get_variable('ffi_dep') 55 + 52 56 libuv_dep = subproject('libuv', default_options: [ 53 57 'build_tests=false', 54 58 'build_benchmarks=false' ··· 69 73 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 70 74 71 75 version_conf = configuration_data() 72 - version_conf.set('ANT_VERSION', '0.0.7.11') 76 + version_conf.set('ANT_VERSION', '0.0.7.12') 73 77 version_conf.set('ANT_GIT_HASH', git_hash) 74 78 version_conf.set('ANT_BUILD_DATE', build_date) 75 79 ··· 117 121 tlsuv_dep, libsodium_dep, 118 122 yyjson_dep, minicoro_dep, 119 123 uuidv7_dep, openssl_dep, 120 - zlib_dep, uthash_dep 124 + zlib_dep, uthash_dep, libffi_dep 121 125 ] 122 126 123 127 if host_machine.system() == 'darwin'
+1
src/ant.c
··· 3362 3362 case TOK_TRUE: return js_mktrue(); 3363 3363 case TOK_FALSE: return js_mkfalse(); 3364 3364 case TOK_THIS: return js->this_val; 3365 + case TOK_VOID: return mkcoderef((jsoff_t) js->toff, (jsoff_t) js->tlen); 3365 3366 case TOK_DELETE: return mkcoderef((jsoff_t) js->toff, (jsoff_t) js->tlen); 3366 3367 case TOK_IMPORT: return mkcoderef((jsoff_t) js->toff, (jsoff_t) js->tlen); 3367 3368 case TOK_IDENTIFIER: return mkcoderef((jsoff_t) js->toff, (jsoff_t) js->tlen);
+3
src/main.c
··· 21 21 #include "modules/shell.h" 22 22 #include "modules/process.h" 23 23 #include "modules/path.h" 24 + #include "modules/ffi.h" 24 25 25 26 int js_result = EXIT_SUCCESS; 26 27 ··· 134 135 init_server_module(); 135 136 init_timer_module(); 136 137 init_process_module(); 138 + 137 139 138 140 ant_register_library("ant:fs", fs_library); 139 141 ant_register_library("ant:shell", shell_library); 140 142 ant_register_library("ant:path", path_library); 143 + ant_register_library("ant:ffi", ffi_library); 141 144 142 145 js_protect_init_memory(js); 143 146
+650
src/modules/ffi.c
··· 1 + #include <dlfcn.h> 2 + #include <ffi.h> 3 + #include <pthread.h> 4 + #include <stdlib.h> 5 + #include <string.h> 6 + #include <utarray.h> 7 + #include <uthash.h> 8 + 9 + #include "modules/ffi.h" 10 + 11 + typedef struct ffi_lib { 12 + char name[256]; 13 + void *handle; 14 + jsval_t js_obj; 15 + UT_hash_handle hh; 16 + } ffi_lib_t; 17 + 18 + typedef struct ffi_func { 19 + char name[256]; 20 + void *func_ptr; 21 + ffi_cif cif; 22 + ffi_type **arg_types; 23 + ffi_type *ret_type; 24 + char ret_type_str[32]; 25 + int arg_count; 26 + bool is_variadic; 27 + UT_hash_handle hh; 28 + } ffi_func_t; 29 + 30 + typedef struct ffi_ptr { 31 + void *ptr; 32 + size_t size; 33 + bool is_managed; 34 + uint64_t ptr_key; 35 + UT_hash_handle hh; 36 + } ffi_ptr_t; 37 + 38 + static ffi_lib_t *ffi_libraries = NULL; 39 + static ffi_ptr_t *ffi_pointers = NULL; 40 + static UT_array *ffi_functions_array = NULL; 41 + 42 + static pthread_mutex_t ffi_libraries_mutex = PTHREAD_MUTEX_INITIALIZER; 43 + static pthread_mutex_t ffi_functions_mutex = PTHREAD_MUTEX_INITIALIZER; 44 + static pthread_mutex_t ffi_pointers_mutex = PTHREAD_MUTEX_INITIALIZER; 45 + 46 + static const UT_icd ffi_func_icd = { 47 + .sz = sizeof(ffi_func_t *), 48 + .init = NULL, 49 + .copy = NULL, 50 + .dtor = NULL, 51 + }; 52 + 53 + static jsval_t ffi_dlopen(struct js *js, jsval_t *args, int nargs); 54 + static jsval_t ffi_define(struct js *js, jsval_t *args, int nargs); 55 + static jsval_t ffi_lib_call(struct js *js, jsval_t *args, int nargs); 56 + static jsval_t ffi_call_function(struct js *js, ffi_func_t *func, jsval_t *args, int nargs); 57 + static jsval_t ffi_alloc_memory(struct js *js, jsval_t *args, int nargs); 58 + static jsval_t ffi_free_memory(struct js *js, jsval_t *args, int nargs); 59 + static jsval_t ffi_read_memory(struct js *js, jsval_t *args, int nargs); 60 + static jsval_t ffi_write_memory(struct js *js, jsval_t *args, int nargs); 61 + static jsval_t ffi_get_pointer(struct js *js, jsval_t *args, int nargs); 62 + 63 + static ffi_type *get_ffi_type(const char *type_str); 64 + static void *js_to_ffi_value(struct js *js, jsval_t val, ffi_type *type, void *buffer); 65 + static jsval_t ffi_to_js_value(struct js *js, void *val, ffi_type *type, const char *type_str); 66 + 67 + jsval_t ffi_library(struct js *js) { 68 + jsval_t ffi_obj = js_mkobj(js); 69 + 70 + js_set(js, ffi_obj, "dlopen", js_mkfun(ffi_dlopen)); 71 + js_set(js, ffi_obj, "alloc", js_mkfun(ffi_alloc_memory)); 72 + js_set(js, ffi_obj, "free", js_mkfun(ffi_free_memory)); 73 + js_set(js, ffi_obj, "read", js_mkfun(ffi_read_memory)); 74 + js_set(js, ffi_obj, "write", js_mkfun(ffi_write_memory)); 75 + js_set(js, ffi_obj, "pointer", js_mkfun(ffi_get_pointer)); 76 + 77 + const char *suffix; 78 + #ifdef __APPLE__ 79 + suffix = "dylib"; 80 + #elif defined(__linux__) 81 + suffix = "so"; 82 + #elif defined(_WIN32) 83 + suffix = "dll"; 84 + #else 85 + suffix = "so"; 86 + #endif 87 + js_set(js, ffi_obj, "suffix", js_mkstr(js, suffix, strlen(suffix))); 88 + 89 + jsval_t ffi_types = js_mkobj(js); 90 + js_set(js, ffi_types, "void", js_mkstr(js, "void", 4)); 91 + js_set(js, ffi_types, "int8", js_mkstr(js, "int8", 4)); 92 + js_set(js, ffi_types, "int16", js_mkstr(js, "int16", 5)); 93 + js_set(js, ffi_types, "int", js_mkstr(js, "int", 3)); 94 + js_set(js, ffi_types, "int64", js_mkstr(js, "int64", 5)); 95 + js_set(js, ffi_types, "uint8", js_mkstr(js, "uint8", 5)); 96 + js_set(js, ffi_types, "uint16", js_mkstr(js, "uint16", 6)); 97 + js_set(js, ffi_types, "uint64", js_mkstr(js, "uint64", 6)); 98 + js_set(js, ffi_types, "float", js_mkstr(js, "float", 5)); 99 + js_set(js, ffi_types, "double", js_mkstr(js, "double", 6)); 100 + js_set(js, ffi_types, "pointer", js_mkstr(js, "pointer", 7)); 101 + js_set(js, ffi_types, "string", js_mkstr(js, "string", 6)); 102 + js_set(js, ffi_types, "spread", js_mkstr(js, "...", 3)); 103 + js_set(js, ffi_obj, "FFIType", ffi_types); 104 + 105 + return ffi_obj; 106 + } 107 + 108 + static void ffi_init_array(void) { 109 + static int initialized = 0; 110 + if (initialized) 111 + return; 112 + initialized = 1; 113 + if (!ffi_functions_array) 114 + utarray_new(ffi_functions_array, &ffi_func_icd); 115 + } 116 + 117 + static jsval_t ffi_dlopen(struct js *js, jsval_t *args, int nargs) { 118 + if (nargs < 1 || js_type(args[0]) != JS_STR) { 119 + return js_mkerr(js, "dlopen() requires library name string"); 120 + } 121 + 122 + ffi_init_array(); 123 + 124 + size_t lib_name_len; 125 + const char *lib_name = js_getstr(js, args[0], &lib_name_len); 126 + 127 + pthread_mutex_lock(&ffi_libraries_mutex); 128 + 129 + ffi_lib_t *lib = NULL; 130 + HASH_FIND_STR(ffi_libraries, lib_name, lib); 131 + if (lib) { 132 + jsval_t result = lib->js_obj; 133 + pthread_mutex_unlock(&ffi_libraries_mutex); 134 + return result; 135 + } 136 + 137 + pthread_mutex_unlock(&ffi_libraries_mutex); 138 + 139 + void *handle = dlopen(lib_name, RTLD_LAZY); 140 + if (!handle) { 141 + return js_mkerr(js, "Failed to load library: %s", dlerror()); 142 + } 143 + 144 + lib = (ffi_lib_t *)malloc(sizeof(ffi_lib_t)); 145 + if (!lib) { 146 + dlclose(handle); 147 + return js_mkerr(js, "Out of memory"); 148 + } 149 + 150 + strncpy(lib->name, lib_name, sizeof(lib->name) - 1); 151 + lib->name[sizeof(lib->name) - 1] = '\0'; 152 + lib->handle = handle; 153 + 154 + lib->js_obj = js_mkobj(js); 155 + js_set(js, lib->js_obj, "__lib_ptr", js_mknum((double)(uint64_t)lib)); 156 + js_set(js, lib->js_obj, "define", js_mkfun(ffi_define)); 157 + js_set(js, lib->js_obj, "call", js_mkfun(ffi_lib_call)); 158 + 159 + pthread_mutex_lock(&ffi_libraries_mutex); 160 + HASH_ADD_STR(ffi_libraries, name, lib); 161 + pthread_mutex_unlock(&ffi_libraries_mutex); 162 + 163 + return lib->js_obj; 164 + } 165 + 166 + static jsval_t ffi_define(struct js *js, jsval_t *args, int nargs) { 167 + if (nargs < 2 || js_type(args[0]) != JS_STR) { 168 + return js_mkerr(js, "define() requires function name string and signature"); 169 + } 170 + 171 + jsval_t this_obj = js_getthis(js); 172 + jsval_t lib_ptr_val = js_get(js, this_obj, "__lib_ptr"); 173 + if (js_type(lib_ptr_val) != JS_NUM) { 174 + return js_mkerr(js, "Invalid library object"); 175 + } 176 + 177 + size_t func_name_len; 178 + const char *func_name = js_getstr(js, args[0], &func_name_len); 179 + 180 + jsval_t sig = args[1]; 181 + int sig_type = js_type(sig); 182 + if (sig_type == JS_STR || sig_type == JS_NUM || sig_type == JS_NULL || 183 + sig_type == JS_UNDEF) { 184 + return js_mkerr(js, 185 + "Signature must be an array [returnType, [argTypes...]] or " 186 + "an object {args: [...], returns: type}"); 187 + } 188 + 189 + const char *ret_type_str; 190 + jsval_t arg_types_arr; 191 + int arg_count; 192 + 193 + jsval_t returns_val = js_get(js, sig, "returns"); 194 + jsval_t args_val = js_get(js, sig, "args"); 195 + 196 + if (js_type(returns_val) != JS_UNDEF && js_type(args_val) != JS_UNDEF) { 197 + if (js_type(returns_val) != JS_STR) { 198 + return js_mkerr(js, "Return type must be a string"); 199 + } 200 + ret_type_str = js_getstr(js, returns_val, NULL); 201 + arg_types_arr = args_val; 202 + 203 + if (js_type(arg_types_arr) == JS_STR || js_type(arg_types_arr) == JS_NUM || 204 + js_type(arg_types_arr) == JS_NULL || 205 + js_type(arg_types_arr) == JS_UNDEF) { 206 + return js_mkerr(js, "Argument types must be an array"); 207 + } 208 + 209 + jsval_t length_val = js_get(js, arg_types_arr, "length"); 210 + arg_count = (int)js_getnum(length_val); 211 + } else { 212 + jsval_t ret_type_val = js_get(js, sig, "0"); 213 + if (js_type(ret_type_val) != JS_STR) { 214 + return js_mkerr(js, "Return type must be a string"); 215 + } 216 + 217 + ret_type_str = js_getstr(js, ret_type_val, NULL); 218 + arg_types_arr = js_get(js, sig, "1"); 219 + 220 + int arg_arr_type = js_type(arg_types_arr); 221 + if (arg_arr_type == JS_STR || arg_arr_type == JS_NUM || 222 + arg_arr_type == JS_NULL || arg_arr_type == JS_UNDEF) { 223 + return js_mkerr(js, "Argument types must be an array"); 224 + } 225 + 226 + jsval_t length_val = js_get(js, arg_types_arr, "length"); 227 + arg_count = (int)js_getnum(length_val); 228 + } 229 + 230 + ffi_type *ret_type = get_ffi_type(ret_type_str); 231 + if (!ret_type) { 232 + return js_mkerr(js, "Unknown return type: %s", ret_type_str); 233 + } 234 + 235 + ffi_lib_t *lib = (ffi_lib_t *)(uint64_t)js_getnum(lib_ptr_val); 236 + void *func_ptr = dlsym(lib->handle, func_name); 237 + if (!func_ptr) { 238 + return js_mkerr(js, "Function '%s' not found", func_name); 239 + } 240 + 241 + ffi_func_t *func = (ffi_func_t *)malloc(sizeof(ffi_func_t)); 242 + if (!func) { 243 + return js_mkerr(js, "Out of memory"); 244 + } 245 + 246 + strncpy(func->name, func_name, sizeof(func->name) - 1); 247 + func->name[sizeof(func->name) - 1] = '\0'; 248 + func->func_ptr = func_ptr; 249 + func->ret_type = ret_type; 250 + strncpy(func->ret_type_str, ret_type_str, sizeof(func->ret_type_str) - 1); 251 + func->ret_type_str[sizeof(func->ret_type_str) - 1] = '\0'; 252 + func->arg_count = arg_count; 253 + func->is_variadic = false; 254 + 255 + if (arg_count > 0) { 256 + func->arg_types = (ffi_type **)malloc(sizeof(ffi_type *) * arg_count); 257 + if (!func->arg_types) { 258 + free(func); 259 + return js_mkerr(js, "Out of memory"); 260 + } 261 + 262 + for (int i = 0; i < arg_count; i++) { 263 + char idx_str[16]; 264 + snprintf(idx_str, sizeof(idx_str), "%d", i); 265 + jsval_t arg_type_val = js_get(js, arg_types_arr, idx_str); 266 + 267 + if (js_type(arg_type_val) != JS_STR) { 268 + free(func->arg_types); 269 + free(func); 270 + return js_mkerr(js, "Argument type must be a string"); 271 + } 272 + 273 + const char *arg_type_str = js_getstr(js, arg_type_val, NULL); 274 + 275 + if (strcmp(arg_type_str, "...") == 0) { 276 + func->is_variadic = true; 277 + func->arg_count = i; 278 + break; 279 + } 280 + 281 + func->arg_types[i] = get_ffi_type(arg_type_str); 282 + if (!func->arg_types[i]) { 283 + free(func->arg_types); 284 + free(func); 285 + return js_mkerr(js, "Unknown argument type: %s", arg_type_str); 286 + } 287 + } 288 + } else { 289 + func->arg_types = NULL; 290 + } 291 + 292 + if (!func->is_variadic) { 293 + ffi_status status = 294 + ffi_prep_cif(&func->cif, FFI_DEFAULT_ABI, func->arg_count, ret_type, func->arg_types); 295 + if (status != FFI_OK) { 296 + if (func->arg_types) 297 + free(func->arg_types); 298 + free(func); 299 + return js_mkerr(js, "Failed to prepare function call (status=%d, argc=%d)", status, func->arg_count); 300 + } 301 + } 302 + 303 + pthread_mutex_lock(&ffi_functions_mutex); 304 + utarray_push_back(ffi_functions_array, &func); 305 + unsigned int func_index = utarray_len(ffi_functions_array) - 1; 306 + pthread_mutex_unlock(&ffi_functions_mutex); 307 + 308 + char index_key[256]; 309 + snprintf(index_key, sizeof(index_key), "__ffi_index_%s", func_name); 310 + js_set(js, this_obj, index_key, js_mknum((double)func_index)); 311 + 312 + return js_mkundef(); 313 + } 314 + 315 + static jsval_t ffi_lib_call(struct js *js, jsval_t *args, int nargs) { 316 + jsval_t lib_obj = js_getthis(js); 317 + if (nargs < 1 || js_type(args[0]) != JS_STR) 318 + return js_mkerr(js, "call() requires function name string"); 319 + 320 + size_t func_name_len; 321 + const char *func_name = js_getstr(js, args[0], &func_name_len); 322 + 323 + char index_key[256]; 324 + snprintf(index_key, sizeof(index_key), "__ffi_index_%s", func_name); 325 + jsval_t index_val = js_get(js, lib_obj, index_key); 326 + 327 + if (js_type(index_val) != JS_NUM) { 328 + return js_mkerr(js, "Function '%s' not defined", func_name); 329 + } 330 + 331 + unsigned int func_index = (unsigned int)js_getnum(index_val); 332 + 333 + pthread_mutex_lock(&ffi_functions_mutex); 334 + if (func_index >= utarray_len(ffi_functions_array)) { 335 + pthread_mutex_unlock(&ffi_functions_mutex); 336 + return js_mkerr(js, "Invalid function index"); 337 + } 338 + 339 + ffi_func_t *func = 340 + *(ffi_func_t **)utarray_eltptr(ffi_functions_array, func_index); 341 + pthread_mutex_unlock(&ffi_functions_mutex); 342 + 343 + jsval_t *call_args = args + 1; 344 + int call_nargs = nargs - 1; 345 + 346 + return ffi_call_function(js, func, call_args, call_nargs); 347 + } 348 + 349 + static jsval_t ffi_call_function(struct js *js, ffi_func_t *func, jsval_t *args,int nargs) { 350 + if (!func->is_variadic && nargs != func->arg_count) { 351 + return js_mkerr(js, "Function '%s' expects %d arguments, got %d", func->name, func->arg_count, nargs); 352 + } 353 + 354 + if (func->is_variadic && nargs < func->arg_count) { 355 + return js_mkerr(js, "Function '%s' expects at least %d arguments, got %d", func->name, func->arg_count, nargs); 356 + } 357 + 358 + #define MAX_ARGS 32 359 + void *arg_values_buf[MAX_ARGS]; 360 + ffi_arg arg_buffers_buf[MAX_ARGS]; 361 + 362 + int actual_arg_count = func->is_variadic ? nargs : func->arg_count; 363 + 364 + if (actual_arg_count > MAX_ARGS) { 365 + return js_mkerr(js, "Too many arguments"); 366 + } 367 + 368 + void **arg_values = arg_values_buf; 369 + memset(arg_values, 0, sizeof(arg_values_buf)); 370 + 371 + for (int i = 0; i < actual_arg_count; i++) { 372 + arg_values[i] = &arg_buffers_buf[i]; 373 + memset(arg_values[i], 0, sizeof(ffi_arg)); 374 + 375 + ffi_type *arg_type; 376 + if (i < func->arg_count) { 377 + arg_type = func->arg_types[i]; 378 + } else arg_type = &ffi_type_sint32; 379 + 380 + js_to_ffi_value(js, args[i], arg_type, arg_values[i]); 381 + } 382 + 383 + ffi_arg result; 384 + memset(&result, 0, sizeof(result)); 385 + 386 + if (func->is_variadic) { 387 + #define MAX_VARIADIC_ARGS 32 388 + ffi_type *all_arg_types[MAX_VARIADIC_ARGS]; 389 + 390 + if (actual_arg_count > MAX_VARIADIC_ARGS) { 391 + return js_mkerr(js, "Too many variadic arguments"); 392 + } 393 + 394 + for (int i = 0; i < func->arg_count; i++) all_arg_types[i] = func->arg_types[i]; 395 + for (int i = func->arg_count; i < actual_arg_count; i++) all_arg_types[i] = &ffi_type_sint32; 396 + 397 + ffi_cif call_cif; 398 + ffi_status status = 399 + ffi_prep_cif_var(&call_cif, FFI_DEFAULT_ABI, func->arg_count, 400 + actual_arg_count, func->ret_type, all_arg_types); 401 + 402 + if (status != FFI_OK) { 403 + return js_mkerr(js, "Failed to prepare variadic call CIF (status=%d)", status); 404 + } 405 + 406 + ffi_call(&call_cif, func->func_ptr, &result, arg_values); 407 + } else { 408 + ffi_call(&func->cif, func->func_ptr, &result, arg_values); 409 + } 410 + 411 + return ffi_to_js_value(js, &result, func->ret_type, func->ret_type_str); 412 + } 413 + 414 + static jsval_t ffi_alloc_memory(struct js *js, jsval_t *args, int nargs) { 415 + if (nargs < 1 || js_type(args[0]) != JS_NUM) { 416 + return js_mkerr(js, "alloc() requires size"); 417 + } 418 + 419 + size_t size = (size_t)js_getnum(args[0]); 420 + if (size == 0) { 421 + return js_mkerr(js, "alloc() requires non-zero size"); 422 + } 423 + 424 + void *ptr = malloc(size); 425 + if (!ptr) { 426 + return js_mkerr(js, "alloc() failed to allocate memory"); 427 + } 428 + 429 + ffi_ptr_t *ffi_ptr = (ffi_ptr_t *)malloc(sizeof(ffi_ptr_t)); 430 + if (!ffi_ptr) { 431 + free(ptr); 432 + return js_mkerr(js, "Out of memory"); 433 + } 434 + 435 + ffi_ptr->ptr = ptr; 436 + ffi_ptr->size = size; 437 + ffi_ptr->is_managed = true; 438 + ffi_ptr->ptr_key = (uint64_t)ptr; 439 + 440 + pthread_mutex_lock(&ffi_pointers_mutex); 441 + HASH_ADD(hh, ffi_pointers, ptr_key, sizeof(uint64_t), ffi_ptr); 442 + pthread_mutex_unlock(&ffi_pointers_mutex); 443 + 444 + return js_mknum((double)ffi_ptr->ptr_key); 445 + } 446 + 447 + static jsval_t ffi_free_memory(struct js *js, jsval_t *args, int nargs) { 448 + if (nargs < 1 || js_type(args[0]) != JS_NUM) { 449 + return js_mkerr(js, "free() requires pointer"); 450 + } 451 + 452 + uint64_t ptr_key = (uint64_t)js_getnum(args[0]); 453 + 454 + pthread_mutex_lock(&ffi_pointers_mutex); 455 + ffi_ptr_t *ffi_ptr = NULL; 456 + HASH_FIND(hh, ffi_pointers, &ptr_key, sizeof(uint64_t), ffi_ptr); 457 + 458 + if (!ffi_ptr) { 459 + pthread_mutex_unlock(&ffi_pointers_mutex); 460 + return js_mkerr(js, "Invalid pointer"); 461 + } 462 + 463 + if (ffi_ptr->is_managed) { 464 + free(ffi_ptr->ptr); 465 + } 466 + 467 + HASH_DEL(ffi_pointers, ffi_ptr); 468 + free(ffi_ptr); 469 + pthread_mutex_unlock(&ffi_pointers_mutex); 470 + 471 + return js_mkundef(); 472 + } 473 + 474 + static jsval_t ffi_read_memory(struct js *js, jsval_t *args, int nargs) { 475 + if (nargs < 2 || js_type(args[0]) != JS_NUM || js_type(args[1]) != JS_STR) { 476 + return js_mkerr(js, "read() requires pointer and type"); 477 + } 478 + 479 + uint64_t ptr_key = (uint64_t)js_getnum(args[0]); 480 + 481 + pthread_mutex_lock(&ffi_pointers_mutex); 482 + ffi_ptr_t *ffi_ptr = NULL; 483 + HASH_FIND(hh, ffi_pointers, &ptr_key, sizeof(uint64_t), ffi_ptr); 484 + 485 + if (!ffi_ptr) { 486 + pthread_mutex_unlock(&ffi_pointers_mutex); 487 + return js_mkerr(js, "Invalid pointer"); 488 + } 489 + 490 + void *ptr = ffi_ptr->ptr; 491 + pthread_mutex_unlock(&ffi_pointers_mutex); 492 + 493 + const char *type_str = js_getstr(js, args[1], NULL); 494 + ffi_type *type = get_ffi_type(type_str); 495 + if (!type) { 496 + return js_mkerr(js, "Unknown type: %s", type_str); 497 + } 498 + 499 + return ffi_to_js_value(js, ptr, type, type_str); 500 + } 501 + 502 + static jsval_t ffi_write_memory(struct js *js, jsval_t *args, int nargs) { 503 + if (nargs < 3 || js_type(args[0]) != JS_NUM || js_type(args[1]) != JS_STR) { 504 + return js_mkerr(js, "write() requires pointer, type, and value"); 505 + } 506 + 507 + uint64_t ptr_key = (uint64_t)js_getnum(args[0]); 508 + 509 + pthread_mutex_lock(&ffi_pointers_mutex); 510 + ffi_ptr_t *ffi_ptr = NULL; 511 + HASH_FIND(hh, ffi_pointers, &ptr_key, sizeof(uint64_t), ffi_ptr); 512 + 513 + if (!ffi_ptr) { 514 + pthread_mutex_unlock(&ffi_pointers_mutex); 515 + return js_mkerr(js, "Invalid pointer"); 516 + } 517 + 518 + void *ptr = ffi_ptr->ptr; 519 + pthread_mutex_unlock(&ffi_pointers_mutex); 520 + 521 + const char *type_str = js_getstr(js, args[1], NULL); 522 + ffi_type *type = get_ffi_type(type_str); 523 + if (!type) { 524 + return js_mkerr(js, "Unknown type: %s", type_str); 525 + } 526 + 527 + js_to_ffi_value(js, args[2], type, ptr); 528 + 529 + return js_mkundef(); 530 + } 531 + 532 + static jsval_t ffi_get_pointer(struct js *js, jsval_t *args, int nargs) { 533 + if (nargs < 1 || js_type(args[0]) != JS_NUM) return js_mkerr(js, "pointer() requires pointer"); 534 + uint64_t ptr_key = (uint64_t)js_getnum(args[0]); 535 + 536 + pthread_mutex_lock(&ffi_pointers_mutex); 537 + ffi_ptr_t *ffi_ptr = NULL; 538 + HASH_FIND(hh, ffi_pointers, &ptr_key, sizeof(uint64_t), ffi_ptr); 539 + bool exists = ffi_ptr != NULL; 540 + pthread_mutex_unlock(&ffi_pointers_mutex); 541 + 542 + return exists ? js_mktrue() : js_mkfalse(); 543 + } 544 + 545 + static ffi_type *get_ffi_type(const char *type_str) { 546 + if (strcmp(type_str, "void") == 0) 547 + return &ffi_type_void; 548 + if (strcmp(type_str, "int8") == 0) 549 + return &ffi_type_sint8; 550 + if (strcmp(type_str, "int16") == 0) 551 + return &ffi_type_sint16; 552 + if (strcmp(type_str, "int") == 0) 553 + return &ffi_type_sint32; 554 + if (strcmp(type_str, "int64") == 0) 555 + return &ffi_type_sint64; 556 + if (strcmp(type_str, "uint8") == 0) 557 + return &ffi_type_uint8; 558 + if (strcmp(type_str, "uint16") == 0) 559 + return &ffi_type_uint16; 560 + 561 + if (strcmp(type_str, "uint64") == 0) 562 + return &ffi_type_uint64; 563 + if (strcmp(type_str, "float") == 0) 564 + return &ffi_type_float; 565 + if (strcmp(type_str, "double") == 0) 566 + return &ffi_type_double; 567 + if (strcmp(type_str, "pointer") == 0) 568 + return &ffi_type_pointer; 569 + if (strcmp(type_str, "string") == 0) 570 + return &ffi_type_pointer; 571 + 572 + return NULL; 573 + } 574 + 575 + static void *js_to_ffi_value(struct js *js, jsval_t val, ffi_type *type, void *buffer) { 576 + if (type == &ffi_type_sint8) { 577 + int8_t v = (int8_t)js_getnum(val); 578 + memcpy(buffer, &v, sizeof(v)); 579 + } else if (type == &ffi_type_sint16) { 580 + int16_t v = (int16_t)js_getnum(val); 581 + memcpy(buffer, &v, sizeof(v)); 582 + } else if (type == &ffi_type_sint32) { 583 + int32_t v = (int32_t)js_getnum(val); 584 + memcpy(buffer, &v, sizeof(v)); 585 + } else if (type == &ffi_type_sint64) { 586 + int64_t v = (int64_t)js_getnum(val); 587 + memcpy(buffer, &v, sizeof(v)); 588 + } else if (type == &ffi_type_uint8) { 589 + uint8_t v = (uint8_t)js_getnum(val); 590 + memcpy(buffer, &v, sizeof(v)); 591 + } else if (type == &ffi_type_uint16) { 592 + uint16_t v = (uint16_t)js_getnum(val); 593 + memcpy(buffer, &v, sizeof(v)); 594 + } else if (type == &ffi_type_uint64) { 595 + uint64_t v = (uint64_t)js_getnum(val); 596 + memcpy(buffer, &v, sizeof(v)); 597 + } else if (type == &ffi_type_float) { 598 + float v = (float)js_getnum(val); 599 + memcpy(buffer, &v, sizeof(v)); 600 + } else if (type == &ffi_type_double) { 601 + double v = js_getnum(val); 602 + memcpy(buffer, &v, sizeof(v)); 603 + } else if (type == &ffi_type_pointer) { 604 + if (js_type(val) == JS_STR) { 605 + size_t str_len; 606 + const char *str = js_getstr(js, val, &str_len); 607 + void *ptr = (void *)str; 608 + memcpy(buffer, &ptr, sizeof(ptr)); 609 + } else { 610 + void *ptr = (void *)(uint64_t)js_getnum(val); 611 + memcpy(buffer, &ptr, sizeof(ptr)); 612 + } 613 + } 614 + 615 + return buffer; 616 + } 617 + 618 + static jsval_t ffi_to_js_value(struct js *js, void *val, ffi_type *type, const char *type_str) { 619 + if (type == &ffi_type_void) { 620 + return js_mkundef(); 621 + } else if (type == &ffi_type_sint8) { 622 + return js_mknum((double)(*(int8_t *)val)); 623 + } else if (type == &ffi_type_sint16) { 624 + return js_mknum((double)(*(int16_t *)val)); 625 + } else if (type == &ffi_type_sint32) { 626 + return js_mknum((double)(*(int32_t *)val)); 627 + } else if (type == &ffi_type_sint64) { 628 + return js_mknum((double)(*(int64_t *)val)); 629 + } else if (type == &ffi_type_uint8) { 630 + return js_mknum((double)(*(uint8_t *)val)); 631 + } else if (type == &ffi_type_uint16) { 632 + return js_mknum((double)(*(uint16_t *)val)); 633 + 634 + } else if (type == &ffi_type_uint64) { 635 + return js_mknum((double)(*(uint64_t *)val)); 636 + } else if (type == &ffi_type_float) { 637 + return js_mknum((double)(*(float *)val)); 638 + } else if (type == &ffi_type_double) { 639 + return js_mknum((double)(*(double *)val)); 640 + } else if (type == &ffi_type_pointer) { 641 + void *ptr = *(void **)val; 642 + if (type_str && strcmp(type_str, "string") == 0 && ptr) { 643 + const char *str = (const char *)ptr; 644 + if (str && strlen(str) < 1024) return js_mkstr(js, str, strlen(str)); 645 + } 646 + return js_mknum((double)(uint64_t)ptr); 647 + } 648 + 649 + return js_mkundef(); 650 + }
+30
src/modules/process.c
··· 1 1 #include <stdlib.h> 2 2 #include <stdio.h> 3 3 #include <string.h> 4 + #include <unistd.h> 4 5 5 6 #include "ant.h" 6 7 #include "runtime.h" ··· 95 96 js_set(js, js_glob(js), "process", process_obj); 96 97 js_set(js, process_obj, "env", env_obj); 97 98 js_set(js, process_obj, "exit", js_mkfun(process_exit)); 99 + 100 + // process.pid 101 + js_set(js, process_obj, "pid", js_mknum((double)getpid())); 102 + 103 + // process.platform 104 + #if defined(__APPLE__) 105 + js_set(js, process_obj, "platform", js_mkstr(js, "darwin", 6)); 106 + #elif defined(__linux__) 107 + js_set(js, process_obj, "platform", js_mkstr(js, "linux", 5)); 108 + #elif defined(_WIN32) || defined(_WIN64) 109 + js_set(js, process_obj, "platform", js_mkstr(js, "win32", 5)); 110 + #elif defined(__FreeBSD__) 111 + js_set(js, process_obj, "platform", js_mkstr(js, "freebsd", 7)); 112 + #else 113 + js_set(js, process_obj, "platform", js_mkstr(js, "unknown", 7)); 114 + #endif 115 + 116 + // process.arch 117 + #if defined(__x86_64__) || defined(_M_X64) 118 + js_set(js, process_obj, "arch", js_mkstr(js, "x64", 3)); 119 + #elif defined(__i386__) || defined(_M_IX86) 120 + js_set(js, process_obj, "arch", js_mkstr(js, "ia32", 4)); 121 + #elif defined(__aarch64__) || defined(_M_ARM64) 122 + js_set(js, process_obj, "arch", js_mkstr(js, "arm64", 5)); 123 + #elif defined(__arm__) || defined(_M_ARM) 124 + js_set(js, process_obj, "arch", js_mkstr(js, "arm", 3)); 125 + #else 126 + js_set(js, process_obj, "arch", js_mkstr(js, "unknown", 7)); 127 + #endif 98 128 99 129 load_dotenv_file(js, env_obj); 100 130 js_set_getter(js, env_obj, env_getter);
+13
subprojects/libffi.wrap
··· 1 + [wrap-file] 2 + directory = libffi-3.5.2 3 + source_url = https://github.com/libffi/libffi/releases/download/v3.5.2/libffi-3.5.2.tar.gz 4 + source_filename = libffi-3.5.2.tar.gz 5 + source_hash = f3a3082a23b37c293a4fcd1053147b371f2ff91fa7ea1b2a52e335676bac82dc 6 + source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libffi_3.5.2-2/libffi-3.5.2.tar.gz 7 + patch_filename = libffi_3.5.2-2_patch.zip 8 + patch_url = https://wrapdb.mesonbuild.com/v2/libffi_3.5.2-2/get_patch 9 + patch_hash = 74ed624f74cd860be3bdf6d473b70ab88707bdf2f940191fbcb577e2a49a9710 10 + wrapdb_version = 3.5.2-2 11 + 12 + [provide] 13 + dependency_names = libffi