2022-06-06 23:54:17 +00:00
/*
2023-01-07 21:03:35 +00:00
* Copyright ( c ) 2023 Calvin Rose
2022-06-06 23:54:17 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to
* deal in the Software without restriction , including without limitation the
* rights to use , copy , modify , merge , publish , distribute , sublicense , and / or
* sell copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
* FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE .
*/
# ifndef JANET_AMALG
# include "features.h"
# include <janet.h>
# include "util.h"
2023-02-12 15:03:31 +00:00
# include "gc.h"
2022-06-06 23:54:17 +00:00
# endif
# ifdef JANET_FFI
2022-06-08 14:59:13 +00:00
# ifdef _MSC_VER
# define alloca _alloca
2022-06-18 17:18:06 +00:00
# elif defined(JANET_LINUX)
2022-06-18 17:15:06 +00:00
# include <alloca.h>
2022-06-18 18:54:47 +00:00
# elif !defined(alloca)
/* Last ditch effort to get alloca - works for gcc and clang */
# define alloca __builtin_alloca
2022-06-08 14:59:13 +00:00
# endif
2022-12-03 17:26:23 +00:00
/* FFI jit includes */
# ifdef JANET_FFI_JIT
# ifndef JANET_WINDOWS
# include <sys/mman.h>
# endif
# endif
2022-06-10 17:24:50 +00:00
# define JANET_FFI_MAX_RECUR 64
2022-06-12 15:12:45 +00:00
/* Compiler, OS, and arch detection. Used
* to enable a set of calling conventions . The
* : none calling convention is always enabled . */
2022-06-12 02:43:35 +00:00
# if defined(JANET_WINDOWS) && (defined(__x86_64__) || defined(_M_X64))
# define JANET_FFI_WIN64_ENABLED
# endif
2022-06-12 14:16:10 +00:00
# if (defined(__x86_64__) || defined(_M_X64)) && !defined(JANET_WINDOWS)
# define JANET_FFI_SYSV64_ENABLED
# endif
2022-06-12 02:43:35 +00:00
2022-06-10 01:27:56 +00:00
typedef struct JanetFFIType JanetFFIType ;
typedef struct JanetFFIStruct JanetFFIStruct ;
2022-06-06 23:54:17 +00:00
typedef enum {
JANET_FFI_TYPE_VOID ,
JANET_FFI_TYPE_BOOL ,
JANET_FFI_TYPE_PTR ,
2022-06-19 13:03:07 +00:00
JANET_FFI_TYPE_STRING ,
2022-06-06 23:54:17 +00:00
JANET_FFI_TYPE_FLOAT ,
JANET_FFI_TYPE_DOUBLE ,
JANET_FFI_TYPE_INT8 ,
JANET_FFI_TYPE_UINT8 ,
JANET_FFI_TYPE_INT16 ,
JANET_FFI_TYPE_UINT16 ,
JANET_FFI_TYPE_INT32 ,
JANET_FFI_TYPE_UINT32 ,
JANET_FFI_TYPE_INT64 ,
JANET_FFI_TYPE_UINT64 ,
2022-06-10 01:27:56 +00:00
JANET_FFI_TYPE_STRUCT
2022-06-06 23:54:17 +00:00
} JanetFFIPrimType ;
2022-06-08 14:41:09 +00:00
/* 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 ( char ) , ALIGNOF ( char ) } , /* JANET_FFI_TYPE_BOOL */
{ sizeof ( void * ) , ALIGNOF ( void * ) } , /* JANET_FFI_TYPE_PTR */
2022-06-19 13:03:07 +00:00
{ sizeof ( char * ) , ALIGNOF ( char * ) } , /* JANET_FFI_TYPE_STRING */
2022-06-08 14:41:09 +00:00
{ 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 */
2022-06-10 01:27:56 +00:00
{ 0 , ALIGNOF ( uint64_t ) } /* JANET_FFI_TYPE_STRUCT */
2022-06-06 23:54:17 +00:00
} ;
2022-06-10 01:27:56 +00:00
struct JanetFFIType {
JanetFFIStruct * st ;
JanetFFIPrimType prim ;
2022-06-20 16:09:41 +00:00
int32_t array_count ;
2022-06-10 01:27:56 +00:00
} ;
2022-06-10 23:53:22 +00:00
typedef struct {
JanetFFIType type ;
size_t offset ;
} JanetFFIStructMember ;
2022-06-19 13:03:07 +00:00
/* Also used to store array types */
2022-06-10 01:27:56 +00:00
struct JanetFFIStruct {
2022-06-08 14:41:09 +00:00
uint32_t size ;
uint32_t align ;
uint32_t field_count ;
2022-06-10 23:53:22 +00:00
uint32_t is_aligned ;
JanetFFIStructMember fields [ ] ;
2022-06-10 01:27:56 +00:00
} ;
2022-06-08 14:41:09 +00:00
2022-06-10 01:27:56 +00:00
/* Specifies how the registers are classified. This is used
* to determine if a certain argument should be passed in a register ,
* on the stack , special floating pointer register , etc . */
typedef enum {
JANET_SYSV64_INTEGER ,
JANET_SYSV64_SSE ,
JANET_SYSV64_SSEUP ,
2022-09-20 14:28:46 +00:00
JANET_SYSV64_PAIR_INTINT ,
JANET_SYSV64_PAIR_INTSSE ,
JANET_SYSV64_PAIR_SSEINT ,
JANET_SYSV64_PAIR_SSESSE ,
2022-06-10 01:27:56 +00:00
JANET_SYSV64_NO_CLASS ,
2022-06-12 02:43:35 +00:00
JANET_SYSV64_MEMORY ,
JANET_WIN64_REGISTER ,
2022-06-12 14:16:10 +00:00
JANET_WIN64_STACK ,
JANET_WIN64_REGISTER_REF ,
JANET_WIN64_STACK_REF
2022-06-10 01:27:56 +00:00
} JanetFFIWordSpec ;
/* Describe how each Janet argument is interpreted in terms of machine words
* that will be mapped to registers / stack . */
2022-06-08 14:41:09 +00:00
typedef struct {
2022-06-10 01:27:56 +00:00
JanetFFIType type ;
JanetFFIWordSpec spec ;
uint32_t offset ; /* point to the exact register / stack offset depending on spec. */
2022-06-12 14:16:10 +00:00
uint32_t offset2 ; /* for reference passing apis (windows), use to allocate reference */
2022-06-08 14:41:09 +00:00
} JanetFFIMapping ;
2022-06-06 23:54:17 +00:00
typedef enum {
2022-06-12 15:12:45 +00:00
JANET_FFI_CC_NONE ,
2022-06-12 02:43:35 +00:00
JANET_FFI_CC_SYSV_64 ,
JANET_FFI_CC_WIN_64
2022-06-06 23:54:17 +00:00
} JanetFFICallingConvention ;
2022-06-12 15:12:45 +00:00
# ifdef JANET_FFI_WIN64_ENABLED
2022-06-12 02:43:35 +00:00
# define JANET_FFI_CC_DEFAULT JANET_FFI_CC_WIN_64
2022-06-12 15:12:45 +00:00
# elif defined(JANET_FFI_SYSV64_ENABLED)
2022-06-12 02:43:35 +00:00
# define JANET_FFI_CC_DEFAULT JANET_FFI_CC_SYSV_64
2022-06-12 15:12:45 +00:00
# else
# define JANET_FFI_CC_DEFAULT JANET_FFI_CC_NONE
2022-06-12 02:43:35 +00:00
# endif
2022-06-10 01:27:56 +00:00
# define JANET_FFI_MAX_ARGS 32
2022-06-06 23:54:17 +00:00
typedef struct {
uint32_t frame_size ;
uint32_t arg_count ;
2022-06-10 01:27:56 +00:00
uint32_t word_count ;
2022-06-08 14:41:09 +00:00
uint32_t variant ;
2022-06-10 01:27:56 +00:00
uint32_t stack_count ;
2022-06-06 23:54:17 +00:00
JanetFFICallingConvention cc ;
2022-06-10 17:24:50 +00:00
JanetFFIMapping ret ;
2022-06-10 01:27:56 +00:00
JanetFFIMapping args [ JANET_FFI_MAX_ARGS ] ;
2022-06-06 23:54:17 +00:00
} JanetFFISignature ;
2022-06-10 01:27:56 +00:00
int signature_mark ( void * p , size_t s ) {
( void ) s ;
JanetFFISignature * sig = p ;
for ( uint32_t i = 0 ; i < sig - > arg_count ; i + + ) {
JanetFFIType t = sig - > args [ i ] . type ;
if ( t . prim = = JANET_FFI_TYPE_STRUCT ) {
janet_mark ( janet_wrap_abstract ( t . st ) ) ;
}
}
return 0 ;
}
2022-06-06 23:54:17 +00:00
static const JanetAbstractType janet_signature_type = {
" core/ffi-signature " ,
2022-06-10 01:27:56 +00:00
NULL ,
signature_mark ,
JANET_ATEND_GCMARK
2022-06-06 23:54:17 +00:00
} ;
2022-06-10 01:27:56 +00:00
int struct_mark ( void * p , size_t s ) {
( void ) s ;
JanetFFIStruct * st = p ;
for ( uint32_t i = 0 ; i < st - > field_count ; i + + ) {
2022-06-10 23:53:22 +00:00
JanetFFIType t = st - > fields [ i ] . type ;
2022-06-10 01:27:56 +00:00
if ( t . prim = = JANET_FFI_TYPE_STRUCT ) {
janet_mark ( janet_wrap_abstract ( t . st ) ) ;
}
}
return 0 ;
}
2022-12-03 17:26:23 +00:00
typedef struct {
void * function_pointer ;
size_t size ;
} JanetFFIJittedFn ;
2022-06-10 01:27:56 +00:00
static const JanetAbstractType janet_struct_type = {
" core/ffi-struct " ,
NULL ,
struct_mark ,
JANET_ATEND_GCMARK
} ;
2022-12-03 17:26:23 +00:00
static int janet_ffijit_gc ( void * p , size_t s ) {
( void ) s ;
JanetFFIJittedFn * fn = p ;
if ( fn - > function_pointer = = NULL ) return 0 ;
# ifdef JANET_FFI_JIT
# ifdef JANET_WINDOWS
VirtualFree ( fn - > function_pointer , fn - > size , MEM_RELEASE ) ;
# else
munmap ( fn - > function_pointer , fn - > size ) ;
# endif
# endif
return 0 ;
}
static JanetByteView janet_ffijit_getbytes ( void * p , size_t s ) {
( void ) s ;
JanetFFIJittedFn * fn = p ;
JanetByteView bytes ;
bytes . bytes = fn - > function_pointer ;
2022-12-03 18:10:22 +00:00
bytes . len = ( int32_t ) fn - > size ;
2022-12-03 17:26:23 +00:00
return bytes ;
}
2022-12-04 16:27:28 +00:00
static size_t janet_ffijit_length ( void * p , size_t s ) {
( void ) s ;
JanetFFIJittedFn * fn = p ;
return fn - > size ;
}
2022-12-03 17:26:23 +00:00
const JanetAbstractType janet_type_ffijit = {
. name = " ffi/jitfn " ,
. gc = janet_ffijit_gc ,
2022-12-04 16:27:28 +00:00
. bytes = janet_ffijit_getbytes ,
. length = janet_ffijit_length
2022-12-03 17:26:23 +00:00
} ;
2022-06-12 15:02:02 +00:00
typedef struct {
Clib clib ;
int closed ;
2022-06-18 15:31:00 +00:00
int is_self ;
2022-06-12 15:02:02 +00:00
} JanetAbstractNative ;
static const JanetAbstractType janet_native_type = {
" core/ffi-native " ,
JANET_ATEND_NAME
} ;
2022-06-10 01:27:56 +00:00
static JanetFFIType prim_type ( JanetFFIPrimType pt ) {
JanetFFIType t ;
t . prim = pt ;
t . st = NULL ;
2022-06-19 21:29:55 +00:00
t . array_count = - 1 ;
2022-06-10 01:27:56 +00:00
return t ;
}
static size_t type_size ( JanetFFIType t ) {
2022-06-19 21:29:55 +00:00
size_t count = t . array_count < 0 ? 1 : ( size_t ) t . array_count ;
2022-06-10 01:27:56 +00:00
if ( t . prim = = JANET_FFI_TYPE_STRUCT ) {
2022-06-19 13:03:07 +00:00
return t . st - > size * count ;
2022-06-10 01:27:56 +00:00
} else {
2022-06-19 13:03:07 +00:00
return janet_ffi_type_info [ t . prim ] . size * count ;
2022-06-10 01:27:56 +00:00
}
}
static size_t type_align ( JanetFFIType t ) {
if ( t . prim = = JANET_FFI_TYPE_STRUCT ) {
return t . st - > align ;
} else {
return janet_ffi_type_info [ t . prim ] . align ;
}
}
2022-06-06 23:54:17 +00:00
static JanetFFICallingConvention decode_ffi_cc ( const uint8_t * name ) {
2022-06-12 15:12:45 +00:00
if ( ! janet_cstrcmp ( name , " none " ) ) return JANET_FFI_CC_NONE ;
# ifdef JANET_FFI_WIN64_ENABLED
if ( ! janet_cstrcmp ( name , " win64 " ) ) return JANET_FFI_CC_WIN_64 ;
# endif
# ifdef JANET_FFI_SYSV64_ENABLED
2022-06-08 14:41:09 +00:00
if ( ! janet_cstrcmp ( name , " sysv64 " ) ) return JANET_FFI_CC_SYSV_64 ;
2022-06-12 15:12:45 +00:00
# endif
2022-06-11 20:47:51 +00:00
if ( ! janet_cstrcmp ( name , " default " ) ) return JANET_FFI_CC_DEFAULT ;
2022-06-08 14:41:09 +00:00
janet_panicf ( " unknown calling convention %s " , name ) ;
2022-06-06 23:54:17 +00:00
}
static JanetFFIPrimType decode_ffi_prim ( const uint8_t * name ) {
if ( ! janet_cstrcmp ( name , " void " ) ) return JANET_FFI_TYPE_VOID ;
if ( ! janet_cstrcmp ( name , " bool " ) ) return JANET_FFI_TYPE_BOOL ;
if ( ! janet_cstrcmp ( name , " ptr " ) ) return JANET_FFI_TYPE_PTR ;
2023-02-12 15:03:31 +00:00
if ( ! janet_cstrcmp ( name , " pointer " ) ) return JANET_FFI_TYPE_PTR ;
2022-06-19 13:03:07 +00:00
if ( ! janet_cstrcmp ( name , " string " ) ) return JANET_FFI_TYPE_STRING ;
2022-06-06 23:54:17 +00:00
if ( ! janet_cstrcmp ( name , " float " ) ) return JANET_FFI_TYPE_FLOAT ;
if ( ! janet_cstrcmp ( name , " double " ) ) return JANET_FFI_TYPE_DOUBLE ;
if ( ! janet_cstrcmp ( name , " int8 " ) ) return JANET_FFI_TYPE_INT8 ;
if ( ! janet_cstrcmp ( name , " uint8 " ) ) return JANET_FFI_TYPE_UINT8 ;
if ( ! janet_cstrcmp ( name , " int16 " ) ) return JANET_FFI_TYPE_INT16 ;
if ( ! janet_cstrcmp ( name , " uint16 " ) ) return JANET_FFI_TYPE_UINT16 ;
if ( ! janet_cstrcmp ( name , " int32 " ) ) return JANET_FFI_TYPE_INT32 ;
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 ;
2022-06-08 14:41:09 +00:00
# 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
2022-06-10 01:27:56 +00:00
/* aliases */
2022-06-11 14:40:37 +00:00
if ( ! janet_cstrcmp ( name , " r32 " ) ) return JANET_FFI_TYPE_FLOAT ;
if ( ! janet_cstrcmp ( name , " r64 " ) ) return JANET_FFI_TYPE_DOUBLE ;
2022-06-10 14:38:52 +00:00
if ( ! janet_cstrcmp ( name , " s8 " ) ) return JANET_FFI_TYPE_INT8 ;
if ( ! janet_cstrcmp ( name , " u8 " ) ) return JANET_FFI_TYPE_UINT8 ;
if ( ! janet_cstrcmp ( name , " s16 " ) ) return JANET_FFI_TYPE_INT16 ;
if ( ! janet_cstrcmp ( name , " u16 " ) ) return JANET_FFI_TYPE_UINT16 ;
if ( ! janet_cstrcmp ( name , " s32 " ) ) return JANET_FFI_TYPE_INT32 ;
if ( ! janet_cstrcmp ( name , " u32 " ) ) return JANET_FFI_TYPE_UINT32 ;
if ( ! janet_cstrcmp ( name , " s64 " ) ) return JANET_FFI_TYPE_INT64 ;
if ( ! janet_cstrcmp ( name , " u64 " ) ) return JANET_FFI_TYPE_UINT64 ;
2022-06-10 01:27:56 +00:00
if ( ! janet_cstrcmp ( name , " char " ) ) return JANET_FFI_TYPE_INT8 ;
if ( ! janet_cstrcmp ( name , " short " ) ) return JANET_FFI_TYPE_INT16 ;
if ( ! janet_cstrcmp ( name , " int " ) ) return JANET_FFI_TYPE_INT32 ;
if ( ! janet_cstrcmp ( name , " long " ) ) return JANET_FFI_TYPE_INT64 ;
if ( ! janet_cstrcmp ( name , " byte " ) ) return JANET_FFI_TYPE_UINT8 ;
2022-06-19 21:29:55 +00:00
if ( ! janet_cstrcmp ( name , " uchar " ) ) return JANET_FFI_TYPE_UINT8 ;
2022-06-10 01:27:56 +00:00
if ( ! janet_cstrcmp ( name , " ushort " ) ) return JANET_FFI_TYPE_UINT16 ;
if ( ! janet_cstrcmp ( name , " uint " ) ) return JANET_FFI_TYPE_UINT32 ;
if ( ! janet_cstrcmp ( name , " ulong " ) ) return JANET_FFI_TYPE_UINT64 ;
2022-06-06 23:54:17 +00:00
janet_panicf ( " unknown machine type %s " , name ) ;
}
2022-06-12 14:16:10 +00:00
/* A common callback function signature. To avoid runtime code generation, which is prohibited
* on many platforms , often buggy ( see libffi ) , and generally complicated , instead provide
* a single ( or small set of commonly used function signatures ) . All callbacks should
* eventually call this . */
void janet_ffi_trampoline ( void * ctx , void * userdata ) {
if ( NULL = = userdata ) {
/* Userdata not set. */
janet_eprintf ( " no userdata found for janet callback " ) ;
return ;
}
Janet context = janet_wrap_pointer ( ctx ) ;
JanetFunction * fun = userdata ;
janet_call ( fun , 1 , & context ) ;
}
2022-06-10 01:27:56 +00:00
static JanetFFIType decode_ffi_type ( Janet x ) ;
2022-06-08 14:41:09 +00:00
2022-06-10 01:27:56 +00:00
static JanetFFIStruct * build_struct_type ( int32_t argc , const Janet * argv ) {
2022-06-10 23:53:22 +00:00
/* Use :pack to indicate a single packed struct member and :pack-all
* to pack the remaining members */
int32_t member_count = argc ;
int all_packed = 0 ;
for ( int32_t i = 0 ; i < argc ; i + + ) {
if ( janet_keyeq ( argv [ i ] , " pack " ) ) {
member_count - - ;
} else if ( janet_keyeq ( argv [ i ] , " pack-all " ) ) {
member_count - - ;
all_packed = 1 ;
}
}
2022-06-10 01:27:56 +00:00
JanetFFIStruct * st = janet_abstract ( & janet_struct_type ,
2022-06-10 23:53:22 +00:00
sizeof ( JanetFFIStruct ) + argc * sizeof ( JanetFFIStructMember ) ) ;
st - > field_count = member_count ;
2022-06-10 01:27:56 +00:00
st - > size = 0 ;
st - > align = 1 ;
2022-06-10 23:53:22 +00:00
if ( argc = = 0 ) {
janet_panic ( " invalid empty struct " ) ;
}
uint32_t is_aligned = 1 ;
int32_t i = 0 ;
for ( int32_t j = 0 ; j < argc ; j + + ) {
int pack_one = 0 ;
if ( janet_keyeq ( argv [ j ] , " pack " ) | | janet_keyeq ( argv [ j ] , " pack-all " ) ) {
pack_one = 1 ;
j + + ;
2022-06-19 18:02:26 +00:00
if ( j = = argc ) break ;
2022-06-10 23:53:22 +00:00
}
st - > fields [ i ] . type = decode_ffi_type ( argv [ j ] ) ;
size_t el_size = type_size ( st - > fields [ i ] . type ) ;
size_t el_align = type_align ( st - > fields [ i ] . type ) ;
if ( all_packed | | pack_one ) {
if ( st - > size % el_align ! = 0 ) is_aligned = 0 ;
st - > fields [ i ] . offset = st - > size ;
2022-08-14 18:26:13 +00:00
st - > size + = ( uint32_t ) el_size ;
2022-06-10 23:53:22 +00:00
} else {
2022-08-14 18:26:13 +00:00
if ( el_align > st - > align ) st - > align = ( uint32_t ) el_align ;
st - > fields [ i ] . offset = ( uint32_t ) ( ( ( st - > size + el_align - 1 ) / el_align ) * el_align ) ;
st - > size = ( uint32_t ) ( el_size + st - > fields [ i ] . offset ) ;
2022-06-10 23:53:22 +00:00
}
i + + ;
2022-06-08 14:41:09 +00:00
}
2022-06-10 23:53:22 +00:00
st - > is_aligned = is_aligned ;
2022-06-19 17:58:45 +00:00
st - > size + = ( st - > align - 1 ) ;
st - > size / = st - > align ;
st - > size * = st - > align ;
2022-06-10 01:27:56 +00:00
return st ;
}
static JanetFFIType decode_ffi_type ( Janet x ) {
if ( janet_checktype ( x , JANET_KEYWORD ) ) {
return prim_type ( decode_ffi_prim ( janet_unwrap_keyword ( x ) ) ) ;
2022-06-08 14:41:09 +00:00
}
2022-06-10 01:27:56 +00:00
JanetFFIType ret ;
2022-06-19 21:29:55 +00:00
ret . array_count = - 1 ;
2022-06-10 01:27:56 +00:00
ret . prim = JANET_FFI_TYPE_STRUCT ;
if ( janet_checkabstract ( x , & janet_struct_type ) ) {
ret . st = janet_unwrap_abstract ( x ) ;
return ret ;
2022-06-06 23:54:17 +00:00
}
2022-06-10 01:27:56 +00:00
int32_t len ;
const Janet * els ;
if ( janet_indexed_view ( x , & els , & len ) ) {
2022-06-19 13:03:07 +00:00
if ( janet_checktype ( x , JANET_ARRAY ) ) {
2022-06-19 21:29:55 +00:00
if ( len ! = 2 & & len ! = 1 ) janet_panicf ( " array type must be of form @[type count], got %v " , x ) ;
2022-06-19 13:03:07 +00:00
ret = decode_ffi_type ( els [ 0 ] ) ;
2022-06-19 21:29:55 +00:00
int32_t array_count = len = = 1 ? 0 : janet_getnat ( els , 1 ) ;
2022-06-19 13:03:07 +00:00
ret . array_count = array_count ;
} else {
ret . st = build_struct_type ( len , els ) ;
}
2022-06-10 01:27:56 +00:00
return ret ;
} else {
janet_panicf ( " bad native type %v " , x ) ;
2022-06-06 23:54:17 +00:00
}
2022-06-10 01:27:56 +00:00
}
2022-06-08 14:50:31 +00:00
2022-06-10 01:27:56 +00:00
JANET_CORE_FN ( cfun_ffi_struct ,
2022-06-12 15:02:02 +00:00
" (ffi/struct & types) " ,
2022-06-19 13:03:07 +00:00
" Create a struct type definition that can be used to pass structs into native functions. " ) {
2022-06-10 01:27:56 +00:00
janet_arity ( argc , 1 , - 1 ) ;
return janet_wrap_abstract ( build_struct_type ( argc , argv ) ) ;
2022-06-06 23:54:17 +00:00
}
2022-06-19 13:03:07 +00:00
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 ) ;
}
2022-06-06 23:54:17 +00:00
static void * janet_ffi_getpointer ( const Janet * argv , int32_t n ) {
2022-06-08 14:50:31 +00:00
switch ( janet_type ( argv [ n ] ) ) {
2022-06-06 23:54:17 +00:00
default :
2022-10-30 14:57:40 +00:00
janet_panicf ( " bad slot #%d, expected ffi pointer convertable type, got %v " , n , argv [ n ] ) ;
2022-06-06 23:54:17 +00:00
case JANET_POINTER :
case JANET_STRING :
case JANET_KEYWORD :
case JANET_SYMBOL :
2022-12-03 17:26:23 +00:00
case JANET_CFUNCTION :
2022-06-06 23:54:17 +00:00
return janet_unwrap_pointer ( argv [ n ] ) ;
2022-12-03 17:26:23 +00:00
case JANET_ABSTRACT :
return ( void * ) janet_getbytes ( argv , n ) . bytes ;
2022-06-06 23:54:17 +00:00
case JANET_BUFFER :
return janet_unwrap_buffer ( argv [ n ] ) - > data ;
2022-06-11 19:47:35 +00:00
case JANET_FUNCTION :
/* Users may pass in a function. Any function passed is almost certainly
* being used as a callback , so we add it to the root set . */
janet_gcroot ( argv [ n ] ) ;
return janet_unwrap_pointer ( argv [ n ] ) ;
case JANET_NIL :
return NULL ;
2022-06-06 23:54:17 +00:00
}
}
2022-12-03 17:26:23 +00:00
static void * janet_ffi_get_callable_pointer ( const Janet * argv , int32_t n ) {
switch ( janet_type ( argv [ n ] ) ) {
default :
break ;
case JANET_POINTER :
return janet_unwrap_pointer ( argv [ n ] ) ;
case JANET_ABSTRACT :
if ( ! janet_checkabstract ( argv [ n ] , & janet_type_ffijit ) ) break ;
return ( ( JanetFFIJittedFn * ) janet_unwrap_abstract ( argv [ n ] ) ) - > function_pointer ;
}
janet_panicf ( " bad slot #%d, expected ffi callable pointer type, got %v " , n , argv [ n ] ) ;
}
2022-06-10 01:27:56 +00:00
/* Write a value given by some Janet values and an FFI type as it would appear in memory.
* The alignment and space available is assumed to already be sufficient */
2022-06-10 14:38:52 +00:00
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 " ) ;
2022-06-19 21:29:55 +00:00
if ( type . array_count > = 0 ) {
2022-06-19 13:03:07 +00:00
JanetFFIType el_type = type ;
2022-06-19 21:29:55 +00:00
el_type . array_count = - 1 ;
2022-06-19 13:03:07 +00:00
size_t el_size = type_size ( el_type ) ;
JanetView els = janet_getindexed ( argv , n ) ;
2022-06-19 21:29:55 +00:00
if ( els . len ! = type . array_count ) {
2022-06-19 13:03:07 +00:00
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 ;
}
2022-06-10 01:27:56 +00:00
switch ( type . prim ) {
case JANET_FFI_TYPE_VOID :
2022-06-10 14:38:52 +00:00
if ( ! janet_checktype ( argv [ n ] , JANET_NIL ) ) {
janet_panicf ( " expected nil, got %v " , argv [ n ] ) ;
}
2022-06-10 01:27:56 +00:00
break ;
case JANET_FFI_TYPE_STRUCT : {
JanetView els = janet_getindexed ( argv , n ) ;
JanetFFIStruct * st = type . st ;
if ( ( uint32_t ) els . len ! = st - > field_count ) {
janet_panicf ( " wrong number of fields in struct, expected %d, got %d " ,
( int32_t ) st - > field_count , els . len ) ;
}
for ( int32_t i = 0 ; i < els . len ; i + + ) {
2022-06-10 23:53:22 +00:00
JanetFFIType tp = st - > fields [ i ] . type ;
2022-08-14 18:26:13 +00:00
janet_ffi_write_one ( ( char * ) to + st - > fields [ i ] . offset , els . items , i , tp , recur - 1 ) ;
2022-06-10 01:27:56 +00:00
}
}
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_DOUBLE :
2022-06-10 01:27:56 +00:00
( ( double * ) ( to ) ) [ 0 ] = janet_getnumber ( argv , n ) ;
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_FLOAT :
2022-08-14 18:26:13 +00:00
( ( float * ) ( to ) ) [ 0 ] = ( float ) janet_getnumber ( argv , n ) ;
2022-06-10 01:27:56 +00:00
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_PTR :
2022-06-10 01:27:56 +00:00
( ( void * * ) ( to ) ) [ 0 ] = janet_ffi_getpointer ( argv , n ) ;
break ;
2022-06-19 13:03:07 +00:00
case JANET_FFI_TYPE_STRING :
( ( const char * * ) ( to ) ) [ 0 ] = janet_getcstring ( argv , n ) ;
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_BOOL :
2022-06-10 01:27:56 +00:00
( ( bool * ) ( to ) ) [ 0 ] = janet_getboolean ( argv , n ) ;
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_INT8 :
2022-06-10 01:27:56 +00:00
( ( int8_t * ) ( to ) ) [ 0 ] = janet_getinteger ( argv , n ) ;
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_INT16 :
2022-06-10 01:27:56 +00:00
( ( int16_t * ) ( to ) ) [ 0 ] = janet_getinteger ( argv , n ) ;
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_INT32 :
2022-06-10 01:27:56 +00:00
( ( int32_t * ) ( to ) ) [ 0 ] = janet_getinteger ( argv , n ) ;
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_INT64 :
2022-06-10 01:27:56 +00:00
( ( int64_t * ) ( to ) ) [ 0 ] = janet_getinteger64 ( argv , n ) ;
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_UINT8 :
2022-08-14 18:26:13 +00:00
( ( uint8_t * ) ( to ) ) [ 0 ] = ( uint8_t ) janet_getuinteger64 ( argv , n ) ;
2022-06-10 01:27:56 +00:00
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_UINT16 :
2022-08-14 18:26:13 +00:00
( ( uint16_t * ) ( to ) ) [ 0 ] = ( uint16_t ) janet_getuinteger64 ( argv , n ) ;
2022-06-10 01:27:56 +00:00
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_UINT32 :
2022-08-14 18:26:13 +00:00
( ( uint32_t * ) ( to ) ) [ 0 ] = ( uint32_t ) janet_getuinteger64 ( argv , n ) ;
2022-06-10 01:27:56 +00:00
break ;
2022-06-08 14:41:09 +00:00
case JANET_FFI_TYPE_UINT64 :
2022-06-10 01:27:56 +00:00
( ( uint64_t * ) ( to ) ) [ 0 ] = janet_getuinteger64 ( argv , n ) ;
break ;
2022-06-06 23:54:17 +00:00
}
2022-06-08 14:41:09 +00:00
}
2022-06-06 23:54:17 +00:00
2022-06-10 14:38:52 +00:00
/* Read a value from memory and construct a Janet data structure that can be passed back into
* the interpreter . This should be the inverse to janet_ffi_write_one . It is assumed that the
* size of the data is correct . */
static Janet janet_ffi_read_one ( const uint8_t * from , JanetFFIType type , int recur ) {
if ( recur = = 0 ) janet_panic ( " recursion too deep " ) ;
2022-06-19 21:29:55 +00:00
if ( type . array_count > = 0 ) {
2022-06-19 13:03:07 +00:00
JanetFFIType el_type = type ;
2022-06-19 21:29:55 +00:00
el_type . array_count = - 1 ;
2022-06-19 13:03:07 +00:00
size_t el_size = type_size ( el_type ) ;
JanetArray * array = janet_array ( type . array_count ) ;
2022-06-20 16:09:41 +00:00
for ( int32_t i = 0 ; i < type . array_count ; i + + ) {
2022-06-19 13:03:07 +00:00
janet_array_push ( array , janet_ffi_read_one ( from , el_type , recur - 1 ) ) ;
from + = el_size ;
}
return janet_wrap_array ( array ) ;
}
2022-06-10 14:38:52 +00:00
switch ( type . prim ) {
default :
case JANET_FFI_TYPE_VOID :
return janet_wrap_nil ( ) ;
2022-06-10 17:24:50 +00:00
case JANET_FFI_TYPE_STRUCT : {
JanetFFIStruct * st = type . st ;
Janet * tup = janet_tuple_begin ( st - > field_count ) ;
for ( uint32_t i = 0 ; i < st - > field_count ; i + + ) {
2022-06-10 23:53:22 +00:00
JanetFFIType tp = st - > fields [ i ] . type ;
tup [ i ] = janet_ffi_read_one ( from + st - > fields [ i ] . offset , tp , recur - 1 ) ;
2022-06-10 14:38:52 +00:00
}
2022-06-10 17:24:50 +00:00
return janet_wrap_tuple ( janet_tuple_end ( tup ) ) ;
}
2022-06-10 14:38:52 +00:00
case JANET_FFI_TYPE_DOUBLE :
return janet_wrap_number ( ( ( double * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_FLOAT :
return janet_wrap_number ( ( ( float * ) ( from ) ) [ 0 ] ) ;
2022-06-18 21:53:01 +00:00
case JANET_FFI_TYPE_PTR : {
void * ptr = ( ( void * * ) ( from ) ) [ 0 ] ;
return ( NULL = = ptr ) ? janet_wrap_nil ( ) : janet_wrap_pointer ( ptr ) ;
}
2022-06-19 13:03:07 +00:00
case JANET_FFI_TYPE_STRING :
return janet_cstringv ( ( ( char * * ) ( from ) ) [ 0 ] ) ;
2022-06-10 14:38:52 +00:00
case JANET_FFI_TYPE_BOOL :
return janet_wrap_boolean ( ( ( bool * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_INT8 :
return janet_wrap_number ( ( ( int8_t * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_INT16 :
return janet_wrap_number ( ( ( int16_t * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_INT32 :
return janet_wrap_number ( ( ( int32_t * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_UINT8 :
return janet_wrap_number ( ( ( uint8_t * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_UINT16 :
return janet_wrap_number ( ( ( uint16_t * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_UINT32 :
return janet_wrap_number ( ( ( uint32_t * ) ( from ) ) [ 0 ] ) ;
# ifdef JANET_INT_TYPES
case JANET_FFI_TYPE_INT64 :
return janet_wrap_s64 ( ( ( int64_t * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_UINT64 :
return janet_wrap_u64 ( ( ( uint64_t * ) ( from ) ) [ 0 ] ) ;
# else
case JANET_FFI_TYPE_INT64 :
return janet_wrap_number ( ( ( int64_t * ) ( from ) ) [ 0 ] ) ;
case JANET_FFI_TYPE_UINT64 :
return janet_wrap_number ( ( ( uint64_t * ) ( from ) ) [ 0 ] ) ;
# endif
}
}
2022-06-10 01:27:56 +00:00
static JanetFFIMapping void_mapping ( void ) {
JanetFFIMapping m ;
m . type = prim_type ( JANET_FFI_TYPE_VOID ) ;
m . spec = JANET_SYSV64_NO_CLASS ;
m . offset = 0 ;
return m ;
}
2022-06-12 14:16:10 +00:00
# ifdef JANET_FFI_SYSV64_ENABLED
2022-06-10 01:27:56 +00:00
/* AMD64 ABI Draft 0.99.7 – November 17, 2014 – 15:08
* See section 3.2 .3 Parameter Passing */
2022-09-20 14:45:17 +00:00
static JanetFFIWordSpec sysv64_classify_ext ( JanetFFIType type , size_t shift ) {
2022-06-10 01:27:56 +00:00
switch ( type . prim ) {
2022-06-06 23:54:17 +00:00
case JANET_FFI_TYPE_PTR :
2022-06-19 13:03:07 +00:00
case JANET_FFI_TYPE_STRING :
2022-06-06 23:54:17 +00:00
case JANET_FFI_TYPE_BOOL :
case JANET_FFI_TYPE_INT8 :
case JANET_FFI_TYPE_INT16 :
case JANET_FFI_TYPE_INT32 :
case JANET_FFI_TYPE_INT64 :
case JANET_FFI_TYPE_UINT8 :
case JANET_FFI_TYPE_UINT16 :
case JANET_FFI_TYPE_UINT32 :
case JANET_FFI_TYPE_UINT64 :
2022-06-10 01:27:56 +00:00
return JANET_SYSV64_INTEGER ;
case JANET_FFI_TYPE_DOUBLE :
case JANET_FFI_TYPE_FLOAT :
return JANET_SYSV64_SSE ;
case JANET_FFI_TYPE_STRUCT : {
JanetFFIStruct * st = type . st ;
if ( st - > size > 16 ) return JANET_SYSV64_MEMORY ;
2022-06-10 23:53:22 +00:00
if ( ! st - > is_aligned ) return JANET_SYSV64_MEMORY ;
2022-06-10 01:27:56 +00:00
JanetFFIWordSpec clazz = JANET_SYSV64_NO_CLASS ;
2022-09-20 14:28:46 +00:00
if ( st - > size > 8 & & st - > size < = 16 ) {
/* map to pair classification */
int has_int_lo = 0 ;
int has_int_hi = 0 ;
for ( uint32_t i = 0 ; i < st - > field_count ; i + + ) {
2022-09-20 14:45:17 +00:00
JanetFFIWordSpec next_class = sysv64_classify_ext ( st - > fields [ i ] . type , shift + st - > fields [ i ] . offset ) ;
2022-09-20 14:28:46 +00:00
switch ( next_class ) {
default :
break ;
case JANET_SYSV64_INTEGER :
2022-09-20 14:45:17 +00:00
if ( shift + st - > fields [ i ] . offset + type_size ( st - > fields [ i ] . type ) < = 8 ) {
2022-09-20 14:28:46 +00:00
has_int_lo = 1 ;
2022-09-20 14:45:17 +00:00
} else {
has_int_hi = 2 ;
2022-09-20 14:28:46 +00:00
}
2022-09-20 14:45:17 +00:00
break ;
case JANET_SYSV64_PAIR_INTINT :
has_int_lo = 1 ;
has_int_hi = 2 ;
break ;
case JANET_SYSV64_PAIR_INTSSE :
has_int_lo = 1 ;
break ;
case JANET_SYSV64_PAIR_SSEINT :
has_int_hi = 2 ;
break ;
break ;
2022-09-20 14:28:46 +00:00
}
}
switch ( has_int_hi + has_int_lo ) {
case 0 :
clazz = JANET_SYSV64_PAIR_SSESSE ;
break ;
case 1 :
clazz = JANET_SYSV64_PAIR_INTSSE ;
break ;
case 2 :
clazz = JANET_SYSV64_PAIR_SSEINT ;
break ;
case 3 :
clazz = JANET_SYSV64_PAIR_INTINT ;
break ;
}
} else {
/* Normal struct classification */
for ( uint32_t i = 0 ; i < st - > field_count ; i + + ) {
2022-09-20 14:45:17 +00:00
JanetFFIWordSpec next_class = sysv64_classify_ext ( st - > fields [ i ] . type , shift + st - > fields [ i ] . offset ) ;
2022-09-20 14:28:46 +00:00
if ( next_class ! = clazz ) {
if ( clazz = = JANET_SYSV64_NO_CLASS ) {
clazz = next_class ;
} else if ( clazz = = JANET_SYSV64_MEMORY | | next_class = = JANET_SYSV64_MEMORY ) {
clazz = JANET_SYSV64_MEMORY ;
} else if ( clazz = = JANET_SYSV64_INTEGER | | next_class = = JANET_SYSV64_INTEGER ) {
clazz = JANET_SYSV64_INTEGER ;
} else {
clazz = JANET_SYSV64_SSE ;
}
2022-06-10 01:27:56 +00:00
}
}
}
return clazz ;
}
case JANET_FFI_TYPE_VOID :
2022-06-10 17:33:01 +00:00
return JANET_SYSV64_NO_CLASS ;
2022-06-10 01:27:56 +00:00
default :
janet_panic ( " nyi " ) ;
return JANET_SYSV64_NO_CLASS ;
2022-06-06 23:54:17 +00:00
}
2022-06-08 14:41:09 +00:00
}
2022-09-20 14:45:17 +00:00
static JanetFFIWordSpec sysv64_classify ( JanetFFIType type ) {
return sysv64_classify_ext ( type , 0 ) ;
}
2022-06-12 14:16:10 +00:00
# endif
2022-06-08 14:41:09 +00:00
2022-06-10 01:27:56 +00:00
JANET_CORE_FN ( cfun_ffi_signature ,
2022-06-12 15:02:02 +00:00
" (ffi/signature calling-convention ret-type & arg-types) " ,
2022-06-10 01:27:56 +00:00
" 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 variant = 0 ;
uint32_t arg_count = argc - 2 ;
uint32_t stack_count = 0 ;
JanetFFICallingConvention cc = decode_ffi_cc ( janet_getkeyword ( argv , 0 ) ) ;
JanetFFIType ret_type = decode_ffi_type ( argv [ 1 ] ) ;
2022-06-10 17:24:50 +00:00
JanetFFIMapping ret = {
ret_type ,
JANET_SYSV64_NO_CLASS ,
2022-06-12 14:16:10 +00:00
0 ,
2022-06-10 17:24:50 +00:00
0
} ;
2022-06-10 01:27:56 +00:00
JanetFFIMapping mappings [ JANET_FFI_MAX_ARGS ] ;
for ( int i = 0 ; i < JANET_FFI_MAX_ARGS ; i + + ) mappings [ i ] = void_mapping ( ) ;
switch ( cc ) {
default :
2022-06-12 15:12:45 +00:00
case JANET_FFI_CC_NONE : {
/* Even if unsupported, we can check that the signature is valid
* and error at runtime */
for ( uint32_t i = 0 ; i < arg_count ; i + + ) {
decode_ffi_type ( argv [ i + 2 ] ) ;
}
}
break ;
2022-06-12 02:43:35 +00:00
# ifdef JANET_FFI_WIN64_ENABLED
case JANET_FFI_CC_WIN_64 : {
size_t ret_size = type_size ( ret . type ) ;
2022-08-14 18:26:13 +00:00
uint32_t ref_stack_count = 0 ;
2022-06-12 02:43:35 +00:00
ret . spec = JANET_WIN64_REGISTER ;
uint32_t next_register = 0 ;
2022-09-15 18:51:11 +00:00
if ( ret_size ! = 0 & & ret_size ! = 1 & & ret_size ! = 2 & & ret_size ! = 4 & & ret_size ! = 8 ) {
2022-06-12 14:16:10 +00:00
ret . spec = JANET_WIN64_REGISTER_REF ;
2022-06-12 02:43:35 +00:00
next_register + + ;
2022-06-12 14:16:10 +00:00
} else if ( ret . type . prim = = JANET_FFI_TYPE_FLOAT | |
ret . type . prim = = JANET_FFI_TYPE_DOUBLE ) {
variant + = 16 ;
2022-06-12 02:43:35 +00:00
}
for ( uint32_t i = 0 ; i < arg_count ; i + + ) {
mappings [ i ] . type = decode_ffi_type ( argv [ i + 2 ] ) ;
2022-06-12 14:16:10 +00:00
size_t el_size = type_size ( mappings [ i ] . type ) ;
int is_register_sized = ( el_size = = 1 | | el_size = = 2 | | el_size = = 4 | | el_size = = 8 ) ;
if ( next_register < 4 ) {
2022-08-14 18:26:13 +00:00
mappings [ i ] . offset = next_register ;
2022-06-12 14:16:10 +00:00
if ( is_register_sized ) {
mappings [ i ] . spec = JANET_WIN64_REGISTER ;
if ( mappings [ i ] . type . prim = = JANET_FFI_TYPE_FLOAT | |
mappings [ i ] . type . prim = = JANET_FFI_TYPE_DOUBLE ) {
2022-08-14 18:26:13 +00:00
variant + = 1 < < ( 3 - next_register ) ;
2022-06-12 14:16:10 +00:00
}
} else {
mappings [ i ] . spec = JANET_WIN64_REGISTER_REF ;
mappings [ i ] . offset2 = ref_stack_count ;
2022-08-14 18:26:13 +00:00
ref_stack_count + = ( uint32_t ) ( ( el_size + 15 ) / 16 ) ;
2022-06-12 14:16:10 +00:00
}
2022-08-14 18:26:13 +00:00
next_register + + ;
2022-06-12 14:16:10 +00:00
} else {
if ( is_register_sized ) {
mappings [ i ] . spec = JANET_WIN64_STACK ;
mappings [ i ] . offset = stack_count ;
stack_count + + ;
} else {
mappings [ i ] . spec = JANET_WIN64_STACK_REF ;
mappings [ i ] . offset = stack_count ;
stack_count + + ;
mappings [ i ] . offset2 = ref_stack_count ;
2022-08-14 18:26:13 +00:00
ref_stack_count + = ( uint32_t ) ( ( el_size + 15 ) / 16 ) ;
2022-06-12 14:16:10 +00:00
}
}
}
2022-08-14 20:20:30 +00:00
/* Add reference items */
2022-06-12 14:16:10 +00:00
stack_count + = 2 * ref_stack_count ;
2022-08-14 20:20:30 +00:00
if ( stack_count & 0x1 ) {
2022-06-12 14:16:10 +00:00
stack_count + + ;
}
/* Invert stack
* Offsets are in units of 8 - bytes */
for ( uint32_t i = 0 ; i < arg_count ; i + + ) {
if ( mappings [ i ] . spec = = JANET_WIN64_STACK_REF | | mappings [ i ] . spec = = JANET_WIN64_REGISTER_REF ) {
/* Align size to 16 bytes */
size_t size = ( type_size ( mappings [ i ] . type ) + 15 ) & ~ 0xFUL ;
2022-08-14 18:26:13 +00:00
mappings [ i ] . offset2 = ( uint32_t ) ( stack_count - mappings [ i ] . offset2 - ( size / 8 ) ) ;
2022-06-12 14:16:10 +00:00
}
2022-06-12 02:43:35 +00:00
}
}
break ;
# endif
2022-06-12 14:16:10 +00:00
# ifdef JANET_FFI_SYSV64_ENABLED
2022-06-10 01:27:56 +00:00
case JANET_FFI_CC_SYSV_64 : {
2022-06-10 17:24:50 +00:00
JanetFFIWordSpec ret_spec = sysv64_classify ( ret . type ) ;
ret . spec = ret_spec ;
2022-06-12 14:16:10 +00:00
if ( ret_spec = = JANET_SYSV64_SSE ) variant = 1 ;
2022-09-20 14:28:46 +00:00
if ( ret_spec = = JANET_SYSV64_PAIR_INTSSE ) variant = 2 ;
if ( ret_spec = = JANET_SYSV64_PAIR_SSEINT ) variant = 3 ;
2022-06-10 01:27:56 +00:00
/* Spill register overflow to memory */
uint32_t next_register = 0 ;
uint32_t next_fp_register = 0 ;
const uint32_t max_regs = 6 ;
const uint32_t max_fp_regs = 8 ;
2022-06-10 17:24:50 +00:00
if ( ret_spec = = JANET_SYSV64_MEMORY ) {
/* First integer reg is pointer. */
next_register = 1 ;
}
2022-06-10 01:27:56 +00:00
for ( uint32_t i = 0 ; i < arg_count ; i + + ) {
2022-06-10 17:24:50 +00:00
mappings [ i ] . type = decode_ffi_type ( argv [ i + 2 ] ) ;
mappings [ i ] . offset = 0 ;
mappings [ i ] . spec = sysv64_classify ( mappings [ i ] . type ) ;
2022-06-10 17:33:01 +00:00
if ( mappings [ i ] . spec = = JANET_SYSV64_NO_CLASS ) {
janet_panic ( " unexpected void parameter " ) ;
}
2022-06-10 01:27:56 +00:00
size_t el_size = ( type_size ( mappings [ i ] . type ) + 7 ) / 8 ;
switch ( mappings [ i ] . spec ) {
default :
janet_panicf ( " nyi: %d " , mappings [ i ] . spec ) ;
case JANET_SYSV64_INTEGER : {
if ( next_register < max_regs ) {
mappings [ i ] . offset = next_register + + ;
} else {
mappings [ i ] . spec = JANET_SYSV64_MEMORY ;
mappings [ i ] . offset = stack_count ;
stack_count + = el_size ;
}
}
2022-09-20 14:28:46 +00:00
break ;
2022-06-10 01:27:56 +00:00
case JANET_SYSV64_SSE : {
if ( next_fp_register < max_fp_regs ) {
mappings [ i ] . offset = next_fp_register + + ;
} else {
mappings [ i ] . spec = JANET_SYSV64_MEMORY ;
mappings [ i ] . offset = stack_count ;
stack_count + = el_size ;
}
}
2022-09-20 14:28:46 +00:00
break ;
2022-06-10 01:27:56 +00:00
case JANET_SYSV64_MEMORY : {
mappings [ i ] . offset = stack_count ;
stack_count + = el_size ;
}
2022-09-20 14:28:46 +00:00
break ;
case JANET_SYSV64_PAIR_INTINT : {
if ( next_register + 1 < max_regs ) {
mappings [ i ] . offset = next_register + + ;
mappings [ i ] . offset2 = next_register + + ;
} else {
mappings [ i ] . spec = JANET_SYSV64_MEMORY ;
mappings [ i ] . offset = stack_count ;
stack_count + = el_size ;
}
}
break ;
case JANET_SYSV64_PAIR_INTSSE : {
if ( next_register < max_regs & & next_fp_register < max_fp_regs ) {
mappings [ i ] . offset = next_register + + ;
mappings [ i ] . offset2 = next_fp_register + + ;
} else {
mappings [ i ] . spec = JANET_SYSV64_MEMORY ;
mappings [ i ] . offset = stack_count ;
stack_count + = el_size ;
}
}
break ;
case JANET_SYSV64_PAIR_SSEINT : {
if ( next_register < max_regs & & next_fp_register < max_fp_regs ) {
mappings [ i ] . offset = next_fp_register + + ;
mappings [ i ] . offset2 = next_register + + ;
} else {
mappings [ i ] . spec = JANET_SYSV64_MEMORY ;
mappings [ i ] . offset = stack_count ;
stack_count + = el_size ;
}
}
break ;
case JANET_SYSV64_PAIR_SSESSE : {
if ( next_fp_register < max_fp_regs ) {
mappings [ i ] . offset = next_fp_register + + ;
mappings [ i ] . offset2 = next_fp_register + + ;
} else {
mappings [ i ] . spec = JANET_SYSV64_MEMORY ;
mappings [ i ] . offset = stack_count ;
stack_count + = el_size ;
}
}
break ;
2022-06-10 01:27:56 +00:00
}
2022-06-12 14:16:10 +00:00
}
2022-06-10 01:27:56 +00:00
}
break ;
2022-06-12 14:16:10 +00:00
# endif
2022-06-10 01:27:56 +00:00
}
/* Create signature abstract value */
JanetFFISignature * abst = janet_abstract ( & janet_signature_type , sizeof ( JanetFFISignature ) ) ;
abst - > frame_size = frame_size ;
abst - > cc = cc ;
2022-06-10 17:24:50 +00:00
abst - > ret = ret ;
2022-06-10 01:27:56 +00:00
abst - > arg_count = arg_count ;
abst - > variant = variant ;
abst - > stack_count = stack_count ;
memcpy ( abst - > args , mappings , sizeof ( JanetFFIMapping ) * JANET_FFI_MAX_ARGS ) ;
return janet_wrap_abstract ( abst ) ;
}
2022-06-12 14:16:10 +00:00
# ifdef JANET_FFI_SYSV64_ENABLED
2022-06-11 19:47:35 +00:00
static void janet_ffi_sysv64_standard_callback ( void * ctx , void * userdata ) {
janet_ffi_trampoline ( ctx , userdata ) ;
}
2022-06-12 14:16:10 +00:00
/* Functions that set all argument registers. Two variants - one to read rax and rdx returns, another
* to read xmm0 and xmm1 returns . */
typedef struct {
uint64_t x ;
uint64_t y ;
} sysv64_int_return ;
typedef struct {
double x ;
double y ;
} sysv64_sse_return ;
2022-09-20 14:28:46 +00:00
typedef struct {
uint64_t x ;
double y ;
} sysv64_intsse_return ;
typedef struct {
double y ;
uint64_t x ;
} sysv64_sseint_return ;
2022-06-12 14:16:10 +00:00
typedef sysv64_int_return janet_sysv64_variant_1 ( uint64_t a , uint64_t b , uint64_t c , uint64_t d , uint64_t e , uint64_t f ,
2023-11-02 13:51:42 +00:00
double r1 , double r2 , double r3 , double r4 , double r5 , double r6 , double r7 , double r8 ) ;
2022-06-12 14:16:10 +00:00
typedef sysv64_sse_return janet_sysv64_variant_2 ( uint64_t a , uint64_t b , uint64_t c , uint64_t d , uint64_t e , uint64_t f ,
2023-11-02 13:51:42 +00:00
double r1 , double r2 , double r3 , double r4 , double r5 , double r6 , double r7 , double r8 ) ;
2022-09-20 14:28:46 +00:00
typedef sysv64_intsse_return janet_sysv64_variant_3 ( uint64_t a , uint64_t b , uint64_t c , uint64_t d , uint64_t e , uint64_t f ,
2023-11-02 13:51:42 +00:00
double r1 , double r2 , double r3 , double r4 , double r5 , double r6 , double r7 , double r8 ) ;
2022-09-20 14:28:46 +00:00
typedef sysv64_sseint_return janet_sysv64_variant_4 ( uint64_t a , uint64_t b , uint64_t c , uint64_t d , uint64_t e , uint64_t f ,
2023-11-02 13:51:42 +00:00
double r1 , double r2 , double r3 , double r4 , double r5 , double r6 , double r7 , double r8 ) ;
2022-06-12 14:16:10 +00:00
2022-06-08 14:41:09 +00:00
static Janet janet_ffi_sysv64 ( JanetFFISignature * signature , void * function_pointer , const Janet * argv ) {
2022-09-20 14:28:46 +00:00
union {
sysv64_int_return int_return ;
sysv64_sse_return sse_return ;
sysv64_sseint_return sseint_return ;
sysv64_intsse_return intsse_return ;
} retu ;
uint64_t pair [ 2 ] ;
2022-06-08 14:41:09 +00:00
uint64_t regs [ 6 ] ;
2022-06-12 14:16:10 +00:00
double fp_regs [ 8 ] ;
2022-06-10 17:24:50 +00:00
JanetFFIWordSpec ret_spec = signature - > ret . spec ;
2022-09-20 14:28:46 +00:00
void * ret_mem = & retu . int_return ;
2022-06-10 17:24:50 +00:00
if ( ret_spec = = JANET_SYSV64_MEMORY ) {
ret_mem = alloca ( type_size ( signature - > ret . type ) ) ;
regs [ 0 ] = ( uint64_t ) ret_mem ;
}
2022-06-08 14:41:09 +00:00
uint64_t * stack = alloca ( sizeof ( uint64_t ) * signature - > stack_count ) ;
2022-06-10 01:27:56 +00:00
for ( uint32_t i = 0 ; i < signature - > arg_count ; i + + ) {
uint64_t * to ;
int32_t n = i + 2 ;
JanetFFIMapping arg = signature - > args [ i ] ;
switch ( arg . spec ) {
default :
janet_panic ( " nyi " ) ;
case JANET_SYSV64_INTEGER :
to = regs + arg . offset ;
break ;
case JANET_SYSV64_SSE :
2022-06-12 14:16:10 +00:00
to = ( uint64_t * ) ( fp_regs + arg . offset ) ;
2022-06-10 01:27:56 +00:00
break ;
case JANET_SYSV64_MEMORY :
to = stack + arg . offset ;
break ;
2022-09-20 14:28:46 +00:00
case JANET_SYSV64_PAIR_INTINT :
janet_ffi_write_one ( pair , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
regs [ arg . offset ] = pair [ 0 ] ;
regs [ arg . offset2 ] = pair [ 1 ] ;
continue ;
case JANET_SYSV64_PAIR_INTSSE :
janet_ffi_write_one ( pair , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
regs [ arg . offset ] = pair [ 0 ] ;
( ( uint64_t * ) fp_regs ) [ arg . offset2 ] = pair [ 1 ] ;
continue ;
case JANET_SYSV64_PAIR_SSEINT :
janet_ffi_write_one ( pair , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
( ( uint64_t * ) fp_regs ) [ arg . offset ] = pair [ 0 ] ;
regs [ arg . offset2 ] = pair [ 1 ] ;
continue ;
case JANET_SYSV64_PAIR_SSESSE :
janet_ffi_write_one ( pair , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
( ( uint64_t * ) fp_regs ) [ arg . offset ] = pair [ 0 ] ;
( ( uint64_t * ) fp_regs ) [ arg . offset2 ] = pair [ 1 ] ;
continue ;
2022-06-10 01:27:56 +00:00
}
2022-06-10 17:24:50 +00:00
janet_ffi_write_one ( to , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
2022-06-08 14:41:09 +00:00
}
2022-09-20 14:28:46 +00:00
switch ( signature - > variant ) {
case 0 :
retu . int_return = ( ( janet_sysv64_variant_1 * ) ( function_pointer ) ) (
regs [ 0 ] , regs [ 1 ] , regs [ 2 ] , regs [ 3 ] , regs [ 4 ] , regs [ 5 ] ,
fp_regs [ 0 ] , fp_regs [ 1 ] , fp_regs [ 2 ] , fp_regs [ 3 ] ,
fp_regs [ 4 ] , fp_regs [ 5 ] , fp_regs [ 6 ] , fp_regs [ 7 ] ) ;
break ;
case 1 :
retu . sse_return = ( ( janet_sysv64_variant_2 * ) ( function_pointer ) ) (
regs [ 0 ] , regs [ 1 ] , regs [ 2 ] , regs [ 3 ] , regs [ 4 ] , regs [ 5 ] ,
fp_regs [ 0 ] , fp_regs [ 1 ] , fp_regs [ 2 ] , fp_regs [ 3 ] ,
fp_regs [ 4 ] , fp_regs [ 5 ] , fp_regs [ 6 ] , fp_regs [ 7 ] ) ;
break ;
case 2 :
retu . intsse_return = ( ( janet_sysv64_variant_3 * ) ( function_pointer ) ) (
regs [ 0 ] , regs [ 1 ] , regs [ 2 ] , regs [ 3 ] , regs [ 4 ] , regs [ 5 ] ,
fp_regs [ 0 ] , fp_regs [ 1 ] , fp_regs [ 2 ] , fp_regs [ 3 ] ,
fp_regs [ 4 ] , fp_regs [ 5 ] , fp_regs [ 6 ] , fp_regs [ 7 ] ) ;
break ;
case 3 :
retu . sseint_return = ( ( janet_sysv64_variant_4 * ) ( function_pointer ) ) (
regs [ 0 ] , regs [ 1 ] , regs [ 2 ] , regs [ 3 ] , regs [ 4 ] , regs [ 5 ] ,
fp_regs [ 0 ] , fp_regs [ 1 ] , fp_regs [ 2 ] , fp_regs [ 3 ] ,
fp_regs [ 4 ] , fp_regs [ 5 ] , fp_regs [ 6 ] , fp_regs [ 7 ] ) ;
break ;
2022-06-12 14:16:10 +00:00
}
2022-06-08 14:41:09 +00:00
2022-06-12 02:43:35 +00:00
return janet_ffi_read_one ( ret_mem , signature - > ret . type , JANET_FFI_MAX_RECUR ) ;
}
2022-06-12 14:16:10 +00:00
# endif
2022-06-12 02:50:34 +00:00
# ifdef JANET_FFI_WIN64_ENABLED
2022-06-12 02:43:35 +00:00
2022-06-12 14:16:10 +00:00
static void janet_ffi_win64_standard_callback ( void * ctx , void * userdata ) {
janet_ffi_trampoline ( ctx , userdata ) ;
}
2022-06-12 02:43:35 +00:00
/* Variants that allow setting all required registers for 64 bit windows calling convention.
* win64 calling convention has up to 4 arguments on registers , and one register for returns .
* Each register can either be an integer or floating point register , resulting in
* 2 ^ 5 = 32 variants . Unlike sysv , there are no function signatures that will fill
* all of the possible registers which is why we have so many variants . If you were using
* assembly , you could manually fill all of the registers and only have a single variant .
* And msvc does not support inline assembly on 64 bit targets , so yeah , we have this hackery . */
typedef uint64_t ( win64_variant_i_iiii ) ( uint64_t , uint64_t , uint64_t , uint64_t ) ;
typedef uint64_t ( win64_variant_i_iiif ) ( uint64_t , uint64_t , uint64_t , double ) ;
typedef uint64_t ( win64_variant_i_iifi ) ( uint64_t , uint64_t , double , uint64_t ) ;
typedef uint64_t ( win64_variant_i_iiff ) ( uint64_t , uint64_t , double , double ) ;
typedef uint64_t ( win64_variant_i_ifii ) ( uint64_t , double , uint64_t , uint64_t ) ;
typedef uint64_t ( win64_variant_i_ifif ) ( uint64_t , double , uint64_t , double ) ;
typedef uint64_t ( win64_variant_i_iffi ) ( uint64_t , double , double , uint64_t ) ;
typedef uint64_t ( win64_variant_i_ifff ) ( uint64_t , double , double , double ) ;
typedef uint64_t ( win64_variant_i_fiii ) ( double , uint64_t , uint64_t , uint64_t ) ;
typedef uint64_t ( win64_variant_i_fiif ) ( double , uint64_t , uint64_t , double ) ;
typedef uint64_t ( win64_variant_i_fifi ) ( double , uint64_t , double , uint64_t ) ;
typedef uint64_t ( win64_variant_i_fiff ) ( double , uint64_t , double , double ) ;
typedef uint64_t ( win64_variant_i_ffii ) ( double , double , uint64_t , uint64_t ) ;
typedef uint64_t ( win64_variant_i_ffif ) ( double , double , uint64_t , double ) ;
typedef uint64_t ( win64_variant_i_fffi ) ( double , double , double , uint64_t ) ;
typedef uint64_t ( win64_variant_i_ffff ) ( double , double , double , double ) ;
typedef double ( win64_variant_f_iiii ) ( uint64_t , uint64_t , uint64_t , uint64_t ) ;
typedef double ( win64_variant_f_iiif ) ( uint64_t , uint64_t , uint64_t , double ) ;
typedef double ( win64_variant_f_iifi ) ( uint64_t , uint64_t , double , uint64_t ) ;
typedef double ( win64_variant_f_iiff ) ( uint64_t , uint64_t , double , double ) ;
typedef double ( win64_variant_f_ifii ) ( uint64_t , double , uint64_t , uint64_t ) ;
typedef double ( win64_variant_f_ifif ) ( uint64_t , double , uint64_t , double ) ;
typedef double ( win64_variant_f_iffi ) ( uint64_t , double , double , uint64_t ) ;
typedef double ( win64_variant_f_ifff ) ( uint64_t , double , double , double ) ;
typedef double ( win64_variant_f_fiii ) ( double , uint64_t , uint64_t , uint64_t ) ;
typedef double ( win64_variant_f_fiif ) ( double , uint64_t , uint64_t , double ) ;
typedef double ( win64_variant_f_fifi ) ( double , uint64_t , double , uint64_t ) ;
typedef double ( win64_variant_f_fiff ) ( double , uint64_t , double , double ) ;
typedef double ( win64_variant_f_ffii ) ( double , double , uint64_t , uint64_t ) ;
typedef double ( win64_variant_f_ffif ) ( double , double , uint64_t , double ) ;
typedef double ( win64_variant_f_fffi ) ( double , double , double , uint64_t ) ;
typedef double ( win64_variant_f_ffff ) ( double , double , double , double ) ;
static Janet janet_ffi_win64 ( JanetFFISignature * signature , void * function_pointer , const Janet * argv ) {
union {
uint64_t integer ;
double real ;
} regs [ 4 ] ;
union {
uint64_t integer ;
double real ;
} ret_reg ;
JanetFFIWordSpec ret_spec = signature - > ret . spec ;
void * ret_mem = & ret_reg . integer ;
2022-08-14 20:20:30 +00:00
if ( ret_spec = = JANET_WIN64_REGISTER_REF ) {
2022-06-12 02:43:35 +00:00
ret_mem = alloca ( type_size ( signature - > ret . type ) ) ;
regs [ 0 ] . integer = ( uint64_t ) ret_mem ;
}
2022-09-20 20:36:03 +00:00
size_t stack_size = signature - > stack_count * 8 ;
2022-09-22 15:58:16 +00:00
size_t stack_shift = 2 ;
2022-09-20 20:36:03 +00:00
uint64_t * stack = alloca ( stack_size ) ;
2022-06-12 02:43:35 +00:00
for ( uint32_t i = 0 ; i < signature - > arg_count ; i + + ) {
int32_t n = i + 2 ;
JanetFFIMapping arg = signature - > args [ i ] ;
if ( arg . spec = = JANET_WIN64_STACK ) {
janet_ffi_write_one ( stack + arg . offset , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
2022-06-12 14:16:10 +00:00
} else if ( arg . spec = = JANET_WIN64_STACK_REF ) {
2022-08-14 18:26:13 +00:00
uint8_t * ptr = ( uint8_t * ) ( stack + arg . offset2 ) ;
2022-06-12 14:16:10 +00:00
janet_ffi_write_one ( ptr , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
2022-10-10 19:24:03 +00:00
stack [ arg . offset ] = ( uint64_t ) ( ptr - stack_shift * sizeof ( uint64_t ) ) ;
2022-06-12 14:16:10 +00:00
} else if ( arg . spec = = JANET_WIN64_REGISTER_REF ) {
2022-08-14 18:26:13 +00:00
uint8_t * ptr = ( uint8_t * ) ( stack + arg . offset2 ) ;
2022-06-12 14:16:10 +00:00
janet_ffi_write_one ( ptr , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
2022-10-10 19:24:03 +00:00
regs [ arg . offset ] . integer = ( uint64_t ) ( ptr - stack_shift * sizeof ( uint64_t ) ) ;
2022-06-12 02:43:35 +00:00
} else {
janet_ffi_write_one ( ( uint8_t * ) & regs [ arg . offset ] . integer , argv , n , arg . type , JANET_FFI_MAX_RECUR ) ;
}
}
2022-09-20 20:36:03 +00:00
/* hack to get proper stack placement and avoid clobbering from logic above - shift stack down, otherwise we have issues.
* Technically , this writes into 16 bytes of unallocated stack memory */
2023-01-21 17:50:03 +00:00
# ifdef JANET_MINGW
# pragma GCC diagnostic ignored "-Wstringop-overflow"
# endif
2022-09-22 15:58:16 +00:00
if ( stack_size ) memmove ( stack - stack_shift , stack , stack_size ) ;
2023-01-21 17:50:03 +00:00
# ifdef JANET_MINGW
# pragma GCC diagnostic pop
# endif
2022-09-20 20:36:03 +00:00
2022-06-08 14:41:09 +00:00
switch ( signature - > variant ) {
default :
2022-08-14 18:26:13 +00:00
janet_panicf ( " unknown variant %d " , signature - > variant ) ;
2022-06-08 14:41:09 +00:00
case 0 :
2022-06-12 02:43:35 +00:00
ret_reg . integer = ( ( win64_variant_i_iiii * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
2022-06-10 01:27:56 +00:00
break ;
2022-06-08 14:41:09 +00:00
case 1 :
2022-06-12 02:43:35 +00:00
ret_reg . integer = ( ( win64_variant_i_iiif * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 2 :
ret_reg . integer = ( ( win64_variant_i_iifi * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 3 :
ret_reg . integer = ( ( win64_variant_i_iiff * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . real ) ;
break ;
case 4 :
ret_reg . integer = ( ( win64_variant_i_ifii * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
break ;
case 5 :
ret_reg . integer = ( ( win64_variant_i_ifif * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 6 :
ret_reg . integer = ( ( win64_variant_i_iffi * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 7 :
ret_reg . integer = ( ( win64_variant_i_ifff * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . real ) ;
break ;
case 8 :
ret_reg . integer = ( ( win64_variant_i_fiii * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
break ;
case 9 :
ret_reg . integer = ( ( win64_variant_i_fiif * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 10 :
ret_reg . integer = ( ( win64_variant_i_fifi * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 11 :
ret_reg . integer = ( ( win64_variant_i_fiff * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . real ) ;
break ;
case 12 :
ret_reg . integer = ( ( win64_variant_i_ffii * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
break ;
case 13 :
ret_reg . integer = ( ( win64_variant_i_ffif * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 14 :
ret_reg . integer = ( ( win64_variant_i_fffi * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 15 :
ret_reg . integer = ( ( win64_variant_i_ffff * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . real ) ;
break ;
case 16 :
ret_reg . real = ( ( win64_variant_f_iiii * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
break ;
case 17 :
ret_reg . real = ( ( win64_variant_f_iiif * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 18 :
ret_reg . real = ( ( win64_variant_f_iifi * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 19 :
ret_reg . real = ( ( win64_variant_f_iiff * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . real ) ;
break ;
case 20 :
ret_reg . real = ( ( win64_variant_f_ifii * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
break ;
case 21 :
ret_reg . real = ( ( win64_variant_f_ifif * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 22 :
ret_reg . real = ( ( win64_variant_f_iffi * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 23 :
ret_reg . real = ( ( win64_variant_f_ifff * ) function_pointer ) ( regs [ 0 ] . integer , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . real ) ;
break ;
case 24 :
ret_reg . real = ( ( win64_variant_f_fiii * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
break ;
case 25 :
ret_reg . real = ( ( win64_variant_f_fiif * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 26 :
ret_reg . real = ( ( win64_variant_f_fifi * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 27 :
ret_reg . real = ( ( win64_variant_f_fiff * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . integer , regs [ 2 ] . real , regs [ 3 ] . real ) ;
break ;
case 28 :
ret_reg . real = ( ( win64_variant_f_ffii * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . integer ) ;
break ;
case 29 :
ret_reg . real = ( ( win64_variant_f_ffif * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . integer , regs [ 3 ] . real ) ;
break ;
case 30 :
ret_reg . real = ( ( win64_variant_f_fffi * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . integer ) ;
break ;
case 31 :
ret_reg . real = ( ( win64_variant_f_ffff * ) function_pointer ) ( regs [ 0 ] . real , regs [ 1 ] . real , regs [ 2 ] . real , regs [ 3 ] . real ) ;
2022-06-10 01:27:56 +00:00
break ;
2022-06-08 14:41:09 +00:00
}
2022-06-10 17:24:50 +00:00
return janet_ffi_read_one ( ret_mem , signature - > ret . type , JANET_FFI_MAX_RECUR ) ;
2022-06-06 23:54:17 +00:00
}
2022-06-12 02:43:35 +00:00
# endif
2022-12-03 23:52:23 +00:00
/* Allocate executable memory chunks in sizes of a page. Ideally we would keep
* an allocator around so that multiple JIT allocations would point to the same
* region but it isn ' t really worth it . */
# define FFI_PAGE_MASK 0xFFF
2022-12-03 17:26:23 +00:00
JANET_CORE_FN ( cfun_ffi_jitfn ,
" (ffi/jitfn bytes) " ,
" Create an abstract type that can be used as the pointer argument to `ffi/call`. The content "
" of `bytes` is architecture specific machine code that will be copied into executable memory. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_JIT ) ;
2022-12-03 17:26:23 +00:00
janet_fixarity ( argc , 1 ) ;
JanetByteView bytes = janet_getbytes ( argv , 0 ) ;
2022-12-03 23:52:23 +00:00
/* Quick hack to align to page boundary, we should query OS. FIXME */
size_t alloc_size = ( ( size_t ) bytes . len + FFI_PAGE_MASK ) & ~ FFI_PAGE_MASK ;
2022-12-03 17:26:23 +00:00
# ifdef JANET_FFI_JIT
2023-02-12 18:14:11 +00:00
# ifdef JANET_EV
2022-12-03 17:26:23 +00:00
JanetFFIJittedFn * fn = janet_abstract_threaded ( & janet_type_ffijit , sizeof ( JanetFFIJittedFn ) ) ;
2023-02-12 18:14:11 +00:00
# else
JanetFFIJittedFn * fn = janet_abstract ( & janet_type_ffijit , sizeof ( JanetFFIJittedFn ) ) ;
# endif
2022-12-03 17:26:23 +00:00
fn - > function_pointer = NULL ;
fn - > size = 0 ;
# ifdef JANET_WINDOWS
2022-12-03 23:52:23 +00:00
void * ptr = VirtualAlloc ( NULL , alloc_size , MEM_COMMIT | MEM_RESERVE , PAGE_READWRITE ) ;
2022-12-03 17:31:04 +00:00
# elif defined(MAP_ANONYMOUS)
2022-12-03 23:52:23 +00:00
void * ptr = mmap ( 0 , alloc_size , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2022-12-03 17:45:33 +00:00
# elif defined(MAP_ANON)
2022-12-03 17:31:04 +00:00
/* macos doesn't have MAP_ANONYMOUS */
2022-12-03 23:52:23 +00:00
void * ptr = mmap ( 0 , alloc_size , PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANON , - 1 , 0 ) ;
2022-12-03 17:45:33 +00:00
# else
/* -std=c99 gets in the way */
2022-12-03 18:10:22 +00:00
/* #define MAP_ANONYMOUS 0x20 should work, though. */
2022-12-03 23:52:23 +00:00
void * ptr = mmap ( 0 , alloc_size , PROT_READ | PROT_WRITE , MAP_PRIVATE , - 1 , 0 ) ;
2022-12-03 17:26:23 +00:00
# endif
if ( ! ptr ) {
janet_panic ( " failed to memory map writable memory " ) ;
}
memcpy ( ptr , bytes . bytes , bytes . len ) ;
# ifdef JANET_WINDOWS
DWORD old = 0 ;
2022-12-03 23:52:23 +00:00
if ( ! VirtualProtect ( ptr , alloc_size , PAGE_EXECUTE_READ , & old ) ) {
2022-12-03 17:26:23 +00:00
janet_panic ( " failed to make mapped memory executable " ) ;
}
# else
2022-12-03 23:52:23 +00:00
if ( mprotect ( ptr , alloc_size , PROT_READ | PROT_EXEC ) = = - 1 ) {
2022-12-03 17:26:23 +00:00
janet_panic ( " failed to make mapped memory executable " ) ;
}
# endif
2022-12-03 23:52:23 +00:00
fn - > size = alloc_size ;
fn - > function_pointer = ptr ;
2022-12-03 17:26:23 +00:00
return janet_wrap_abstract ( fn ) ;
# else
janet_panic ( " ffi/jitfn not available on this platform " ) ;
# endif
}
2022-06-08 14:41:09 +00:00
JANET_CORE_FN ( cfun_ffi_call ,
2022-06-12 15:02:02 +00:00
" (ffi/call pointer signature & args) " ,
2022-06-08 14:50:31 +00:00
" Call a raw pointer as a function pointer. The function signature specifies "
" how Janet values in `args` are converted to native machine types. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_USE ) ;
2022-06-08 14:41:09 +00:00
janet_arity ( argc , 2 , - 1 ) ;
2022-12-03 17:26:23 +00:00
void * function_pointer = janet_ffi_get_callable_pointer ( argv , 0 ) ;
2022-06-08 14:41:09 +00:00
JanetFFISignature * signature = janet_getabstract ( argv , 1 , & janet_signature_type ) ;
janet_fixarity ( argc - 2 , signature - > arg_count ) ;
switch ( signature - > cc ) {
default :
2022-06-12 15:12:45 +00:00
case JANET_FFI_CC_NONE :
2023-06-08 14:06:34 +00:00
( void ) function_pointer ;
2022-06-12 15:12:45 +00:00
janet_panic ( " calling convention not supported " ) ;
2022-06-12 02:43:35 +00:00
# ifdef JANET_FFI_WIN64_ENABLED
case JANET_FFI_CC_WIN_64 :
return janet_ffi_win64 ( signature , function_pointer , argv ) ;
# endif
2022-06-12 14:16:10 +00:00
# ifdef JANET_FFI_SYSV64_ENABLED
2022-06-08 14:41:09 +00:00
case JANET_FFI_CC_SYSV_64 :
return janet_ffi_sysv64 ( signature , function_pointer , argv ) ;
2022-06-12 14:16:10 +00:00
# endif
2022-06-08 14:41:09 +00:00
}
}
2022-06-10 13:46:20 +00:00
JANET_CORE_FN ( cfun_ffi_buffer_write ,
2023-02-12 18:08:28 +00:00
" (ffi/write ffi-type data &opt buffer index) " ,
2023-02-12 17:19:09 +00:00
" Append a native type to a buffer such as it would appear in memory. This can be used "
2022-06-10 13:46:20 +00:00
" to pass pointers to structs in the ffi, or send C/C++/native structs over the network "
2023-10-04 01:54:40 +00:00
" or to files. Returns a modified buffer or a new buffer if one is not supplied. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_USE ) ;
2023-02-12 18:08:28 +00:00
janet_arity ( argc , 2 , 4 ) ;
2022-06-10 13:46:20 +00:00
JanetFFIType type = decode_ffi_type ( argv [ 0 ] ) ;
2022-08-14 18:26:13 +00:00
uint32_t el_size = ( uint32_t ) type_size ( type ) ;
2022-06-10 13:46:20 +00:00
JanetBuffer * buffer = janet_optbuffer ( argv , argc , 2 , el_size ) ;
2023-02-12 18:08:28 +00:00
int32_t index = janet_optnat ( argv , argc , 3 , 0 ) ;
int32_t old_count = buffer - > count ;
if ( index > old_count ) janet_panic ( " index out of bounds " ) ;
buffer - > count = index ;
2022-06-10 13:46:20 +00:00
janet_buffer_extra ( buffer , el_size ) ;
2023-02-12 18:08:28 +00:00
buffer - > count = old_count ;
memset ( buffer - > data + index , 0 , el_size ) ;
janet_ffi_write_one ( buffer - > data + index , argv , 1 , type , JANET_FFI_MAX_RECUR ) ;
index + = el_size ;
if ( buffer - > count < index ) buffer - > count = index ;
2022-06-10 13:46:20 +00:00
return janet_wrap_buffer ( buffer ) ;
}
2022-06-10 14:38:52 +00:00
JANET_CORE_FN ( cfun_ffi_buffer_read ,
2022-06-12 15:02:02 +00:00
" (ffi/read ffi-type bytes &opt offset) " ,
2022-06-10 14:38:52 +00:00
" Parse a native struct out of a buffer and convert it to normal Janet data structures. "
2022-06-12 15:02:02 +00:00
" This function is the inverse of `ffi/write`. `bytes` can also be a raw pointer, although "
2022-06-11 19:47:35 +00:00
" this is unsafe. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_USE ) ;
2022-06-10 14:38:52 +00:00
janet_arity ( argc , 2 , 3 ) ;
JanetFFIType type = decode_ffi_type ( argv [ 0 ] ) ;
size_t offset = ( size_t ) janet_optnat ( argv , argc , 2 , 0 ) ;
2022-06-11 19:47:35 +00:00
if ( janet_checktype ( argv [ 1 ] , JANET_POINTER ) ) {
uint8_t * ptr = janet_unwrap_pointer ( argv [ 1 ] ) ;
return janet_ffi_read_one ( ptr + offset , type , JANET_FFI_MAX_RECUR ) ;
} else {
size_t el_size = type_size ( type ) ;
JanetByteView bytes = janet_getbytes ( argv , 1 ) ;
if ( ( size_t ) bytes . len < offset + el_size ) janet_panic ( " read out of range " ) ;
return janet_ffi_read_one ( bytes . bytes + offset , type , JANET_FFI_MAX_RECUR ) ;
}
}
JANET_CORE_FN ( cfun_ffi_get_callback_trampoline ,
2022-06-12 15:02:02 +00:00
" (ffi/trampoline cc) " ,
2022-06-11 19:47:35 +00:00
" Get a native function pointer that can be used as a callback and passed to C libraries. "
2022-06-19 23:52:37 +00:00
" This callback trampoline has the signature `void trampoline(void \\ *ctx, void \\ *userdata)` in "
2022-06-11 19:47:35 +00:00
" the given calling convention. This is the only function signature supported. "
" It is up to the programmer to ensure that the `userdata` argument contains a janet function "
" the will be called with one argument, `ctx` which is an opaque pointer. This pointer can "
2022-06-12 15:02:02 +00:00
" be further inspected with `ffi/read`. " ) {
2022-06-11 20:47:51 +00:00
janet_arity ( argc , 0 , 1 ) ;
JanetFFICallingConvention cc = JANET_FFI_CC_DEFAULT ;
if ( argc > = 1 ) cc = decode_ffi_cc ( janet_getkeyword ( argv , 0 ) ) ;
2022-06-11 19:47:35 +00:00
switch ( cc ) {
default :
2022-06-12 15:12:45 +00:00
case JANET_FFI_CC_NONE :
janet_panic ( " calling convention not supported " ) ;
2022-06-12 14:16:10 +00:00
# ifdef JANET_FFI_WIN64_ENABLED
case JANET_FFI_CC_WIN_64 :
return janet_wrap_pointer ( janet_ffi_win64_standard_callback ) ;
# endif
# ifdef JANET_FFI_SYSV64_ENABLED
2022-06-11 19:47:35 +00:00
case JANET_FFI_CC_SYSV_64 :
return janet_wrap_pointer ( janet_ffi_sysv64_standard_callback ) ;
2022-06-12 14:16:10 +00:00
# endif
2022-06-11 19:47:35 +00:00
}
2022-06-10 14:38:52 +00:00
}
2022-06-12 15:02:02 +00:00
JANET_CORE_FN ( janet_core_raw_native ,
2022-06-18 14:46:28 +00:00
" (ffi/native &opt path) " ,
2022-06-12 15:02:02 +00:00
" Load a shared object or dll from the given path, and do not extract "
" or run any code from it. This is different than `native`, which will "
2022-06-18 14:46:28 +00:00
" run initialization code to get a module table. If `path` is nil, opens the current running binary. "
" Returns a `core/native`. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_DEFINE ) ;
2022-06-18 14:46:28 +00:00
janet_arity ( argc , 0 , 1 ) ;
const char * path = janet_optcstring ( argv , argc , 0 , NULL ) ;
2022-07-20 01:04:17 +00:00
Clib lib = load_clib ( path ) ;
2022-06-12 15:02:02 +00:00
if ( ! lib ) janet_panic ( error_clib ( ) ) ;
JanetAbstractNative * anative = janet_abstract ( & janet_native_type , sizeof ( JanetAbstractNative ) ) ;
anative - > clib = lib ;
anative - > closed = 0 ;
2022-06-18 15:31:00 +00:00
anative - > is_self = path = = NULL ;
2022-06-12 15:02:02 +00:00
return janet_wrap_abstract ( anative ) ;
}
JANET_CORE_FN ( janet_core_native_lookup ,
" (ffi/lookup native symbol-name) " ,
" Lookup a symbol from a native object. All symbol lookups will return a raw pointer "
" if the symbol is found, else nil. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_DEFINE ) ;
2022-06-12 15:02:02 +00:00
janet_fixarity ( argc , 2 ) ;
JanetAbstractNative * anative = janet_getabstract ( argv , 0 , & janet_native_type ) ;
const char * sym = janet_getcstring ( argv , 1 ) ;
if ( anative - > closed ) janet_panic ( " native object already closed " ) ;
void * value = symbol_clib ( anative - > clib , sym ) ;
if ( NULL = = value ) return janet_wrap_nil ( ) ;
return janet_wrap_pointer ( value ) ;
}
JANET_CORE_FN ( janet_core_native_close ,
" (ffi/close native) " ,
" Free a native object. Dereferencing pointers to symbols in the object will have undefined "
" behavior after freeing. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_DEFINE ) ;
2022-06-12 15:02:02 +00:00
janet_fixarity ( argc , 1 ) ;
JanetAbstractNative * anative = janet_getabstract ( argv , 0 , & janet_native_type ) ;
if ( anative - > closed ) janet_panic ( " native object already closed " ) ;
2022-06-18 15:31:00 +00:00
if ( anative - > is_self ) janet_panic ( " cannot close self " ) ;
2022-06-12 15:02:02 +00:00
anative - > closed = 1 ;
free_clib ( anative - > clib ) ;
return janet_wrap_nil ( ) ;
}
2022-12-16 03:35:44 +00:00
JANET_CORE_FN ( cfun_ffi_malloc ,
" (ffi/malloc size) " ,
2023-02-12 15:03:31 +00:00
" Allocates memory directly using the janet memory allocator. Memory allocated in this way must be freed manually! Returns a raw pointer, or nil if size = 0. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_USE ) ;
2022-12-16 03:35:44 +00:00
janet_fixarity ( argc , 1 ) ;
size_t size = janet_getsize ( argv , 0 ) ;
if ( size = = 0 ) return janet_wrap_nil ( ) ;
2023-02-12 15:03:31 +00:00
return janet_wrap_pointer ( janet_malloc ( size ) ) ;
2022-12-16 03:35:44 +00:00
}
JANET_CORE_FN ( cfun_ffi_free ,
" (ffi/free pointer) " ,
2023-02-12 15:03:31 +00:00
" Free memory allocated with `ffi/malloc`. Returns nil. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_USE ) ;
2022-12-16 03:35:44 +00:00
janet_fixarity ( argc , 1 ) ;
if ( janet_checktype ( argv [ 0 ] , JANET_NIL ) ) return janet_wrap_nil ( ) ;
void * pointer = janet_getpointer ( argv , 0 ) ;
2023-02-12 15:03:31 +00:00
janet_free ( pointer ) ;
2022-12-16 03:35:44 +00:00
return janet_wrap_nil ( ) ;
}
2023-02-12 15:03:31 +00:00
JANET_CORE_FN ( cfun_ffi_pointer_buffer ,
" (ffi/pointer-buffer pointer capacity &opt count offset) " ,
" Create a buffer from a pointer. The underlying memory of the buffer will not be "
" reallocated or freed by the garbage collector, allowing unmanaged, mutable memory "
" to be manipulated with buffer functions. Attempts to resize or extend the buffer "
2023-03-04 00:24:02 +00:00
" beyond its initial capacity will raise an error. As with many FFI functions, this is memory "
2023-02-12 15:03:31 +00:00
" unsafe and can potentially allow out of bounds memory access. Returns a new buffer. " ) {
2023-06-04 23:48:34 +00:00
janet_sandbox_assert ( JANET_SANDBOX_FFI_USE ) ;
2023-02-12 15:03:31 +00:00
janet_arity ( argc , 2 , 4 ) ;
void * pointer = janet_getpointer ( argv , 0 ) ;
int32_t capacity = janet_getnat ( argv , 1 ) ;
int32_t count = janet_optnat ( argv , argc , 2 , 0 ) ;
int64_t offset = janet_optinteger64 ( argv , argc , 3 , 0 ) ;
2023-02-12 17:07:45 +00:00
uint8_t * offset_pointer = ( ( uint8_t * ) pointer ) + offset ;
return janet_wrap_buffer ( janet_pointer_buffer_unsafe ( offset_pointer , capacity , count ) ) ;
2023-02-12 15:03:31 +00:00
}
2023-06-28 00:47:19 +00:00
JANET_CORE_FN ( cfun_ffi_pointer_cfunction ,
" (ffi/pointer-cfunction pointer &opt name source-file source-line) " ,
" Create a C Function from a raw pointer. Optionally give the cfunction a name and "
" source location for stack traces and debugging. " ) {
janet_sandbox_assert ( JANET_SANDBOX_FFI_USE ) ;
janet_arity ( argc , 1 , 4 ) ;
void * pointer = janet_getpointer ( argv , 0 ) ;
const char * name = janet_optcstring ( argv , argc , 1 , NULL ) ;
const char * source = janet_optcstring ( argv , argc , 2 , NULL ) ;
int32_t line = janet_optinteger ( argv , argc , 3 , - 1 ) ;
if ( ( name ! = NULL ) | | ( source ! = NULL ) | | ( line ! = - 1 ) ) {
janet_registry_put ( ( JanetCFunction ) pointer , name , NULL , source , line ) ;
}
return janet_wrap_cfunction ( ( JanetCFunction ) pointer ) ;
}
2023-06-08 14:06:34 +00:00
JANET_CORE_FN ( cfun_ffi_supported_calling_conventions ,
2023-06-08 18:01:49 +00:00
" (ffi/calling-conventions) " ,
2023-10-04 01:54:40 +00:00
" Get an array of all supported calling conventions on the current architecture. Some architectures may have some FFI "
2023-06-08 18:01:49 +00:00
" functionality (ffi/malloc, ffi/free, ffi/read, ffi/write, etc.) but not support "
" any calling conventions. This function can be used to get all supported calling conventions "
" that can be used on this architecture. All architectures support the :none calling "
" convention which is a placeholder that cannot be used at runtime. " ) {
2023-06-08 14:06:34 +00:00
janet_fixarity ( argc , 0 ) ;
( void ) argv ;
JanetArray * array = janet_array ( 4 ) ;
# ifdef JANET_FFI_WIN64_ENABLED
janet_array_push ( array , janet_ckeywordv ( " win64 " ) ) ;
# endif
# ifdef JANET_FFI_SYSV64_ENABLED
janet_array_push ( array , janet_ckeywordv ( " sysv64 " ) ) ;
# endif
janet_array_push ( array , janet_ckeywordv ( " none " ) ) ;
return janet_wrap_array ( array ) ;
}
2022-06-06 23:54:17 +00:00
void janet_lib_ffi ( JanetTable * env ) {
JanetRegExt ffi_cfuns [ ] = {
2022-06-12 15:02:02 +00:00
JANET_CORE_REG ( " ffi/native " , janet_core_raw_native ) ,
JANET_CORE_REG ( " ffi/lookup " , janet_core_native_lookup ) ,
JANET_CORE_REG ( " ffi/close " , janet_core_native_close ) ,
JANET_CORE_REG ( " ffi/signature " , cfun_ffi_signature ) ,
JANET_CORE_REG ( " ffi/call " , cfun_ffi_call ) ,
JANET_CORE_REG ( " ffi/struct " , cfun_ffi_struct ) ,
JANET_CORE_REG ( " ffi/write " , cfun_ffi_buffer_write ) ,
JANET_CORE_REG ( " ffi/read " , cfun_ffi_buffer_read ) ,
2022-06-19 13:03:07 +00:00
JANET_CORE_REG ( " ffi/size " , cfun_ffi_size ) ,
JANET_CORE_REG ( " ffi/align " , cfun_ffi_align ) ,
2022-06-12 15:02:02 +00:00
JANET_CORE_REG ( " ffi/trampoline " , cfun_ffi_get_callback_trampoline ) ,
2022-12-03 17:26:23 +00:00
JANET_CORE_REG ( " ffi/jitfn " , cfun_ffi_jitfn ) ,
2022-12-16 03:35:44 +00:00
JANET_CORE_REG ( " ffi/malloc " , cfun_ffi_malloc ) ,
JANET_CORE_REG ( " ffi/free " , cfun_ffi_free ) ,
2023-02-12 15:03:31 +00:00
JANET_CORE_REG ( " ffi/pointer-buffer " , cfun_ffi_pointer_buffer ) ,
2023-06-28 00:47:19 +00:00
JANET_CORE_REG ( " ffi/pointer-cfunction " , cfun_ffi_pointer_cfunction ) ,
2023-06-08 14:06:34 +00:00
JANET_CORE_REG ( " ffi/calling-conventions " , cfun_ffi_supported_calling_conventions ) ,
2022-06-06 23:54:17 +00:00
JANET_REG_END
} ;
janet_core_cfuns_ext ( env , NULL , ffi_cfuns ) ;
}
# endif