mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 11:09:54 +00:00
Support for array types in ffi.
This commit is contained in:
parent
20511cf608
commit
a6f93efd39
@ -7,7 +7,7 @@
|
|||||||
(ffi/defbind
|
(ffi/defbind
|
||||||
gtk-application-new :ptr
|
gtk-application-new :ptr
|
||||||
"Add docstrings as needed."
|
"Add docstrings as needed."
|
||||||
[a :ptr b :uint])
|
[title :string flags :uint])
|
||||||
|
|
||||||
(ffi/defbind
|
(ffi/defbind
|
||||||
g-signal-connect-data :ulong
|
g-signal-connect-data :ulong
|
||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
(ffi/defbind
|
(ffi/defbind
|
||||||
g-application-run :int
|
g-application-run :int
|
||||||
[a :ptr b :int c :ptr])
|
[app :ptr argc :int argv :ptr])
|
||||||
|
|
||||||
(ffi/defbind
|
(ffi/defbind
|
||||||
gtk-application-window-new :ptr
|
gtk-application-window-new :ptr
|
||||||
@ -39,6 +39,18 @@
|
|||||||
|
|
||||||
(def cb (delay (ffi/trampoline :default)))
|
(def cb (delay (ffi/trampoline :default)))
|
||||||
|
|
||||||
|
(defn ffi/array
|
||||||
|
``Convert a janet array to a buffer that can be passed to FFI functions.
|
||||||
|
For example, to create an array of type `char *` (array of c strings), one
|
||||||
|
could use `(ffi/array ["hello" "world"] :ptr)`. One needs to be careful that
|
||||||
|
array elements are not garbage collected though - the GC can't follow references
|
||||||
|
inside an arbitrary byte buffer.``
|
||||||
|
[arr ctype &opt buf]
|
||||||
|
(default buf @"")
|
||||||
|
(each el arr
|
||||||
|
(ffi/write ctype el buf))
|
||||||
|
buf)
|
||||||
|
|
||||||
(defn on-active
|
(defn on-active
|
||||||
[app]
|
[app]
|
||||||
(def window (gtk-application-window-new app))
|
(def window (gtk-application-window-new app))
|
||||||
@ -53,4 +65,7 @@
|
|||||||
[&]
|
[&]
|
||||||
(def app (gtk-application-new "org.janet-lang.example.HelloApp" 0))
|
(def app (gtk-application-new "org.janet-lang.example.HelloApp" 0))
|
||||||
(g-signal-connect-data app "activate" (cb) on-active nil 1)
|
(g-signal-connect-data app "activate" (cb) on-active nil 1)
|
||||||
(g-application-run app 0 nil))
|
# manually build an array with ffi/write
|
||||||
|
# - we are responsible for preventing gc when the arg array is used
|
||||||
|
(def argv (ffi/array (dyn *args*) :string))
|
||||||
|
(g-application-run app (length (dyn *args*)) argv))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# The core janet library
|
# The core janet library
|
||||||
# Copyright 2021 © Calvin Rose
|
# Copyright 2022 © Calvin Rose
|
||||||
|
|
||||||
###
|
###
|
||||||
###
|
###
|
||||||
@ -3413,26 +3413,26 @@
|
|||||||
(def pc (frame :pc))
|
(def pc (frame :pc))
|
||||||
(def sourcemap (in dasm :sourcemap))
|
(def sourcemap (in dasm :sourcemap))
|
||||||
(var last-loc [-2 -2])
|
(var last-loc [-2 -2])
|
||||||
(print "\n signal: " (.signal))
|
(eprint "\n signal: " (.signal))
|
||||||
(print " status: " (fiber/status (.fiber)))
|
(eprint " status: " (fiber/status (.fiber)))
|
||||||
(print " function: " (dasm :name) " [" (in dasm :source "") "]")
|
(eprint " function: " (get dasm :name "<anonymous>") " [" (in dasm :source "") "]")
|
||||||
(when-let [constants (dasm :constants)]
|
(when-let [constants (dasm :constants)]
|
||||||
(printf " constants: %.4q" constants))
|
(eprintf " constants: %.4q" constants))
|
||||||
(printf " slots: %.4q\n" (frame :slots))
|
(eprintf " slots: %.4q\n" (frame :slots))
|
||||||
(def padding (string/repeat " " 20))
|
(def padding (string/repeat " " 20))
|
||||||
(loop [i :range [0 (length bytecode)]
|
(loop [i :range [0 (length bytecode)]
|
||||||
:let [instr (bytecode i)]]
|
:let [instr (bytecode i)]]
|
||||||
(prin (if (= (tuple/type instr) :brackets) "*" " "))
|
(eprin (if (= (tuple/type instr) :brackets) "*" " "))
|
||||||
(prin (if (= i pc) "> " " "))
|
(eprin (if (= i pc) "> " " "))
|
||||||
(prinf "%.20s" (string (string/join (map string instr) " ") padding))
|
(eprinf "%.20s" (string (string/join (map string instr) " ") padding))
|
||||||
(when sourcemap
|
(when sourcemap
|
||||||
(let [[sl sc] (sourcemap i)
|
(let [[sl sc] (sourcemap i)
|
||||||
loc [sl sc]]
|
loc [sl sc]]
|
||||||
(when (not= loc last-loc)
|
(when (not= loc last-loc)
|
||||||
(set last-loc loc)
|
(set last-loc loc)
|
||||||
(prin " # line " sl ", column " sc))))
|
(eprin " # line " sl ", column " sc))))
|
||||||
(print))
|
(eprint))
|
||||||
(print))
|
(eprint))
|
||||||
|
|
||||||
(defn .breakall
|
(defn .breakall
|
||||||
"Set breakpoints on all instructions in the current function."
|
"Set breakpoints on all instructions in the current function."
|
||||||
@ -3441,7 +3441,7 @@
|
|||||||
(def bytecode (.bytecode n))
|
(def bytecode (.bytecode n))
|
||||||
(forv i 0 (length bytecode)
|
(forv i 0 (length bytecode)
|
||||||
(debug/fbreak fun i))
|
(debug/fbreak fun i))
|
||||||
(print "Set " (length bytecode) " breakpoints in " fun))
|
(eprint "set " (length bytecode) " breakpoints in " fun))
|
||||||
|
|
||||||
(defn .clearall
|
(defn .clearall
|
||||||
"Clear all breakpoints on the current function."
|
"Clear all breakpoints on the current function."
|
||||||
@ -3450,7 +3450,7 @@
|
|||||||
(def bytecode (.bytecode n))
|
(def bytecode (.bytecode n))
|
||||||
(forv i 0 (length bytecode)
|
(forv i 0 (length bytecode)
|
||||||
(debug/unfbreak fun i))
|
(debug/unfbreak fun i))
|
||||||
(print "Cleared " (length bytecode) " breakpoints in " fun)))
|
(eprint "cleared " (length bytecode) " breakpoints in " fun)))
|
||||||
|
|
||||||
(defn .source
|
(defn .source
|
||||||
"Show the source code for the function being debugged."
|
"Show the source code for the function being debugged."
|
||||||
@ -3458,7 +3458,7 @@
|
|||||||
(def frame (.frame n))
|
(def frame (.frame n))
|
||||||
(def s (frame :source))
|
(def s (frame :source))
|
||||||
(def all-source (slurp s))
|
(def all-source (slurp s))
|
||||||
(print "\n" all-source "\n"))
|
(eprint "\n" all-source "\n"))
|
||||||
|
|
||||||
(defn .break
|
(defn .break
|
||||||
"Set breakpoint at the current pc."
|
"Set breakpoint at the current pc."
|
||||||
@ -3467,7 +3467,7 @@
|
|||||||
(def fun (frame :function))
|
(def fun (frame :function))
|
||||||
(def pc (frame :pc))
|
(def pc (frame :pc))
|
||||||
(debug/fbreak fun pc)
|
(debug/fbreak fun pc)
|
||||||
(print "Set breakpoint in " fun " at pc=" pc))
|
(eprint "set breakpoint in " fun " at pc=" pc))
|
||||||
|
|
||||||
(defn .clear
|
(defn .clear
|
||||||
"Clear the current breakpoint."
|
"Clear the current breakpoint."
|
||||||
@ -3476,7 +3476,7 @@
|
|||||||
(def fun (frame :function))
|
(def fun (frame :function))
|
||||||
(def pc (frame :pc))
|
(def pc (frame :pc))
|
||||||
(debug/unfbreak fun pc)
|
(debug/unfbreak fun pc)
|
||||||
(print "Cleared breakpoint in " fun " at pc=" pc))
|
(eprint "cleared breakpoint in " fun " at pc=" pc))
|
||||||
|
|
||||||
(defn .next
|
(defn .next
|
||||||
"Go to the next breakpoint."
|
"Go to the next breakpoint."
|
||||||
|
@ -56,6 +56,7 @@ typedef enum {
|
|||||||
JANET_FFI_TYPE_VOID,
|
JANET_FFI_TYPE_VOID,
|
||||||
JANET_FFI_TYPE_BOOL,
|
JANET_FFI_TYPE_BOOL,
|
||||||
JANET_FFI_TYPE_PTR,
|
JANET_FFI_TYPE_PTR,
|
||||||
|
JANET_FFI_TYPE_STRING,
|
||||||
JANET_FFI_TYPE_FLOAT,
|
JANET_FFI_TYPE_FLOAT,
|
||||||
JANET_FFI_TYPE_DOUBLE,
|
JANET_FFI_TYPE_DOUBLE,
|
||||||
JANET_FFI_TYPE_INT8,
|
JANET_FFI_TYPE_INT8,
|
||||||
@ -81,6 +82,7 @@ static const JanetFFIPrimInfo janet_ffi_type_info[] = {
|
|||||||
{0, 0}, /* JANET_FFI_TYPE_VOID */
|
{0, 0}, /* JANET_FFI_TYPE_VOID */
|
||||||
{sizeof(char), ALIGNOF(char)}, /* JANET_FFI_TYPE_BOOL */
|
{sizeof(char), ALIGNOF(char)}, /* JANET_FFI_TYPE_BOOL */
|
||||||
{sizeof(void *), ALIGNOF(void *)}, /* JANET_FFI_TYPE_PTR */
|
{sizeof(void *), ALIGNOF(void *)}, /* JANET_FFI_TYPE_PTR */
|
||||||
|
{sizeof(char *), ALIGNOF(char *)}, /* JANET_FFI_TYPE_STRING */
|
||||||
{sizeof(float), ALIGNOF(float)}, /* JANET_FFI_TYPE_FLOAT */
|
{sizeof(float), ALIGNOF(float)}, /* JANET_FFI_TYPE_FLOAT */
|
||||||
{sizeof(double), ALIGNOF(double)}, /* JANET_FFI_TYPE_DOUBLE */
|
{sizeof(double), ALIGNOF(double)}, /* JANET_FFI_TYPE_DOUBLE */
|
||||||
{sizeof(int8_t), ALIGNOF(int8_t)}, /* JANET_FFI_TYPE_INT8 */
|
{sizeof(int8_t), ALIGNOF(int8_t)}, /* JANET_FFI_TYPE_INT8 */
|
||||||
@ -97,6 +99,7 @@ static const JanetFFIPrimInfo janet_ffi_type_info[] = {
|
|||||||
struct JanetFFIType {
|
struct JanetFFIType {
|
||||||
JanetFFIStruct *st;
|
JanetFFIStruct *st;
|
||||||
JanetFFIPrimType prim;
|
JanetFFIPrimType prim;
|
||||||
|
size_t array_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -104,6 +107,7 @@ typedef struct {
|
|||||||
size_t offset;
|
size_t offset;
|
||||||
} JanetFFIStructMember;
|
} JanetFFIStructMember;
|
||||||
|
|
||||||
|
/* Also used to store array types */
|
||||||
struct JanetFFIStruct {
|
struct JanetFFIStruct {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t align;
|
uint32_t align;
|
||||||
@ -219,14 +223,16 @@ static JanetFFIType prim_type(JanetFFIPrimType pt) {
|
|||||||
JanetFFIType t;
|
JanetFFIType t;
|
||||||
t.prim = pt;
|
t.prim = pt;
|
||||||
t.st = NULL;
|
t.st = NULL;
|
||||||
|
t.array_count = 0;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t type_size(JanetFFIType t) {
|
static size_t type_size(JanetFFIType t) {
|
||||||
|
size_t count = t.array_count ? t.array_count : 1;
|
||||||
if (t.prim == JANET_FFI_TYPE_STRUCT) {
|
if (t.prim == JANET_FFI_TYPE_STRUCT) {
|
||||||
return t.st->size;
|
return t.st->size * count;
|
||||||
} else {
|
} else {
|
||||||
return janet_ffi_type_info[t.prim].size;
|
return janet_ffi_type_info[t.prim].size * count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,6 +260,7 @@ static JanetFFIPrimType decode_ffi_prim(const uint8_t *name) {
|
|||||||
if (!janet_cstrcmp(name, "void")) return JANET_FFI_TYPE_VOID;
|
if (!janet_cstrcmp(name, "void")) return JANET_FFI_TYPE_VOID;
|
||||||
if (!janet_cstrcmp(name, "bool")) return JANET_FFI_TYPE_BOOL;
|
if (!janet_cstrcmp(name, "bool")) return JANET_FFI_TYPE_BOOL;
|
||||||
if (!janet_cstrcmp(name, "ptr")) return JANET_FFI_TYPE_PTR;
|
if (!janet_cstrcmp(name, "ptr")) return JANET_FFI_TYPE_PTR;
|
||||||
|
if (!janet_cstrcmp(name, "string")) return JANET_FFI_TYPE_STRING;
|
||||||
if (!janet_cstrcmp(name, "float")) return JANET_FFI_TYPE_FLOAT;
|
if (!janet_cstrcmp(name, "float")) return JANET_FFI_TYPE_FLOAT;
|
||||||
if (!janet_cstrcmp(name, "double")) return JANET_FFI_TYPE_DOUBLE;
|
if (!janet_cstrcmp(name, "double")) return JANET_FFI_TYPE_DOUBLE;
|
||||||
if (!janet_cstrcmp(name, "int8")) return JANET_FFI_TYPE_INT8;
|
if (!janet_cstrcmp(name, "int8")) return JANET_FFI_TYPE_INT8;
|
||||||
@ -355,6 +362,11 @@ static JanetFFIStruct *build_struct_type(int32_t argc, const Janet *argv) {
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
st->is_aligned = is_aligned;
|
st->is_aligned = is_aligned;
|
||||||
|
if (is_aligned) {
|
||||||
|
st->size += st->align - 1;
|
||||||
|
st->size /= st->align;
|
||||||
|
st->size *= st->align;
|
||||||
|
}
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +383,15 @@ static JanetFFIType decode_ffi_type(Janet x) {
|
|||||||
int32_t len;
|
int32_t len;
|
||||||
const Janet *els;
|
const Janet *els;
|
||||||
if (janet_indexed_view(x, &els, &len)) {
|
if (janet_indexed_view(x, &els, &len)) {
|
||||||
ret.st = build_struct_type(len, els);
|
if (janet_checktype(x, JANET_ARRAY)) {
|
||||||
|
if (len != 2) janet_panicf("array type must be of form @[type count], got %v", x);
|
||||||
|
int32_t array_count = janet_getnat(els, 1);
|
||||||
|
if (array_count == 0) janet_panic("vla not supported");
|
||||||
|
ret = decode_ffi_type(els[0]);
|
||||||
|
ret.array_count = array_count;
|
||||||
|
} else {
|
||||||
|
ret.st = build_struct_type(len, els);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
janet_panicf("bad native type %v", x);
|
janet_panicf("bad native type %v", x);
|
||||||
@ -380,11 +400,27 @@ static JanetFFIType decode_ffi_type(Janet x) {
|
|||||||
|
|
||||||
JANET_CORE_FN(cfun_ffi_struct,
|
JANET_CORE_FN(cfun_ffi_struct,
|
||||||
"(ffi/struct & types)",
|
"(ffi/struct & types)",
|
||||||
"Create a struct type descriptor that can be used to pass structs into native functions. ") {
|
"Create a struct type definition that can be used to pass structs into native functions. ") {
|
||||||
janet_arity(argc, 1, -1);
|
janet_arity(argc, 1, -1);
|
||||||
return janet_wrap_abstract(build_struct_type(argc, argv));
|
return janet_wrap_abstract(build_struct_type(argc, argv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_ffi_size,
|
||||||
|
"(ffi/size type)",
|
||||||
|
"Get the size of an ffi type in bytes.") {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
size_t size = type_size(decode_ffi_type(argv[0]));
|
||||||
|
return janet_wrap_number((double) size);
|
||||||
|
}
|
||||||
|
|
||||||
|
JANET_CORE_FN(cfun_ffi_align,
|
||||||
|
"(ffi/align type)",
|
||||||
|
"Get the align of an ffi type in bytes.") {
|
||||||
|
janet_fixarity(argc, 1);
|
||||||
|
size_t size = type_align(decode_ffi_type(argv[0]));
|
||||||
|
return janet_wrap_number((double) size);
|
||||||
|
}
|
||||||
|
|
||||||
static void *janet_ffi_getpointer(const Janet *argv, int32_t n) {
|
static void *janet_ffi_getpointer(const Janet *argv, int32_t n) {
|
||||||
switch (janet_type(argv[n])) {
|
switch (janet_type(argv[n])) {
|
||||||
default:
|
default:
|
||||||
@ -411,6 +447,21 @@ static void *janet_ffi_getpointer(const Janet *argv, int32_t n) {
|
|||||||
* The alignment and space available is assumed to already be sufficient */
|
* The alignment and space available is assumed to already be sufficient */
|
||||||
static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFIType type, int recur) {
|
static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFIType type, int recur) {
|
||||||
if (recur == 0) janet_panic("recursion too deep");
|
if (recur == 0) janet_panic("recursion too deep");
|
||||||
|
if (type.array_count) {
|
||||||
|
JanetFFIType el_type = type;
|
||||||
|
el_type.array_count = 0;
|
||||||
|
size_t el_size = type_size(el_type);
|
||||||
|
JanetView els = janet_getindexed(argv, n);
|
||||||
|
if ((size_t) els.len != type.array_count) {
|
||||||
|
janet_panicf("bad array length, expected %d, got %d", type.array_count, els.len);
|
||||||
|
}
|
||||||
|
char *cursor = to;
|
||||||
|
for (int32_t i = 0; i < els.len; i++) {
|
||||||
|
janet_ffi_write_one(cursor, els.items, i, el_type, recur - 1);
|
||||||
|
cursor += el_size;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (type.prim) {
|
switch (type.prim) {
|
||||||
case JANET_FFI_TYPE_VOID:
|
case JANET_FFI_TYPE_VOID:
|
||||||
if (!janet_checktype(argv[n], JANET_NIL)) {
|
if (!janet_checktype(argv[n], JANET_NIL)) {
|
||||||
@ -439,6 +490,9 @@ static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFI
|
|||||||
case JANET_FFI_TYPE_PTR:
|
case JANET_FFI_TYPE_PTR:
|
||||||
((void **)(to))[0] = janet_ffi_getpointer(argv, n);
|
((void **)(to))[0] = janet_ffi_getpointer(argv, n);
|
||||||
break;
|
break;
|
||||||
|
case JANET_FFI_TYPE_STRING:
|
||||||
|
((const char **)(to))[0] = janet_getcstring(argv, n);
|
||||||
|
break;
|
||||||
case JANET_FFI_TYPE_BOOL:
|
case JANET_FFI_TYPE_BOOL:
|
||||||
((bool *)(to))[0] = janet_getboolean(argv, n);
|
((bool *)(to))[0] = janet_getboolean(argv, n);
|
||||||
break;
|
break;
|
||||||
@ -474,6 +528,17 @@ static void janet_ffi_write_one(void *to, const Janet *argv, int32_t n, JanetFFI
|
|||||||
* size of the data is correct. */
|
* size of the data is correct. */
|
||||||
static Janet janet_ffi_read_one(const uint8_t *from, JanetFFIType type, int recur) {
|
static Janet janet_ffi_read_one(const uint8_t *from, JanetFFIType type, int recur) {
|
||||||
if (recur == 0) janet_panic("recursion too deep");
|
if (recur == 0) janet_panic("recursion too deep");
|
||||||
|
if (type.array_count) {
|
||||||
|
JanetFFIType el_type = type;
|
||||||
|
el_type.array_count = 0;
|
||||||
|
size_t el_size = type_size(el_type);
|
||||||
|
JanetArray *array = janet_array(type.array_count);
|
||||||
|
for (size_t i = 0; i < type.array_count; i++) {
|
||||||
|
janet_array_push(array, janet_ffi_read_one(from, el_type, recur - 1));
|
||||||
|
from += el_size;
|
||||||
|
}
|
||||||
|
return janet_wrap_array(array);
|
||||||
|
}
|
||||||
switch (type.prim) {
|
switch (type.prim) {
|
||||||
default:
|
default:
|
||||||
case JANET_FFI_TYPE_VOID:
|
case JANET_FFI_TYPE_VOID:
|
||||||
@ -495,6 +560,8 @@ static Janet janet_ffi_read_one(const uint8_t *from, JanetFFIType type, int recu
|
|||||||
void *ptr = ((void **)(from))[0];
|
void *ptr = ((void **)(from))[0];
|
||||||
return (NULL == ptr) ? janet_wrap_nil() : janet_wrap_pointer(ptr);
|
return (NULL == ptr) ? janet_wrap_nil() : janet_wrap_pointer(ptr);
|
||||||
}
|
}
|
||||||
|
case JANET_FFI_TYPE_STRING:
|
||||||
|
return janet_cstringv(((char **)(from))[0]);
|
||||||
case JANET_FFI_TYPE_BOOL:
|
case JANET_FFI_TYPE_BOOL:
|
||||||
return janet_wrap_boolean(((bool *)(from))[0]);
|
return janet_wrap_boolean(((bool *)(from))[0]);
|
||||||
case JANET_FFI_TYPE_INT8:
|
case JANET_FFI_TYPE_INT8:
|
||||||
@ -537,6 +604,7 @@ static JanetFFIMapping void_mapping(void) {
|
|||||||
static JanetFFIWordSpec sysv64_classify(JanetFFIType type) {
|
static JanetFFIWordSpec sysv64_classify(JanetFFIType type) {
|
||||||
switch (type.prim) {
|
switch (type.prim) {
|
||||||
case JANET_FFI_TYPE_PTR:
|
case JANET_FFI_TYPE_PTR:
|
||||||
|
case JANET_FFI_TYPE_STRING:
|
||||||
case JANET_FFI_TYPE_BOOL:
|
case JANET_FFI_TYPE_BOOL:
|
||||||
case JANET_FFI_TYPE_INT8:
|
case JANET_FFI_TYPE_INT8:
|
||||||
case JANET_FFI_TYPE_INT16:
|
case JANET_FFI_TYPE_INT16:
|
||||||
@ -1163,6 +1231,8 @@ void janet_lib_ffi(JanetTable *env) {
|
|||||||
JANET_CORE_REG("ffi/struct", cfun_ffi_struct),
|
JANET_CORE_REG("ffi/struct", cfun_ffi_struct),
|
||||||
JANET_CORE_REG("ffi/write", cfun_ffi_buffer_write),
|
JANET_CORE_REG("ffi/write", cfun_ffi_buffer_write),
|
||||||
JANET_CORE_REG("ffi/read", cfun_ffi_buffer_read),
|
JANET_CORE_REG("ffi/read", cfun_ffi_buffer_read),
|
||||||
|
JANET_CORE_REG("ffi/size", cfun_ffi_size),
|
||||||
|
JANET_CORE_REG("ffi/align", cfun_ffi_align),
|
||||||
JANET_CORE_REG("ffi/trampoline", cfun_ffi_get_callback_trampoline),
|
JANET_CORE_REG("ffi/trampoline", cfun_ffi_get_callback_trampoline),
|
||||||
JANET_REG_END
|
JANET_REG_END
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user