Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4498123
ffi.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
31 KB
Referenced Files
None
Subscribers
None
ffi.c
View Options
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include
<windows.h>
#define dlopen(name, flags) ((void*)LoadLibraryA(name))
#define dlsym(handle, name) ((void*)GetProcAddress((HMODULE)(handle), (name)))
#define dlclose(handle) FreeLibrary((HMODULE)(handle))
#define dlerror() "LoadLibrary failed"
#define RTLD_LAZY 0
#else
#include
<dlfcn.h>
#endif
#include
<ffi.h>
#include
<pthread.h>
#include
<stdlib.h>
#include
<string.h>
#include
<utarray.h>
#include
<uthash.h>
#include
"errors.h"
#include
"gc/modules.h"
#include
"internal.h"
#include
"silver/engine.h"
#include
"modules/ffi.h"
#include
"modules/symbol.h"
typedef
struct
ffi_lib
{
char
name
[
256
];
void
*
handle
;
ant_value_t
js_obj
;
UT_hash_handle
hh
;
}
ffi_lib_t
;
typedef
struct
ffi_func
{
char
name
[
256
];
void
*
func_ptr
;
ffi_cif
cif
;
ffi_type
**
arg_types
;
ffi_type
*
ret_type
;
char
ret_type_str
[
32
];
int
arg_count
;
bool
is_variadic
;
UT_hash_handle
hh
;
}
ffi_func_t
;
typedef
struct
ffi_ptr
{
void
*
ptr
;
size_t
size
;
bool
is_managed
;
uint64_t
ptr_key
;
UT_hash_handle
hh
;
}
ffi_ptr_t
;
typedef
struct
ffi_callback
{
ffi_closure
*
closure
;
void
*
code_ptr
;
ffi_cif
cif
;
ffi_type
**
arg_types
;
ffi_type
*
ret_type
;
char
ret_type_str
[
32
];
char
**
arg_type_strs
;
int
arg_count
;
ant_t
*
js
;
ant_value_t
js_func
;
uint64_t
cb_key
;
UT_hash_handle
hh
;
}
ffi_callback_t
;
static
ffi_lib_t
*
ffi_libraries
=
NULL
;
static
ffi_ptr_t
*
ffi_pointers
=
NULL
;
static
ffi_callback_t
*
ffi_callbacks
=
NULL
;
static
UT_array
*
ffi_functions_array
=
NULL
;
static
pthread_mutex_t
ffi_libraries_mutex
=
PTHREAD_MUTEX_INITIALIZER
;
static
pthread_mutex_t
ffi_functions_mutex
=
PTHREAD_MUTEX_INITIALIZER
;
static
pthread_mutex_t
ffi_pointers_mutex
=
PTHREAD_MUTEX_INITIALIZER
;
static
pthread_mutex_t
ffi_callbacks_mutex
=
PTHREAD_MUTEX_INITIALIZER
;
static
const
UT_icd
ffi_func_icd
=
{
.
sz
=
sizeof
(
ffi_func_t
*
),
.
init
=
NULL
,
.
copy
=
NULL
,
.
dtor
=
NULL
,
};
static
ant_value_t
ffi_dlopen
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_define
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_lib_call
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_call_function
(
ant_t
*
js
,
ffi_func_t
*
func
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_alloc_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_free_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_read_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_write_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_get_pointer
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_create_callback
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_free_callback
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ant_value_t
ffi_read_ptr
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
);
static
ffi_type
*
get_ffi_type
(
const
char
*
type_str
);
static
void
*
js_to_ffi_value
(
ant_t
*
js
,
ant_value_t
val
,
ffi_type
*
type
,
void
*
buffer
);
static
ant_value_t
ffi_to_js_value
(
ant_t
*
js
,
void
*
val
,
ffi_type
*
type
,
const
char
*
type_str
);
static
void
ffi_callback_handler
(
ffi_cif
*
cif
,
void
*
ret
,
void
**
args
,
void
*
user_data
);
ant_value_t
ffi_library
(
ant_t
*
js
)
{
ant_value_t
ffi_obj
=
js_mkobj
(
js
);
js_set
(
js
,
ffi_obj
,
"dlopen"
,
js_mkfun
(
ffi_dlopen
));
js_set
(
js
,
ffi_obj
,
"alloc"
,
js_mkfun
(
ffi_alloc_memory
));
js_set
(
js
,
ffi_obj
,
"free"
,
js_mkfun
(
ffi_free_memory
));
js_set
(
js
,
ffi_obj
,
"read"
,
js_mkfun
(
ffi_read_memory
));
js_set
(
js
,
ffi_obj
,
"write"
,
js_mkfun
(
ffi_write_memory
));
js_set
(
js
,
ffi_obj
,
"pointer"
,
js_mkfun
(
ffi_get_pointer
));
js_set
(
js
,
ffi_obj
,
"callback"
,
js_mkfun
(
ffi_create_callback
));
js_set
(
js
,
ffi_obj
,
"freeCallback"
,
js_mkfun
(
ffi_free_callback
));
js_set
(
js
,
ffi_obj
,
"readPtr"
,
js_mkfun
(
ffi_read_ptr
));
const
char
*
suffix
;
#ifdef __APPLE__
suffix
=
"dylib"
;
#elif defined(__linux__)
suffix
=
"so"
;
#elif defined(_WIN32)
suffix
=
"dll"
;
#else
suffix
=
"so"
;
#endif
js_set
(
js
,
ffi_obj
,
"suffix"
,
js_mkstr
(
js
,
suffix
,
strlen
(
suffix
)));
ant_value_t
ffi_types
=
js_mkobj
(
js
);
js_set
(
js
,
ffi_types
,
"void"
,
js_mkstr
(
js
,
"void"
,
4
));
js_set
(
js
,
ffi_types
,
"int8"
,
js_mkstr
(
js
,
"int8"
,
4
));
js_set
(
js
,
ffi_types
,
"int16"
,
js_mkstr
(
js
,
"int16"
,
5
));
js_set
(
js
,
ffi_types
,
"int"
,
js_mkstr
(
js
,
"int"
,
3
));
js_set
(
js
,
ffi_types
,
"int64"
,
js_mkstr
(
js
,
"int64"
,
5
));
js_set
(
js
,
ffi_types
,
"uint8"
,
js_mkstr
(
js
,
"uint8"
,
5
));
js_set
(
js
,
ffi_types
,
"uint16"
,
js_mkstr
(
js
,
"uint16"
,
6
));
js_set
(
js
,
ffi_types
,
"uint64"
,
js_mkstr
(
js
,
"uint64"
,
6
));
js_set
(
js
,
ffi_types
,
"float"
,
js_mkstr
(
js
,
"float"
,
5
));
js_set
(
js
,
ffi_types
,
"double"
,
js_mkstr
(
js
,
"double"
,
6
));
js_set
(
js
,
ffi_types
,
"pointer"
,
js_mkstr
(
js
,
"pointer"
,
7
));
js_set
(
js
,
ffi_types
,
"string"
,
js_mkstr
(
js
,
"string"
,
6
));
js_set
(
js
,
ffi_types
,
"spread"
,
js_mkstr
(
js
,
"..."
,
3
));
js_set
(
js
,
ffi_obj
,
"FFIType"
,
ffi_types
);
js_set_sym
(
js
,
ffi_obj
,
get_toStringTag_sym
(),
js_mkstr
(
js
,
"FFI"
,
3
));
return
ffi_obj
;
}
static
void
ffi_init_array
(
void
)
{
static
int
initialized
=
0
;
if
(
initialized
)
return
;
initialized
=
1
;
if
(
!
ffi_functions_array
)
utarray_new
(
ffi_functions_array
,
&
ffi_func_icd
);
}
static
ant_value_t
ffi_dlopen
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_STR
)
{
return
js_mkerr
(
js
,
"dlopen() requires library name string"
);
}
ffi_init_array
();
size_t
lib_name_len
;
const
char
*
lib_name
=
js_getstr
(
js
,
args
[
0
],
&
lib_name_len
);
pthread_mutex_lock
(
&
ffi_libraries_mutex
);
ffi_lib_t
*
lib
=
NULL
;
HASH_FIND_STR
(
ffi_libraries
,
lib_name
,
lib
);
if
(
lib
)
{
ant_value_t
result
=
lib
->
js_obj
;
pthread_mutex_unlock
(
&
ffi_libraries_mutex
);
return
result
;
}
pthread_mutex_unlock
(
&
ffi_libraries_mutex
);
void
*
handle
=
dlopen
(
lib_name
,
RTLD_LAZY
);
if
(
!
handle
)
{
return
js_mkerr
(
js
,
"Failed to load library: %s"
,
dlerror
());
}
lib
=
(
ffi_lib_t
*
)
malloc
(
sizeof
(
ffi_lib_t
));
if
(
!
lib
)
{
dlclose
(
handle
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
strncpy
(
lib
->
name
,
lib_name
,
sizeof
(
lib
->
name
)
-
1
);
lib
->
name
[
sizeof
(
lib
->
name
)
-
1
]
=
'\0'
;
lib
->
handle
=
handle
;
lib
->
js_obj
=
js_mkobj
(
js
);
js_set
(
js
,
lib
->
js_obj
,
"__lib_ptr"
,
js_mknum
((
double
)(
uint64_t
)
lib
));
js_set
(
js
,
lib
->
js_obj
,
"define"
,
js_mkfun
(
ffi_define
));
js_set
(
js
,
lib
->
js_obj
,
"call"
,
js_mkfun
(
ffi_lib_call
));
pthread_mutex_lock
(
&
ffi_libraries_mutex
);
HASH_ADD_STR
(
ffi_libraries
,
name
,
lib
);
pthread_mutex_unlock
(
&
ffi_libraries_mutex
);
return
lib
->
js_obj
;
}
static
ant_value_t
ffi_define
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
||
vtype
(
args
[
0
])
!=
T_STR
)
{
return
js_mkerr
(
js
,
"define() requires function name string and signature"
);
}
ant_value_t
this_obj
=
js_getthis
(
js
);
ant_value_t
lib_ptr_val
=
js_get
(
js
,
this_obj
,
"__lib_ptr"
);
if
(
vtype
(
lib_ptr_val
)
!=
T_NUM
)
{
return
js_mkerr
(
js
,
"Invalid library object"
);
}
size_t
func_name_len
;
const
char
*
func_name
=
js_getstr
(
js
,
args
[
0
],
&
func_name_len
);
ant_value_t
sig
=
args
[
1
];
int
sig_type
=
vtype
(
sig
);
if
(
sig_type
==
T_STR
||
sig_type
==
T_NUM
||
sig_type
==
T_NULL
||
sig_type
==
T_UNDEF
)
{
return
js_mkerr
(
js
,
"Signature must be an array [returnType, [argTypes...]] or "
"an object {args: [...], returns: type}"
);
}
const
char
*
ret_type_str
;
ant_value_t
arg_types_arr
;
int
arg_count
;
ant_value_t
returns_val
=
js_get
(
js
,
sig
,
"returns"
);
ant_value_t
args_val
=
js_get
(
js
,
sig
,
"args"
);
if
(
vtype
(
returns_val
)
!=
T_UNDEF
&&
vtype
(
args_val
)
!=
T_UNDEF
)
{
if
(
vtype
(
returns_val
)
!=
T_STR
)
{
return
js_mkerr
(
js
,
"Return type must be a string"
);
}
ret_type_str
=
js_getstr
(
js
,
returns_val
,
NULL
);
arg_types_arr
=
args_val
;
if
(
vtype
(
arg_types_arr
)
==
T_STR
||
vtype
(
arg_types_arr
)
==
T_NUM
||
vtype
(
arg_types_arr
)
==
T_NULL
||
vtype
(
arg_types_arr
)
==
T_UNDEF
)
{
return
js_mkerr
(
js
,
"Argument types must be an array"
);
}
ant_value_t
length_val
=
js_get
(
js
,
arg_types_arr
,
"length"
);
arg_count
=
(
int
)
js_getnum
(
length_val
);
}
else
{
ant_value_t
ret_type_val
=
js_get
(
js
,
sig
,
"0"
);
if
(
vtype
(
ret_type_val
)
!=
T_STR
)
{
return
js_mkerr
(
js
,
"Return type must be a string"
);
}
ret_type_str
=
js_getstr
(
js
,
ret_type_val
,
NULL
);
arg_types_arr
=
js_get
(
js
,
sig
,
"1"
);
int
arg_arr_type
=
vtype
(
arg_types_arr
);
if
(
arg_arr_type
==
T_STR
||
arg_arr_type
==
T_NUM
||
arg_arr_type
==
T_NULL
||
arg_arr_type
==
T_UNDEF
)
{
return
js_mkerr
(
js
,
"Argument types must be an array"
);
}
ant_value_t
length_val
=
js_get
(
js
,
arg_types_arr
,
"length"
);
arg_count
=
(
int
)
js_getnum
(
length_val
);
}
ffi_type
*
ret_type
=
get_ffi_type
(
ret_type_str
);
if
(
!
ret_type
)
{
return
js_mkerr
(
js
,
"Unknown return type: %s"
,
ret_type_str
);
}
ffi_lib_t
*
lib
=
(
ffi_lib_t
*
)(
uint64_t
)
js_getnum
(
lib_ptr_val
);
void
*
func_ptr
=
dlsym
(
lib
->
handle
,
func_name
);
if
(
!
func_ptr
)
{
return
js_mkerr
(
js
,
"Function '%s' not found"
,
func_name
);
}
ffi_func_t
*
func
=
(
ffi_func_t
*
)
malloc
(
sizeof
(
ffi_func_t
));
if
(
!
func
)
{
return
js_mkerr
(
js
,
"Out of memory"
);
}
strncpy
(
func
->
name
,
func_name
,
sizeof
(
func
->
name
)
-
1
);
func
->
name
[
sizeof
(
func
->
name
)
-
1
]
=
'\0'
;
func
->
func_ptr
=
func_ptr
;
func
->
ret_type
=
ret_type
;
strncpy
(
func
->
ret_type_str
,
ret_type_str
,
sizeof
(
func
->
ret_type_str
)
-
1
);
func
->
ret_type_str
[
sizeof
(
func
->
ret_type_str
)
-
1
]
=
'\0'
;
func
->
arg_count
=
arg_count
;
func
->
is_variadic
=
false
;
if
(
arg_count
>
0
)
{
func
->
arg_types
=
(
ffi_type
**
)
malloc
(
sizeof
(
ffi_type
*
)
*
arg_count
);
if
(
!
func
->
arg_types
)
{
free
(
func
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
for
(
int
i
=
0
;
i
<
arg_count
;
i
++
)
{
char
idx_str
[
16
];
snprintf
(
idx_str
,
sizeof
(
idx_str
),
"%d"
,
i
);
ant_value_t
arg_type_val
=
js_get
(
js
,
arg_types_arr
,
idx_str
);
if
(
vtype
(
arg_type_val
)
!=
T_STR
)
{
free
(
func
->
arg_types
);
free
(
func
);
return
js_mkerr
(
js
,
"Argument type must be a string"
);
}
const
char
*
arg_type_str
=
js_getstr
(
js
,
arg_type_val
,
NULL
);
if
(
strcmp
(
arg_type_str
,
"..."
)
==
0
)
{
func
->
is_variadic
=
true
;
func
->
arg_count
=
i
;
break
;
}
func
->
arg_types
[
i
]
=
get_ffi_type
(
arg_type_str
);
if
(
!
func
->
arg_types
[
i
])
{
free
(
func
->
arg_types
);
free
(
func
);
return
js_mkerr
(
js
,
"Unknown argument type: %s"
,
arg_type_str
);
}
}
}
else
{
func
->
arg_types
=
NULL
;
}
if
(
!
func
->
is_variadic
)
{
ffi_status
status
=
ffi_prep_cif
(
&
func
->
cif
,
FFI_DEFAULT_ABI
,
func
->
arg_count
,
ret_type
,
func
->
arg_types
);
if
(
status
!=
FFI_OK
)
{
if
(
func
->
arg_types
)
free
(
func
->
arg_types
);
free
(
func
);
return
js_mkerr
(
js
,
"Failed to prepare function call (status=%d, argc=%d)"
,
status
,
func
->
arg_count
);
}
}
pthread_mutex_lock
(
&
ffi_functions_mutex
);
utarray_push_back
(
ffi_functions_array
,
&
func
);
unsigned
int
func_index
=
utarray_len
(
ffi_functions_array
)
-
1
;
pthread_mutex_unlock
(
&
ffi_functions_mutex
);
js_set
(
js
,
this_obj
,
func_name
,
js_mkffi
(
func_index
));
return
js_mkundef
();
}
static
ant_value_t
ffi_lib_call
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
ant_value_t
lib_obj
=
js_getthis
(
js
);
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_STR
)
return
js_mkerr
(
js
,
"call() requires function name string"
);
size_t
func_name_len
;
const
char
*
func_name
=
js_getstr
(
js
,
args
[
0
],
&
func_name_len
);
ant_value_t
ffi_val
=
js_get
(
js
,
lib_obj
,
func_name
);
int
func_index
=
js_getffi
(
ffi_val
);
if
(
func_index
<
0
)
{
return
js_mkerr
(
js
,
"Function '%s' not defined"
,
func_name
);
}
return
ffi_call_by_index
(
js
,
(
unsigned
int
)
func_index
,
args
+
1
,
nargs
-
1
);
}
static
ant_value_t
ffi_call_function
(
ant_t
*
js
,
ffi_func_t
*
func
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
!
func
->
is_variadic
&&
nargs
!=
func
->
arg_count
)
{
return
js_mkerr
(
js
,
"Function '%s' expects %d arguments, got %d"
,
func
->
name
,
func
->
arg_count
,
nargs
);
}
if
(
func
->
is_variadic
&&
nargs
<
func
->
arg_count
)
{
return
js_mkerr
(
js
,
"Function '%s' expects at least %d arguments, got %d"
,
func
->
name
,
func
->
arg_count
,
nargs
);
}
#define MAX_ARGS 32
void
*
arg_values_buf
[
MAX_ARGS
];
ffi_arg
arg_buffers_buf
[
MAX_ARGS
];
int
actual_arg_count
=
func
->
is_variadic
?
nargs
:
func
->
arg_count
;
if
(
actual_arg_count
>
MAX_ARGS
)
{
return
js_mkerr
(
js
,
"Too many arguments"
);
}
void
**
arg_values
=
arg_values_buf
;
memset
(
arg_values
,
0
,
sizeof
(
arg_values_buf
));
for
(
int
i
=
0
;
i
<
actual_arg_count
;
i
++
)
{
arg_values
[
i
]
=
&
arg_buffers_buf
[
i
];
memset
(
arg_values
[
i
],
0
,
sizeof
(
ffi_arg
));
ffi_type
*
arg_type
;
if
(
i
<
func
->
arg_count
)
{
arg_type
=
func
->
arg_types
[
i
];
}
else
arg_type
=
&
ffi_type_sint32
;
js_to_ffi_value
(
js
,
args
[
i
],
arg_type
,
arg_values
[
i
]);
}
ffi_arg
result
;
memset
(
&
result
,
0
,
sizeof
(
result
));
if
(
func
->
is_variadic
)
{
#define MAX_VARIADIC_ARGS 32
ffi_type
*
all_arg_types
[
MAX_VARIADIC_ARGS
];
if
(
actual_arg_count
>
MAX_VARIADIC_ARGS
)
{
return
js_mkerr
(
js
,
"Too many variadic arguments"
);
}
for
(
int
i
=
0
;
i
<
func
->
arg_count
;
i
++
)
all_arg_types
[
i
]
=
func
->
arg_types
[
i
];
for
(
int
i
=
func
->
arg_count
;
i
<
actual_arg_count
;
i
++
)
all_arg_types
[
i
]
=
&
ffi_type_sint32
;
ffi_cif
call_cif
;
ffi_status
status
=
ffi_prep_cif_var
(
&
call_cif
,
FFI_DEFAULT_ABI
,
func
->
arg_count
,
actual_arg_count
,
func
->
ret_type
,
all_arg_types
);
if
(
status
!=
FFI_OK
)
{
return
js_mkerr
(
js
,
"Failed to prepare variadic call CIF (status=%d)"
,
status
);
}
ffi_call
(
&
call_cif
,
func
->
func_ptr
,
&
result
,
arg_values
);
}
else
{
ffi_call
(
&
func
->
cif
,
func
->
func_ptr
,
&
result
,
arg_values
);
}
return
ffi_to_js_value
(
js
,
&
result
,
func
->
ret_type
,
func
->
ret_type_str
);
}
ant_value_t
ffi_call_by_index
(
ant_t
*
js
,
unsigned
int
func_index
,
ant_value_t
*
args
,
int
nargs
)
{
pthread_mutex_lock
(
&
ffi_functions_mutex
);
if
(
func_index
>=
utarray_len
(
ffi_functions_array
))
{
pthread_mutex_unlock
(
&
ffi_functions_mutex
);
return
js_mkerr
(
js
,
"Invalid FFI function index"
);
}
ffi_func_t
*
func
=
*
(
ffi_func_t
**
)
utarray_eltptr
(
ffi_functions_array
,
func_index
);
pthread_mutex_unlock
(
&
ffi_functions_mutex
);
return
ffi_call_function
(
js
,
func
,
args
,
nargs
);
}
static
ant_value_t
ffi_alloc_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_NUM
)
{
return
js_mkerr
(
js
,
"alloc() requires size"
);
}
size_t
size
=
(
size_t
)
js_getnum
(
args
[
0
]);
if
(
size
==
0
)
{
return
js_mkerr
(
js
,
"alloc() requires non-zero size"
);
}
void
*
ptr
=
malloc
(
size
);
if
(
!
ptr
)
{
return
js_mkerr
(
js
,
"alloc() failed to allocate memory"
);
}
ffi_ptr_t
*
ffi_ptr
=
(
ffi_ptr_t
*
)
malloc
(
sizeof
(
ffi_ptr_t
));
if
(
!
ffi_ptr
)
{
free
(
ptr
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
ffi_ptr
->
ptr
=
ptr
;
ffi_ptr
->
size
=
size
;
ffi_ptr
->
is_managed
=
true
;
ffi_ptr
->
ptr_key
=
(
uint64_t
)
ptr
;
pthread_mutex_lock
(
&
ffi_pointers_mutex
);
HASH_ADD
(
hh
,
ffi_pointers
,
ptr_key
,
sizeof
(
uint64_t
),
ffi_ptr
);
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
return
js_mknum
((
double
)
ffi_ptr
->
ptr_key
);
}
static
ant_value_t
ffi_free_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_NUM
)
{
return
js_mkerr
(
js
,
"free() requires pointer"
);
}
uint64_t
ptr_key
=
(
uint64_t
)
js_getnum
(
args
[
0
]);
pthread_mutex_lock
(
&
ffi_pointers_mutex
);
ffi_ptr_t
*
ffi_ptr
=
NULL
;
HASH_FIND
(
hh
,
ffi_pointers
,
&
ptr_key
,
sizeof
(
uint64_t
),
ffi_ptr
);
if
(
!
ffi_ptr
)
{
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
return
js_mkerr
(
js
,
"Invalid pointer"
);
}
if
(
ffi_ptr
->
is_managed
)
{
free
(
ffi_ptr
->
ptr
);
}
HASH_DEL
(
ffi_pointers
,
ffi_ptr
);
free
(
ffi_ptr
);
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
return
js_mkundef
();
}
static
ant_value_t
ffi_read_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
||
vtype
(
args
[
0
])
!=
T_NUM
||
vtype
(
args
[
1
])
!=
T_STR
)
{
return
js_mkerr
(
js
,
"read() requires pointer and type"
);
}
uint64_t
ptr_key
=
(
uint64_t
)
js_getnum
(
args
[
0
]);
pthread_mutex_lock
(
&
ffi_pointers_mutex
);
ffi_ptr_t
*
ffi_ptr
=
NULL
;
HASH_FIND
(
hh
,
ffi_pointers
,
&
ptr_key
,
sizeof
(
uint64_t
),
ffi_ptr
);
if
(
!
ffi_ptr
)
{
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
return
js_mkerr
(
js
,
"Invalid pointer"
);
}
void
*
ptr
=
ffi_ptr
->
ptr
;
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
const
char
*
type_str
=
js_getstr
(
js
,
args
[
1
],
NULL
);
ffi_type
*
type
=
get_ffi_type
(
type_str
);
if
(
!
type
)
{
return
js_mkerr
(
js
,
"Unknown type: %s"
,
type_str
);
}
return
ffi_to_js_value
(
js
,
ptr
,
type
,
type_str
);
}
static
ant_value_t
ffi_write_memory
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
3
||
vtype
(
args
[
0
])
!=
T_NUM
||
vtype
(
args
[
1
])
!=
T_STR
)
{
return
js_mkerr
(
js
,
"write() requires pointer, type, and value"
);
}
uint64_t
ptr_key
=
(
uint64_t
)
js_getnum
(
args
[
0
]);
pthread_mutex_lock
(
&
ffi_pointers_mutex
);
ffi_ptr_t
*
ffi_ptr
=
NULL
;
HASH_FIND
(
hh
,
ffi_pointers
,
&
ptr_key
,
sizeof
(
uint64_t
),
ffi_ptr
);
if
(
!
ffi_ptr
)
{
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
return
js_mkerr
(
js
,
"Invalid pointer"
);
}
void
*
ptr
=
ffi_ptr
->
ptr
;
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
const
char
*
type_str
=
js_getstr
(
js
,
args
[
1
],
NULL
);
ffi_type
*
type
=
get_ffi_type
(
type_str
);
if
(
!
type
)
{
return
js_mkerr
(
js
,
"Unknown type: %s"
,
type_str
);
}
js_to_ffi_value
(
js
,
args
[
2
],
type
,
ptr
);
return
js_mkundef
();
}
static
ant_value_t
ffi_get_pointer
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_NUM
)
return
js_mkerr
(
js
,
"pointer() requires pointer"
);
uint64_t
ptr_key
=
(
uint64_t
)
js_getnum
(
args
[
0
]);
pthread_mutex_lock
(
&
ffi_pointers_mutex
);
ffi_ptr_t
*
ffi_ptr
=
NULL
;
HASH_FIND
(
hh
,
ffi_pointers
,
&
ptr_key
,
sizeof
(
uint64_t
),
ffi_ptr
);
bool
exists
=
ffi_ptr
!=
NULL
;
pthread_mutex_unlock
(
&
ffi_pointers_mutex
);
return
js_bool
(
exists
);
}
static
ant_value_t
ffi_read_ptr
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
||
vtype
(
args
[
0
])
!=
T_NUM
||
vtype
(
args
[
1
])
!=
T_STR
)
{
return
js_mkerr
(
js
,
"readPtr() requires pointer and type"
);
}
void
*
ptr
=
(
void
*
)(
uint64_t
)
js_getnum
(
args
[
0
]);
if
(
!
ptr
)
return
js_mknull
();
const
char
*
type_str
=
js_getstr
(
js
,
args
[
1
],
NULL
);
if
(
strcmp
(
type_str
,
"string"
)
==
0
)
{
const
char
*
str
=
(
const
char
*
)
ptr
;
return
js_mkstr
(
js
,
str
,
strlen
(
str
));
}
ffi_type
*
type
=
get_ffi_type
(
type_str
);
if
(
!
type
)
return
js_mkerr
(
js
,
"Unknown type: %s"
,
type_str
);
return
ffi_to_js_value
(
js
,
ptr
,
type
,
type_str
);
}
static
void
ffi_callback_handler
(
ffi_cif
*
cif
,
void
*
ret
,
void
**
args
,
void
*
user_data
)
{
(
void
)
cif
;
ffi_callback_t
*
cb
=
(
ffi_callback_t
*
)
user_data
;
ant_t
*
js
=
cb
->
js
;
ant_value_t
js_args
[
32
];
int
arg_count
=
cb
->
arg_count
>
32
?
32
:
cb
->
arg_count
;
for
(
int
i
=
0
;
i
<
arg_count
;
i
++
)
{
js_args
[
i
]
=
ffi_to_js_value
(
js
,
args
[
i
],
cb
->
arg_types
[
i
],
cb
->
arg_type_strs
[
i
]);
}
ant_value_t
result
=
sv_vm_call
(
js
->
vm
,
js
,
cb
->
js_func
,
js_mkundef
(),
js_args
,
arg_count
,
NULL
,
false
);
if
(
cb
->
ret_type
!=
&
ffi_type_void
)
{
if
(
cb
->
ret_type
==
&
ffi_type_sint8
)
{
*
(
int8_t
*
)
ret
=
(
int8_t
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_sint16
)
{
*
(
int16_t
*
)
ret
=
(
int16_t
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_sint32
)
{
*
(
int32_t
*
)
ret
=
(
int32_t
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_sint64
)
{
*
(
int64_t
*
)
ret
=
(
int64_t
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_uint8
)
{
*
(
uint8_t
*
)
ret
=
(
uint8_t
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_uint16
)
{
*
(
uint16_t
*
)
ret
=
(
uint16_t
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_uint64
)
{
*
(
uint64_t
*
)
ret
=
(
uint64_t
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_float
)
{
*
(
float
*
)
ret
=
(
float
)
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_double
)
{
*
(
double
*
)
ret
=
js_getnum
(
result
);
}
else
if
(
cb
->
ret_type
==
&
ffi_type_pointer
)
{
if
(
vtype
(
result
)
==
T_NUM
)
{
*
(
void
**
)
ret
=
(
void
*
)(
uint64_t
)
js_getnum
(
result
);
}
else
{
*
(
void
**
)
ret
=
NULL
;
}
}
}
}
static
ant_value_t
ffi_create_callback
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
2
)
return
js_mkerr
(
js
,
"callback() requires function and signature"
);
ant_value_t
js_func
=
args
[
0
];
ant_value_t
sig
=
args
[
1
];
int
sig_type
=
vtype
(
sig
);
if
(
sig_type
==
T_STR
||
sig_type
==
T_NUM
||
sig_type
==
T_NULL
||
sig_type
==
T_UNDEF
)
{
return
js_mkerr
(
js
,
"Signature must be an object {args: [...], returns: type}"
);
}
const
char
*
ret_type_str
;
ant_value_t
arg_types_arr
;
int
arg_count
;
ant_value_t
returns_val
=
js_get
(
js
,
sig
,
"returns"
);
ant_value_t
args_val
=
js_get
(
js
,
sig
,
"args"
);
if
(
vtype
(
returns_val
)
!=
T_UNDEF
&&
vtype
(
args_val
)
!=
T_UNDEF
)
{
if
(
vtype
(
returns_val
)
!=
T_STR
)
return
js_mkerr
(
js
,
"Return type must be a string"
);
ret_type_str
=
js_getstr
(
js
,
returns_val
,
NULL
);
arg_types_arr
=
args_val
;
ant_value_t
length_val
=
js_get
(
js
,
arg_types_arr
,
"length"
);
arg_count
=
(
int
)
js_getnum
(
length_val
);
}
else
{
ant_value_t
ret_type_val
=
js_get
(
js
,
sig
,
"0"
);
if
(
vtype
(
ret_type_val
)
!=
T_STR
)
return
js_mkerr
(
js
,
"Return type must be a string"
);
ret_type_str
=
js_getstr
(
js
,
ret_type_val
,
NULL
);
arg_types_arr
=
js_get
(
js
,
sig
,
"1"
);
ant_value_t
length_val
=
js_get
(
js
,
arg_types_arr
,
"length"
);
arg_count
=
(
int
)
js_getnum
(
length_val
);
}
ffi_type
*
ret_type
=
get_ffi_type
(
ret_type_str
);
if
(
!
ret_type
)
return
js_mkerr
(
js
,
"Unknown return type: %s"
,
ret_type_str
);
ffi_callback_t
*
cb
=
(
ffi_callback_t
*
)
malloc
(
sizeof
(
ffi_callback_t
));
if
(
!
cb
)
return
js_mkerr
(
js
,
"Out of memory"
);
cb
->
js
=
js
;
cb
->
js_func
=
js_func
;
cb
->
ret_type
=
ret_type
;
strncpy
(
cb
->
ret_type_str
,
ret_type_str
,
sizeof
(
cb
->
ret_type_str
)
-
1
);
cb
->
ret_type_str
[
sizeof
(
cb
->
ret_type_str
)
-
1
]
=
'\0'
;
cb
->
arg_count
=
arg_count
;
if
(
arg_count
>
0
)
{
cb
->
arg_types
=
(
ffi_type
**
)
malloc
(
sizeof
(
ffi_type
*
)
*
arg_count
);
cb
->
arg_type_strs
=
(
char
**
)
malloc
(
sizeof
(
char
*
)
*
arg_count
);
if
(
!
cb
->
arg_types
||
!
cb
->
arg_type_strs
)
{
if
(
cb
->
arg_types
)
free
(
cb
->
arg_types
);
if
(
cb
->
arg_type_strs
)
free
(
cb
->
arg_type_strs
);
free
(
cb
);
return
js_mkerr
(
js
,
"Out of memory"
);
}
for
(
int
i
=
0
;
i
<
arg_count
;
i
++
)
{
char
idx_str
[
16
];
snprintf
(
idx_str
,
sizeof
(
idx_str
),
"%d"
,
i
);
ant_value_t
arg_type_val
=
js_get
(
js
,
arg_types_arr
,
idx_str
);
if
(
vtype
(
arg_type_val
)
!=
T_STR
)
{
for
(
int
j
=
0
;
j
<
i
;
j
++
)
free
(
cb
->
arg_type_strs
[
j
]);
free
(
cb
->
arg_types
);
free
(
cb
->
arg_type_strs
);
free
(
cb
);
return
js_mkerr
(
js
,
"Argument type must be a string"
);
}
const
char
*
arg_type_str
=
js_getstr
(
js
,
arg_type_val
,
NULL
);
cb
->
arg_types
[
i
]
=
get_ffi_type
(
arg_type_str
);
if
(
!
cb
->
arg_types
[
i
])
{
for
(
int
j
=
0
;
j
<
i
;
j
++
)
free
(
cb
->
arg_type_strs
[
j
]);
free
(
cb
->
arg_types
);
free
(
cb
->
arg_type_strs
);
free
(
cb
);
return
js_mkerr
(
js
,
"Unknown argument type: %s"
,
arg_type_str
);
}
cb
->
arg_type_strs
[
i
]
=
strdup
(
arg_type_str
);
}
}
else
{
cb
->
arg_types
=
NULL
;
cb
->
arg_type_strs
=
NULL
;
}
ffi_status
status
=
ffi_prep_cif
(
&
cb
->
cif
,
FFI_DEFAULT_ABI
,
arg_count
,
ret_type
,
cb
->
arg_types
);
if
(
status
!=
FFI_OK
)
{
for
(
int
i
=
0
;
i
<
arg_count
;
i
++
)
free
(
cb
->
arg_type_strs
[
i
]);
if
(
cb
->
arg_types
)
free
(
cb
->
arg_types
);
if
(
cb
->
arg_type_strs
)
free
(
cb
->
arg_type_strs
);
free
(
cb
);
return
js_mkerr
(
js
,
"Failed to prepare callback CIF (status=%d)"
,
status
);
}
cb
->
closure
=
(
ffi_closure
*
)
ffi_closure_alloc
(
sizeof
(
ffi_closure
),
&
cb
->
code_ptr
);
if
(
!
cb
->
closure
)
{
for
(
int
i
=
0
;
i
<
arg_count
;
i
++
)
free
(
cb
->
arg_type_strs
[
i
]);
if
(
cb
->
arg_types
)
free
(
cb
->
arg_types
);
if
(
cb
->
arg_type_strs
)
free
(
cb
->
arg_type_strs
);
free
(
cb
);
return
js_mkerr
(
js
,
"Failed to allocate closure"
);
}
status
=
ffi_prep_closure_loc
(
cb
->
closure
,
&
cb
->
cif
,
ffi_callback_handler
,
cb
,
cb
->
code_ptr
);
if
(
status
!=
FFI_OK
)
{
ffi_closure_free
(
cb
->
closure
);
for
(
int
i
=
0
;
i
<
arg_count
;
i
++
)
free
(
cb
->
arg_type_strs
[
i
]);
if
(
cb
->
arg_types
)
free
(
cb
->
arg_types
);
if
(
cb
->
arg_type_strs
)
free
(
cb
->
arg_type_strs
);
free
(
cb
);
return
js_mkerr
(
js
,
"Failed to prepare closure (status=%d)"
,
status
);
}
cb
->
cb_key
=
(
uint64_t
)
cb
->
code_ptr
;
pthread_mutex_lock
(
&
ffi_callbacks_mutex
);
HASH_ADD
(
hh
,
ffi_callbacks
,
cb_key
,
sizeof
(
uint64_t
),
cb
);
pthread_mutex_unlock
(
&
ffi_callbacks_mutex
);
return
js_mknum
((
double
)
cb
->
cb_key
);
}
static
ant_value_t
ffi_free_callback
(
ant_t
*
js
,
ant_value_t
*
args
,
int
nargs
)
{
if
(
nargs
<
1
||
vtype
(
args
[
0
])
!=
T_NUM
)
{
return
js_mkerr
(
js
,
"freeCallback() requires callback pointer"
);
}
uint64_t
cb_key
=
(
uint64_t
)
js_getnum
(
args
[
0
]);
pthread_mutex_lock
(
&
ffi_callbacks_mutex
);
ffi_callback_t
*
cb
=
NULL
;
HASH_FIND
(
hh
,
ffi_callbacks
,
&
cb_key
,
sizeof
(
uint64_t
),
cb
);
if
(
!
cb
)
{
pthread_mutex_unlock
(
&
ffi_callbacks_mutex
);
return
js_mkerr
(
js
,
"Invalid callback pointer"
);
}
HASH_DEL
(
ffi_callbacks
,
cb
);
pthread_mutex_unlock
(
&
ffi_callbacks_mutex
);
ffi_closure_free
(
cb
->
closure
);
for
(
int
i
=
0
;
i
<
cb
->
arg_count
;
i
++
)
free
(
cb
->
arg_type_strs
[
i
]);
if
(
cb
->
arg_types
)
free
(
cb
->
arg_types
);
if
(
cb
->
arg_type_strs
)
free
(
cb
->
arg_type_strs
);
free
(
cb
);
return
js_mkundef
();
}
typedef
enum
{
JS_FFI_VOID
=
0
,
JS_FFI_INT8
,
JS_FFI_INT16
,
JS_FFI_INT
,
JS_FFI_INT64
,
JS_FFI_UINT8
,
JS_FFI_UINT16
,
JS_FFI_UINT64
,
JS_FFI_FLOAT
,
JS_FFI_DOUBLE
,
JS_FFI_POINTER
,
JS_FFI_STRING
,
JS_FFI_UNKNOWN
,
JS_FFI_COUNT
}
js_ffi_type_id
;
static
js_ffi_type_id
get_ffi_type_id
(
const
char
*
type_str
)
{
if
(
!
type_str
)
return
JS_FFI_UNKNOWN
;
switch
(
type_str
[
0
])
{
case
'v'
:
if
(
strcmp
(
type_str
,
"void"
)
==
0
)
return
JS_FFI_VOID
;
break
;
case
'i'
:
if
(
type_str
[
1
]
==
'n'
&&
type_str
[
2
]
==
't'
)
{
if
(
type_str
[
3
]
==
'\0'
)
return
JS_FFI_INT
;
if
(
strcmp
(
type_str
+
3
,
"8"
)
==
0
)
return
JS_FFI_INT8
;
if
(
strcmp
(
type_str
+
3
,
"16"
)
==
0
)
return
JS_FFI_INT16
;
if
(
strcmp
(
type_str
+
3
,
"64"
)
==
0
)
return
JS_FFI_INT64
;
}
break
;
case
'u'
:
if
(
type_str
[
1
]
==
'i'
&&
type_str
[
2
]
==
'n'
&&
type_str
[
3
]
==
't'
)
{
if
(
strcmp
(
type_str
+
4
,
"8"
)
==
0
)
return
JS_FFI_UINT8
;
if
(
strcmp
(
type_str
+
4
,
"16"
)
==
0
)
return
JS_FFI_UINT16
;
if
(
strcmp
(
type_str
+
4
,
"64"
)
==
0
)
return
JS_FFI_UINT64
;
}
break
;
case
'f'
:
if
(
strcmp
(
type_str
,
"float"
)
==
0
)
return
JS_FFI_FLOAT
;
break
;
case
'd'
:
if
(
strcmp
(
type_str
,
"double"
)
==
0
)
return
JS_FFI_DOUBLE
;
break
;
case
'p'
:
if
(
strcmp
(
type_str
,
"pointer"
)
==
0
)
return
JS_FFI_POINTER
;
break
;
case
's'
:
if
(
strcmp
(
type_str
,
"string"
)
==
0
)
return
JS_FFI_STRING
;
break
;
}
return
JS_FFI_UNKNOWN
;
}
static
ffi_type
*
get_ffi_type
(
const
char
*
type_str
)
{
static
ffi_type
*
type_map
[]
=
{
[
JS_FFI_VOID
]
=
&
ffi_type_void
,
[
JS_FFI_INT8
]
=
&
ffi_type_sint8
,
[
JS_FFI_INT16
]
=
&
ffi_type_sint16
,
[
JS_FFI_INT
]
=
&
ffi_type_sint32
,
[
JS_FFI_INT64
]
=
&
ffi_type_sint64
,
[
JS_FFI_UINT8
]
=
&
ffi_type_uint8
,
[
JS_FFI_UINT16
]
=
&
ffi_type_uint16
,
[
JS_FFI_UINT64
]
=
&
ffi_type_uint64
,
[
JS_FFI_FLOAT
]
=
&
ffi_type_float
,
[
JS_FFI_DOUBLE
]
=
&
ffi_type_double
,
[
JS_FFI_POINTER
]
=
&
ffi_type_pointer
,
[
JS_FFI_STRING
]
=
&
ffi_type_pointer
,
[
JS_FFI_UNKNOWN
]
=
NULL
,
};
js_ffi_type_id
id
=
get_ffi_type_id
(
type_str
);
return
type_map
[
id
];
}
static
void
*
js_to_ffi_value
(
ant_t
*
js
,
ant_value_t
val
,
ffi_type
*
type
,
void
*
buffer
)
{
static
const
void
*
dispatch
[]
=
{
&&
do_sint8
,
&&
do_sint16
,
&&
do_sint32
,
&&
do_sint64
,
&&
do_uint8
,
&&
do_uint16
,
&&
do_uint64
,
&&
do_float
,
&&
do_double
,
&&
do_pointer
,
&&
do_done
};
int
idx
;
if
(
type
==
&
ffi_type_sint8
)
idx
=
0
;
else
if
(
type
==
&
ffi_type_sint16
)
idx
=
1
;
else
if
(
type
==
&
ffi_type_sint32
)
idx
=
2
;
else
if
(
type
==
&
ffi_type_sint64
)
idx
=
3
;
else
if
(
type
==
&
ffi_type_uint8
)
idx
=
4
;
else
if
(
type
==
&
ffi_type_uint16
)
idx
=
5
;
else
if
(
type
==
&
ffi_type_uint64
)
idx
=
6
;
else
if
(
type
==
&
ffi_type_float
)
idx
=
7
;
else
if
(
type
==
&
ffi_type_double
)
idx
=
8
;
else
if
(
type
==
&
ffi_type_pointer
)
idx
=
9
;
else
idx
=
10
;
goto
*
dispatch
[
idx
];
do_sint8
:
{
int8_t
v
=
(
int8_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_sint16
:
{
int16_t
v
=
(
int16_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_sint32
:
{
int32_t
v
=
(
int32_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_sint64
:
{
int64_t
v
=
(
int64_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_uint8
:
{
uint8_t
v
=
(
uint8_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_uint16
:
{
uint16_t
v
=
(
uint16_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_uint64
:
{
uint64_t
v
=
(
uint64_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_float
:
{
float
v
=
(
float
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_double
:
{
double
v
=
js_getnum
(
val
);
memcpy
(
buffer
,
&
v
,
sizeof
(
v
));
goto
do_done
;
}
do_pointer
:
{
if
(
vtype
(
val
)
==
T_STR
)
{
size_t
str_len
;
const
char
*
str
=
js_getstr
(
js
,
val
,
&
str_len
);
void
*
ptr
=
(
void
*
)
str
;
memcpy
(
buffer
,
&
ptr
,
sizeof
(
ptr
));
}
else
{
void
*
ptr
=
(
void
*
)(
uint64_t
)
js_getnum
(
val
);
memcpy
(
buffer
,
&
ptr
,
sizeof
(
ptr
));
}
goto
do_done
;
}
do_done
:
return
buffer
;
}
static
ant_value_t
ffi_to_js_value
(
ant_t
*
js
,
void
*
val
,
ffi_type
*
type
,
const
char
*
type_str
)
{
static
const
void
*
dispatch
[]
=
{
&&
ret_void
,
&&
ret_sint8
,
&&
ret_sint16
,
&&
ret_sint32
,
&&
ret_sint64
,
&&
ret_uint8
,
&&
ret_uint16
,
&&
ret_uint64
,
&&
ret_float
,
&&
ret_double
,
&&
ret_pointer
,
&&
ret_undef
};
int
idx
;
if
(
type
==
&
ffi_type_void
)
idx
=
0
;
else
if
(
type
==
&
ffi_type_sint8
)
idx
=
1
;
else
if
(
type
==
&
ffi_type_sint16
)
idx
=
2
;
else
if
(
type
==
&
ffi_type_sint32
)
idx
=
3
;
else
if
(
type
==
&
ffi_type_sint64
)
idx
=
4
;
else
if
(
type
==
&
ffi_type_uint8
)
idx
=
5
;
else
if
(
type
==
&
ffi_type_uint16
)
idx
=
6
;
else
if
(
type
==
&
ffi_type_uint64
)
idx
=
7
;
else
if
(
type
==
&
ffi_type_float
)
idx
=
8
;
else
if
(
type
==
&
ffi_type_double
)
idx
=
9
;
else
if
(
type
==
&
ffi_type_pointer
)
idx
=
10
;
else
idx
=
11
;
goto
*
dispatch
[
idx
];
ret_void
:
return
js_mkundef
();
ret_sint8
:
return
js_mknum
((
double
)(
*
(
int8_t
*
)
val
));
ret_sint16
:
return
js_mknum
((
double
)(
*
(
int16_t
*
)
val
));
ret_sint32
:
return
js_mknum
((
double
)(
*
(
int32_t
*
)
val
));
ret_sint64
:
return
js_mknum
((
double
)(
*
(
int64_t
*
)
val
));
ret_uint8
:
return
js_mknum
((
double
)(
*
(
uint8_t
*
)
val
));
ret_uint16
:
return
js_mknum
((
double
)(
*
(
uint16_t
*
)
val
));
ret_uint64
:
return
js_mknum
((
double
)(
*
(
uint64_t
*
)
val
));
ret_float
:
return
js_mknum
((
double
)(
*
(
float
*
)
val
));
ret_double
:
return
js_mknum
((
double
)(
*
(
double
*
)
val
));
ret_pointer
:
{
void
*
ptr
=
*
(
void
**
)
val
;
if
(
type_str
&&
strcmp
(
type_str
,
"string"
)
==
0
&&
ptr
)
{
const
char
*
str
=
(
const
char
*
)
ptr
;
if
(
str
&&
strlen
(
str
)
<
1024
)
return
js_mkstr
(
js
,
str
,
strlen
(
str
));
}
return
js_mknum
((
double
)(
uint64_t
)
ptr
);
}
ret_undef
:
return
js_mkundef
();
}
void
gc_mark_ffi
(
ant_t
*
js
,
gc_mark_fn
mark
)
{
pthread_mutex_lock
(
&
ffi_callbacks_mutex
);
ffi_callback_t
*
cb
,
*
tmp
;
HASH_ITER
(
hh
,
ffi_callbacks
,
cb
,
tmp
)
{
mark
(
js
,
cb
->
js_func
);
}
pthread_mutex_unlock
(
&
ffi_callbacks_mutex
);
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, May 3, 7:31 AM (2 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
534627
Default Alt Text
ffi.c (31 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment