diff --git a/Makefile b/Makefile index dd8e0f25..ad562ee7 100644 --- a/Makefile +++ b/Makefile @@ -227,6 +227,9 @@ valtest: $(JANET_TARGET) $(TEST_PROGRAMS) callgrind: $(JANET_TARGET) for f in test/suite*.janet; do valgrind --tool=callgrind ./$(JANET_TARGET) "$$f" || exit; done +ffitest: $(JANET_TARGET) + $(JANET_TARGET) ffitest/test.janet + ######################## ##### Distribution ##### ######################## @@ -367,5 +370,5 @@ help: @echo ' make grammar Generate a TextMate language grammar' @echo -.PHONY: clean install repl debug valgrind test \ +.PHONY: clean install repl debug valgrind test ffitest \ valtest dist uninstall docs grammar format help compile-commands diff --git a/ffitest/so.c b/ffitest/so.c new file mode 100644 index 00000000..a38c03d1 --- /dev/null +++ b/ffitest/so.c @@ -0,0 +1,37 @@ +#include +#include +#include + +int int_fn(int a, int b) { + return (a << 2) + b; +} + +double my_fn(int64_t a, int64_t b, const char *x) { + return (double)(a + b) + 0.5 + strlen(x); +} + +double double_fn(double x, double y, double z) { + return (x + y) * z * 3; +} + +double double_many(double x, double y, double z, double w, double a, double b) { + return x + y + z + w + a + b; +} + +double double_lots( + double a, + double b, + double c, + double d, + double e, + double f, + double g, + double h, + double i, + double j) { + return i + j; +} + +double float_fn(float x, float y, float z) { + return (x + y) * z; +} diff --git a/ffitest/test.janet b/ffitest/test.janet new file mode 100644 index 00000000..427a9b71 --- /dev/null +++ b/ffitest/test.janet @@ -0,0 +1,49 @@ +(def native-loc "ffitest/so.so") +(def native-source-loc "ffitest/so.c") + +(os/execute ["cc" native-source-loc "-shared" "-o" native-loc] :px) +(def module (raw-native native-loc)) + +(def int-fn-sig (native-signature :default :int :int :int)) +(def int-fn-pointer (native-lookup module "int_fn")) +(defn int-fn + [x y] + (native-call int-fn-pointer int-fn-sig x y)) + +(def double-fn-sig (native-signature :default :double :double :double :double)) +(def double-fn-pointer (native-lookup module "double_fn")) +(defn double-fn + [x y z] + (native-call double-fn-pointer double-fn-sig x y z)) + +(def double-many-sig (native-signature :default :double :double :double :double :double :double :double)) +(def double-many-pointer (native-lookup module "double_many")) +(defn double-many + [x y z w a b] + (native-call double-many-pointer double-many-sig x y z w a b)) + +(def double-lots-sig (native-signature :default :double + :double :double :double :double :double + :double :double :double :double :double)) +(def double-lots-pointer (native-lookup module "double_lots")) +(defn double-lots + [a b c d e f g h i j] + (native-call double-lots-pointer double-lots-sig a b c d e f g h i j)) + +(def float-fn-sig (native-signature :default :double :float :float :float)) +(def float-fn-pointer (native-lookup module "float_fn")) +(defn float-fn + [x y z] + (native-call float-fn-pointer float-fn-sig x y z)) + +# +# Call functions +# + +(assert (= 60 (int-fn 10 20))) +(assert (= 42 (double-fn 1.5 2.5 3.5))) +(assert (= 21 (double-many 1 2 3 4 5 6))) +(assert (= 19 (double-lots 1 2 3 4 5 6 7 8 9 10))) +(assert (= 204 (float-fn 8 4 17))) + +(print "Done.") diff --git a/src/core/ffi.c b/src/core/ffi.c index e0dfd13f..37a8c789 100644 --- a/src/core/ffi.c +++ b/src/core/ffi.c @@ -28,23 +28,6 @@ #ifdef JANET_FFI -static uint64_t test_function(int32_t a, int32_t b, const char *s) { - printf("a = %d\n", a); - printf("b = %d\n", b); - uint64_t ret = a + b; - printf("string: %s\n", s); - printf("hello from test function. Returning %lu.\n", ret); - return ret; -} - -JANET_CORE_FN(cfun_ffi_get_test_pointer, - "(ffi/get-test-pointer)", - "Get a test pointer to call using ffi.") { - janet_fixarity(argc, 0); - (void) argv; - return janet_wrap_pointer(test_function); -} - typedef enum { JANET_FFI_TYPE_VOID, JANET_FFI_TYPE_SHORT, @@ -67,44 +50,68 @@ typedef enum { JANET_FFI_TYPE_UINT64, } JanetFFIPrimType; -static const size_t janet_ffi_type_sizes[] = { - 0, /* JANET_FFI_TYPE_VOID */ - sizeof(short), /* JANET_FFI_TYPE_SHORT */ - sizeof(int), /* JANET_FFI_TYPE_INT */ - sizeof(long), /* JANET_FFI_TYPE_LONG */ - sizeof(unsigned short), /* JANET_FFI_TYPE_USHORT */ - sizeof(unsigned), /* JANET_FFI_TYPE_UINT */ - sizeof(unsigned long), /* JANET_FFI_TYPE_ULONG */ - sizeof(char), /* JANET_FFI_TYPE_BOOL */ - sizeof(void *), /* JANET_FFI_TYPE_PTR */ - sizeof(float), /* JANET_FFI_TYPE_FLOAT */ - sizeof(double), /* JANET_FFI_TYPE_DOUBLE */ - sizeof(int8_t), /* JANET_FFI_TYPE_INT8 */ - sizeof(uint8_t), /* JANET_FFI_TYPE_UINT8 */ - sizeof(int16_t), /* JANET_FFI_TYPE_INT16 */ - sizeof(uint16_t), /* JANET_FFI_TYPE_UINT16 */ - sizeof(int32_t), /* JANET_FFI_TYPE_INT32 */ - sizeof(uint32_t), /* JANET_FFI_TYPE_UINT32 */ - sizeof(int64_t), /* JANET_FFI_TYPE_INT64 */ - sizeof(uint64_t) /* JANET_FFI_TYPE_UINT64 */ +/* Custom alignof since alignof not in c99 standard */ +#define ALIGNOF(type) offsetof(struct { char c; type member; }, member) + +typedef struct { + size_t size; + size_t align; +} JanetFFIPrimInfo; + +static const JanetFFIPrimInfo janet_ffi_type_info[] = { + {0, 0}, /* JANET_FFI_TYPE_VOID */ + {sizeof(short), ALIGNOF(short)},/* JANET_FFI_TYPE_SHORT */ + {sizeof(int), ALIGNOF(int)}, /* JANET_FFI_TYPE_INT */ + {sizeof(long), ALIGNOF(long)}, /* JANET_FFI_TYPE_LONG */ + {sizeof(unsigned short), ALIGNOF(unsigned short)}, /* JANET_FFI_TYPE_USHORT */ + {sizeof(unsigned), ALIGNOF(unsigned)}, /* JANET_FFI_TYPE_UINT */ + {sizeof(unsigned long), ALIGNOF(unsigned long)}, /* JANET_FFI_TYPE_ULONG */ + {sizeof(char), ALIGNOF(char)}, /* JANET_FFI_TYPE_BOOL */ + {sizeof(void *), ALIGNOF(void *)}, /* JANET_FFI_TYPE_PTR */ + {sizeof(float), ALIGNOF(float)}, /* JANET_FFI_TYPE_FLOAT */ + {sizeof(double), ALIGNOF(double)}, /* JANET_FFI_TYPE_DOUBLE */ + {sizeof(int8_t), ALIGNOF(int8_t)}, /* JANET_FFI_TYPE_INT8 */ + {sizeof(uint8_t), ALIGNOF(uint8_t)}, /* JANET_FFI_TYPE_UINT8 */ + {sizeof(int16_t), ALIGNOF(int16_t)}, /* JANET_FFI_TYPE_INT16 */ + {sizeof(uint16_t), ALIGNOF(uint16_t)}, /* JANET_FFI_TYPE_UINT16 */ + {sizeof(int32_t), ALIGNOF(int32_t)}, /* JANET_FFI_TYPE_INT32 */ + {sizeof(uint32_t), ALIGNOF(uint32_t)}, /* JANET_FFI_TYPE_UINT32 */ + {sizeof(int64_t), ALIGNOF(int64_t)}, /* JANET_FFI_TYPE_INT64 */ + {sizeof(uint64_t), ALIGNOF(uint64_t)}, /* JANET_FFI_TYPE_UINT64 */ }; +typedef struct { + uint32_t size; + uint32_t align; + uint32_t field_count; + JanetFFIPrimType fields[]; +} JanetFFIStruct; + +typedef struct { + JanetFFIPrimType prim; + int32_t argn; +} JanetFFIMapping; + typedef enum { JANET_FFI_CC_SYSV_64 } JanetFFICallingConvention; #define JANET_FFI_MAX_REGS 16 +#define JANET_FFI_MAX_FP_REGS 8 #define JANET_FFI_MAX_STACK 32 typedef struct { uint32_t frame_size; uint32_t reg_count; + uint32_t fp_reg_count; uint32_t stack_count; uint32_t arg_count; + uint32_t variant; JanetFFICallingConvention cc; JanetFFIPrimType ret_type; - JanetFFIPrimType regs[JANET_FFI_MAX_REGS]; - JanetFFIPrimType stack[JANET_FFI_MAX_STACK]; + JanetFFIMapping regs[JANET_FFI_MAX_REGS]; + JanetFFIMapping fp_regs[JANET_FFI_MAX_FP_REGS]; + JanetFFIMapping stack[JANET_FFI_MAX_STACK]; } JanetFFISignature; static const JanetAbstractType janet_signature_type = { @@ -113,9 +120,11 @@ static const JanetAbstractType janet_signature_type = { }; static JanetFFICallingConvention decode_ffi_cc(const uint8_t *name) { - /* TODO */ - (void) name; - return JANET_FFI_CC_SYSV_64; + if (!janet_cstrcmp(name, "sysv64")) return JANET_FFI_CC_SYSV_64; + if (!janet_cstrcmp(name, "default")) { + return JANET_FFI_CC_SYSV_64; + } + janet_panicf("unknown calling convention %s", name); } static JanetFFIPrimType decode_ffi_prim(const uint8_t *name) { @@ -138,49 +147,87 @@ static JanetFFIPrimType decode_ffi_prim(const uint8_t *name) { if (!janet_cstrcmp(name, "uint32")) return JANET_FFI_TYPE_UINT32; if (!janet_cstrcmp(name, "int64")) return JANET_FFI_TYPE_INT64; if (!janet_cstrcmp(name, "uint64")) return JANET_FFI_TYPE_UINT64; +#ifdef JANET_64 + if (!janet_cstrcmp(name, "size")) return JANET_FFI_TYPE_UINT64; + if (!janet_cstrcmp(name, "ssize")) return JANET_FFI_TYPE_INT64; +#else + if (!janet_cstrcmp(name, "size")) return JANET_FFI_TYPE_UINT32; + if (!janet_cstrcmp(name, "ssize")) return JANET_FFI_TYPE_INT32; +#endif janet_panicf("unknown machine type %s", name); } +static int is_fp_type(JanetFFIPrimType prim) { + return prim == JANET_FFI_TYPE_DOUBLE || prim == JANET_FFI_TYPE_FLOAT; +} + JANET_CORE_FN(cfun_ffi_signature, - "(ffi/signature calling-convention ret-type & arg-types)", + "(native-signature calling-convention ret-type & arg-types)", "Create a function signature object that can be used to make calls " "with raw function pointers.") { janet_arity(argc, 2, -1); uint32_t frame_size = 0; uint32_t reg_count = 0; + uint32_t fp_reg_count = 0; uint32_t stack_count = 0; + uint32_t variant = 0; JanetFFICallingConvention cc = decode_ffi_cc(janet_getkeyword(argv, 0)); JanetFFIPrimType ret_type = decode_ffi_prim(janet_getkeyword(argv, 1)); uint32_t max_regs = JANET_FFI_MAX_REGS; - JanetFFIPrimType regs[JANET_FFI_MAX_REGS]; - JanetFFIPrimType stack[JANET_FFI_MAX_STACK]; - for (int i = 0; i < JANET_FFI_MAX_REGS; i++) regs[i] = JANET_FFI_TYPE_VOID; - for (int i = 0; i < JANET_FFI_MAX_STACK; i++) stack[i] = JANET_FFI_TYPE_VOID; + uint32_t max_fp_regs = JANET_FFI_MAX_FP_REGS; + JanetFFIMapping regs[JANET_FFI_MAX_REGS]; + JanetFFIMapping stack[JANET_FFI_MAX_STACK]; + JanetFFIMapping fp_regs[JANET_FFI_MAX_FP_REGS]; + for (int i = 0; i < JANET_FFI_MAX_REGS; i++) { + regs[i].prim = JANET_FFI_TYPE_VOID; + regs[i].argn = 0; + } + for (int i = 0; i < JANET_FFI_MAX_FP_REGS; i++) { + fp_regs[i].prim = JANET_FFI_TYPE_VOID; + fp_regs[i].argn = 0; + } + for (int i = 0; i < JANET_FFI_MAX_STACK; i++) { + stack[i].prim = JANET_FFI_TYPE_VOID; + stack[i].argn = 0; + } switch (cc) { default: break; case JANET_FFI_CC_SYSV_64: max_regs = 6; + max_fp_regs = 8; + if (is_fp_type(ret_type)) variant = 1; break; } for (int32_t i = 2; i < argc; i++) { JanetFFIPrimType ptype = decode_ffi_prim(janet_getkeyword(argv, i)); - if (reg_count < max_regs) { - regs[reg_count++] = ptype; + int is_fp = is_fp_type(ptype); + if (is_fp && fp_reg_count < max_fp_regs) { + fp_regs[fp_reg_count].argn = i; + fp_regs[fp_reg_count++].prim = ptype; + } else if (!is_fp && reg_count < max_regs) { + regs[reg_count].argn = i; + regs[reg_count++].prim = ptype; } else { - stack[stack_count++] = ptype; - frame_size += janet_ffi_type_sizes[ptype]; + stack[stack_count].argn = i; + stack[stack_count++].prim = ptype; + frame_size += janet_ffi_type_info[ptype].size; } } + + /* Create signature abstract value */ JanetFFISignature *abst = janet_abstract(&janet_signature_type, sizeof(JanetFFISignature)); abst->frame_size = frame_size; abst->reg_count = reg_count; + abst->fp_reg_count = fp_reg_count; abst->stack_count = stack_count; abst->cc = cc; abst->ret_type = ret_type; - abst->arg_count = stack_count + reg_count; - memcpy(abst->regs, regs, sizeof(JanetFFIPrimType) * JANET_FFI_MAX_REGS); - memcpy(abst->stack, stack, sizeof(JanetFFIPrimType) * JANET_FFI_MAX_STACK); + abst->arg_count = stack_count + reg_count + fp_reg_count; + abst->variant = variant; + memcpy(abst->regs, regs, sizeof(JanetFFIMapping) * JANET_FFI_MAX_REGS); + memcpy(abst->fp_regs, fp_regs, sizeof(JanetFFIMapping) * JANET_FFI_MAX_FP_REGS); + memcpy(abst->stack, stack, sizeof(JanetFFIMapping) * JANET_FFI_MAX_STACK); return janet_wrap_abstract(abst); } @@ -198,81 +245,67 @@ static void *janet_ffi_getpointer(const Janet *argv, int32_t n) { } } -JANET_CORE_FN(cfun_ffi_call, - "(ffi/call pointer signature & args)", - "Call a raw pointer as a function pointer. The function signature specifies " - "how Janet values in `args` are converted to native machine types.") { - janet_arity(argc, 2, -1); - void *function_pointer = janet_getpointer(argv, 0); - JanetFFISignature *signature = janet_getabstract(argv, 1, &janet_signature_type); - janet_fixarity(argc - 2, signature->arg_count); - - uint64_t regs[6]; - for (uint32_t i = 0; i < signature->reg_count; i++) { - switch (signature->regs[i]) { - case JANET_FFI_TYPE_FLOAT: - case JANET_FFI_TYPE_DOUBLE: - janet_panic("nyi"); - break; - case JANET_FFI_TYPE_VOID: - regs[i] = 0; - continue; - case JANET_FFI_TYPE_PTR: - regs[i] = (uint64_t) janet_ffi_getpointer(argv, i + 2); - break; - case JANET_FFI_TYPE_BOOL: - regs[i] = (uint64_t) janet_getboolean(argv, i + 2); - break; - case JANET_FFI_TYPE_SHORT: - case JANET_FFI_TYPE_INT: - case JANET_FFI_TYPE_INT8: - case JANET_FFI_TYPE_INT16: - case JANET_FFI_TYPE_INT32: - case JANET_FFI_TYPE_INT64: - case JANET_FFI_TYPE_LONG: - regs[i] = (uint64_t) janet_getinteger64(argv, i + 2); - break; - case JANET_FFI_TYPE_USHORT: - case JANET_FFI_TYPE_UINT: - case JANET_FFI_TYPE_UINT8: - case JANET_FFI_TYPE_UINT16: - case JANET_FFI_TYPE_UINT32: - case JANET_FFI_TYPE_UINT64: - case JANET_FFI_TYPE_ULONG: - regs[i] = janet_getuinteger64(argv, i + 2); - break; - } - } - - /* Danger zone */ - uint64_t ret, rethi; - __asm__("mov %3, %%rdi\n\t" - "mov %4, %%rsi\n\t" - "mov %5, %%rdx\n\t" - "mov %6, %%rcx\n\t" - "mov %7, %%r8\n\t" - "mov %8, %%r9\n\t" - "call *%2\n\t" - "mov %%rax, %0\n\t" - "mov %%rdx, %1" - : "=g" (ret), "=g" (rethi) - : "g"(function_pointer), - "g"(regs[0]), - "g"(regs[1]), - "g"(regs[2]), - "g"(regs[3]), - "g"(regs[4]), - "g"(regs[5]) - : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11"); - - (void) rethi; /* at some point we will support more complex return types */ - switch (signature->ret_type) { - case JANET_FFI_TYPE_FLOAT: - case JANET_FFI_TYPE_DOUBLE: +static uint64_t janet_ffi_reg64(const Janet *argv, JanetFFIMapping mapping) { + JanetFFIPrimType ptype = mapping.prim; + int32_t n = mapping.argn; + union { + float f; + double d; + uint64_t reg; + } u; + switch (ptype) { + default: janet_panic("nyi"); - break; + return 0; + case JANET_FFI_TYPE_DOUBLE: + u.d = janet_getnumber(argv, n); + return u.reg; + case JANET_FFI_TYPE_FLOAT: + u.f = janet_getnumber(argv, n); + return u.reg; case JANET_FFI_TYPE_VOID: - break; + return 0; + case JANET_FFI_TYPE_PTR: + return (uint64_t) janet_ffi_getpointer(argv, n); + case JANET_FFI_TYPE_BOOL: + return (uint64_t) janet_getboolean(argv, n); + case JANET_FFI_TYPE_SHORT: + case JANET_FFI_TYPE_INT: + case JANET_FFI_TYPE_INT8: + case JANET_FFI_TYPE_INT16: + case JANET_FFI_TYPE_INT32: + case JANET_FFI_TYPE_INT64: + case JANET_FFI_TYPE_LONG: + return (uint64_t) janet_getinteger64(argv, n); + case JANET_FFI_TYPE_USHORT: + case JANET_FFI_TYPE_UINT: + case JANET_FFI_TYPE_UINT8: + case JANET_FFI_TYPE_UINT16: + case JANET_FFI_TYPE_UINT32: + case JANET_FFI_TYPE_UINT64: + case JANET_FFI_TYPE_ULONG: + return janet_getuinteger64(argv, n); + } +} + +static Janet janet_ffi_from64(uint64_t ret, JanetFFIPrimType ret_type) { + union { + float f; + double d; + uint64_t reg; + } u; + switch (ret_type) { + default: + janet_panic("nyi"); + return janet_wrap_nil(); + case JANET_FFI_TYPE_FLOAT: + u.reg = ret; + return janet_wrap_number(u.f); + case JANET_FFI_TYPE_DOUBLE: + u.reg = ret; + return janet_wrap_number(u.d); + case JANET_FFI_TYPE_VOID: + return janet_wrap_nil(); case JANET_FFI_TYPE_PTR: return janet_wrap_pointer((void *) ret); case JANET_FFI_TYPE_BOOL: @@ -295,15 +328,109 @@ JANET_CORE_FN(cfun_ffi_call, case JANET_FFI_TYPE_ULONG: return janet_wrap_number(ret); } +} + +static Janet janet_ffi_sysv64(JanetFFISignature *signature, void *function_pointer, const Janet *argv) { + uint64_t ret, rethi; + (void) rethi; /* at some point we will support more complex return types */ + uint64_t regs[6]; + uint64_t fp_regs[8]; + for (uint32_t i = 0; i < signature->reg_count; i++) { + regs[i] = janet_ffi_reg64(argv, signature->regs[i]); + } + for (uint32_t i = 0; i < signature->fp_reg_count; i++) { + fp_regs[i] = janet_ffi_reg64(argv, signature->fp_regs[i]); + } + uint64_t *stack = alloca(sizeof(uint64_t) * signature->stack_count); + for (uint32_t i = 0; i < signature->stack_count; i++) { + stack[signature->stack_count - 1 - i] = janet_ffi_reg64(argv, signature->stack[i]); + } + + /* !!ACHTUNG!! */ + +#define FFI_ASM_PRELUDE \ + "mov %3, %%rdi\n\t" \ + "mov %4, %%rsi\n\t" \ + "mov %5, %%rdx\n\t" \ + "mov %6, %%rcx\n\t" \ + "mov %7, %%r8\n\t" \ + "mov %8, %%r9\n\t" \ + "movq %9, %%xmm0\n\t" \ + "movq %10, %%xmm1\n\t" \ + "movq %11, %%xmm2\n\t" \ + "movq %12, %%xmm3\n\t" \ + "movq %13, %%xmm4\n\t" \ + "movq %14, %%xmm5\n\t" \ + "movq %15, %%xmm6\n\t" \ + "movq %16, %%xmm7\n\t" +#define FFI_ASM_OUTPUTS "=g" (ret), "=g" (rethi) +#define FFI_ASM_INPUTS \ + "g"(function_pointer), \ + "g"(regs[0]), \ + "g"(regs[1]), \ + "g"(regs[2]), \ + "g"(regs[3]), \ + "g"(regs[4]), \ + "g"(regs[5]), \ + "g"(fp_regs[0]), \ + "g"(fp_regs[1]), \ + "g"(fp_regs[2]), \ + "g"(fp_regs[3]), \ + "g"(fp_regs[4]), \ + "g"(fp_regs[5]), \ + "g"(fp_regs[6]), \ + "g"(fp_regs[7]) + + switch (signature->variant) { + default: + /* fallthrough */ + case 0: + __asm__( FFI_ASM_PRELUDE + "call *%2\n\t" + "mov %%rax, %0\n\t" + "mov %%rdx, %1" + : FFI_ASM_OUTPUTS + : FFI_ASM_INPUTS + : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11"); + return janet_ffi_from64(ret, signature->ret_type); + case 1: + __asm__( FFI_ASM_PRELUDE + "call *%2\n\t" + "movq %%xmm0, %0\n\t" + "movq %%xmm1, %1" + : FFI_ASM_OUTPUTS + : FFI_ASM_INPUTS + : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11"); + return janet_ffi_from64(ret, signature->ret_type); + } + +#undef FFI_ASM_PRELUDE +#undef FFI_ASM_OUTPUTS +#undef FFI_ASM_INPUTS return janet_wrap_nil(); } +JANET_CORE_FN(cfun_ffi_call, + "(native-call pointer signature & args)", + "Call a raw pointer as a function pointer. The function signature specifies " + "how Janet values in `args` are converted to native machine types.") { + janet_arity(argc, 2, -1); + void *function_pointer = janet_getpointer(argv, 0); + JanetFFISignature *signature = janet_getabstract(argv, 1, &janet_signature_type); + janet_fixarity(argc - 2, signature->arg_count); + switch (signature->cc) { + default: + janet_panic("unsupported calling convention"); + case JANET_FFI_CC_SYSV_64: + return janet_ffi_sysv64(signature, function_pointer, argv); + } +} + void janet_lib_ffi(JanetTable *env) { JanetRegExt ffi_cfuns[] = { - JANET_CORE_REG("ffi/get-test-pointer", cfun_ffi_get_test_pointer), - JANET_CORE_REG("ffi/signature", cfun_ffi_signature), - JANET_CORE_REG("ffi/call", cfun_ffi_call), + JANET_CORE_REG("native-signature", cfun_ffi_signature), + JANET_CORE_REG("native-call", cfun_ffi_call), JANET_REG_END }; janet_core_cfuns_ext(env, NULL, ffi_cfuns); diff --git a/src/core/util.h b/src/core/util.h index 92feaa2c..69d9f358 100644 --- a/src/core/util.h +++ b/src/core/util.h @@ -31,6 +31,8 @@ #include #include +#include +#include /* for ffi */ #if !defined(JANET_REDUCED_OS) || !defined(JANET_SINGLE_THREADED) #include