1248 lines
30 KiB
C
1248 lines
30 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
Copyright (c) 2014-2019 Chung, Hyung-Hwan. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "_ffi.h"
|
|
#include <moo-utl.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#if defined(HAVE_FFI_LIB) && defined(HAVE_FFI_H)
|
|
# define USE_LIBFFI
|
|
#elif defined(HAVE_DYNCALL_LIB) && defined(HAVE_DYNCALL_H)
|
|
# define USE_DYNCALL
|
|
#endif
|
|
|
|
#if defined(USE_LIBFFI)
|
|
# include <ffi.h>
|
|
# if (MOO_SIZEOF_LONG_LONG > 0) && !defined(ffi_type_ulonglong)
|
|
# if MOO_SIZEOF_LONG_LONG == MOO_SIZEOF_INT32_T
|
|
# define ffi_type_ulonglong ffi_type_uint32
|
|
# define ffi_type_slonglong ffi_type_sint32
|
|
# elif MOO_SIZEOF_LONG_LONG == MOO_SIZEOF_INT64_T
|
|
# define ffi_type_ulonglong ffi_type_uint64
|
|
# define ffi_type_slonglong ffi_type_sint64
|
|
# endif
|
|
# endif
|
|
#elif defined(USE_DYNCALL)
|
|
# include <dyncall.h>
|
|
|
|
#define __dcArgInt8 dcArgChar
|
|
#define __dcCallInt8 dcCallChar
|
|
|
|
#define __dcArgInt16 dcArgShort
|
|
#define __dcCallInt16 dcCallShort
|
|
|
|
#if (MOO_SIZEOF_INT32_T == MOO_SIZEOF_INT)
|
|
#define __dcArgInt32 dcArgInt
|
|
#define __dcCallInt32 dcCallInt
|
|
#elif (MOO_SIZEOF_INT32_T == MOO_SIZEOF_LONG)
|
|
#define __dcArgInt32 dcArgLong
|
|
#define __dcCallInt32 dcCallLong
|
|
#endif
|
|
|
|
#if (MOO_SIZEOF_INT64_T == MOO_SIZEOF_LONG)
|
|
#define __dcArgInt64 dcArgLong
|
|
#define __dcCallInt64 dcCallLong
|
|
#elif (MOO_SIZEOF_INT64_T == MOO_SIZEOF_LONG_LONG)
|
|
#define __dcArgInt64 dcArgLongLong
|
|
#define __dcCallInt64 dcCallLongLong
|
|
#endif
|
|
|
|
|
|
#endif
|
|
|
|
#define FMTC_NULL '\0' /* internal use only */
|
|
|
|
#define FMTC_CHAR 'c'
|
|
#define FMTC_SHORT 'h'
|
|
#define FMTC_INT 'i'
|
|
#define FMTC_LONG 'l'
|
|
#define FMTC_LONGLONG 'L'
|
|
#define FMTC_BCS 's'
|
|
#define FMTC_UCS 'S'
|
|
#define FMTC_BLOB 'b'
|
|
#define FMTC_POINTER 'p'
|
|
|
|
#define FMTC_INT8 '1'
|
|
#define FMTC_INT16 '2'
|
|
#define FMTC_INT32 '4'
|
|
#define FMTC_INT64 '8'
|
|
|
|
typedef struct link_t link_t;
|
|
struct link_t
|
|
{
|
|
link_t* next;
|
|
};
|
|
|
|
#if defined(USE_LIBFFI)
|
|
typedef union ffi_sv_t ffi_sv_t;
|
|
union ffi_sv_t
|
|
{
|
|
void* p;
|
|
unsigned char uc;
|
|
char c;
|
|
unsigned short int uh;
|
|
short h;
|
|
unsigned int ui;
|
|
int i;
|
|
unsigned long int ul;
|
|
long int l;
|
|
#if (MOO_SIZEOF_LONG_LONG > 0)
|
|
unsigned long long int ull;
|
|
long long int ll;
|
|
#endif
|
|
|
|
|
|
moo_uint8_t ui8;
|
|
moo_int8_t i8;
|
|
moo_uint16_t ui16;
|
|
moo_int16_t i16;
|
|
moo_uint32_t ui32;
|
|
moo_int32_t i32;
|
|
#if (MOO_SIZEOF_INT64_T > 0)
|
|
moo_uint64_t ui64;
|
|
moo_int64_t i64;
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
typedef struct ffi_t ffi_t;
|
|
struct ffi_t
|
|
{
|
|
void* handle;
|
|
|
|
#if defined(USE_DYNCALL)
|
|
DCCallVM* dc;
|
|
#elif defined(USE_LIBFFI)
|
|
moo_oow_t arg_count;
|
|
moo_oow_t arg_max;
|
|
ffi_type** arg_types;
|
|
void** arg_values;
|
|
ffi_sv_t* arg_svs;
|
|
|
|
ffi_sv_t ret_sv;
|
|
ffi_cif cif;
|
|
ffi_type* fmtc_to_type[2][128];
|
|
#endif
|
|
|
|
link_t* ca; /* call arguments duplicated */
|
|
};
|
|
|
|
|
|
static MOO_INLINE void link_ca (ffi_t* ffi, void* ptr)
|
|
{
|
|
link_t* l = (link_t*)((moo_oob_t*)ptr - MOO_SIZEOF_VOID_P);
|
|
l->next = ffi->ca;
|
|
ffi->ca = l;
|
|
}
|
|
|
|
static void free_linked_cas (moo_t* moo, ffi_t* ffi)
|
|
{
|
|
while (ffi->ca)
|
|
{
|
|
link_t* ptr;
|
|
ptr = ffi->ca;
|
|
ffi->ca = ptr->next;
|
|
moo_freemem (moo, ptr);
|
|
}
|
|
}
|
|
|
|
static moo_pfrc_t pf_open (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
|
|
{
|
|
ffi_t* ffi;
|
|
moo_oop_t name;
|
|
void* handle;
|
|
#if defined(USE_DYNCALL)
|
|
DCCallVM* dc;
|
|
#endif
|
|
|
|
MOO_ASSERT (moo, nargs == 1);
|
|
|
|
ffi = (ffi_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL);
|
|
name = MOO_STACK_GETARG(moo, nargs, 0);
|
|
|
|
if (!MOO_OBJ_IS_CHAR_POINTER(name))
|
|
{
|
|
moo_seterrnum (moo, MOO_EINVAL);
|
|
goto softfail;
|
|
}
|
|
|
|
if (!moo->vmprim.dl_open)
|
|
{
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
goto softfail;
|
|
}
|
|
|
|
if (ffi->handle)
|
|
{
|
|
moo_seterrnum (moo, MOO_EPERM); /* no allowed to open again */
|
|
goto softfail;
|
|
}
|
|
|
|
handle = moo->vmprim.dl_open(moo, MOO_OBJ_GET_CHAR_SLOT(name), 0);
|
|
if (!handle) goto softfail;
|
|
|
|
#if defined(USE_DYNCALL)
|
|
dc = dcNewCallVM(4096); /* TODO: right size? */
|
|
if (!dc)
|
|
{
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
moo->vmprim.dl_close (moo, handle);
|
|
goto softfail;
|
|
}
|
|
#endif
|
|
|
|
ffi->handle = handle;
|
|
|
|
#if defined(USE_DYNCALL)
|
|
ffi->dc = dc;
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->fmtc_to_type[0][FMTC_NULL] = &ffi_type_void;
|
|
ffi->fmtc_to_type[1][FMTC_NULL] = &ffi_type_void;
|
|
|
|
ffi->fmtc_to_type[0][FMTC_CHAR] = &ffi_type_schar;
|
|
ffi->fmtc_to_type[1][FMTC_CHAR] = &ffi_type_uchar;
|
|
ffi->fmtc_to_type[0][FMTC_SHORT] = &ffi_type_sshort;
|
|
ffi->fmtc_to_type[1][FMTC_SHORT] = &ffi_type_ushort;
|
|
ffi->fmtc_to_type[0][FMTC_INT] = &ffi_type_sint;
|
|
ffi->fmtc_to_type[1][FMTC_INT] = &ffi_type_uint;
|
|
ffi->fmtc_to_type[0][FMTC_LONG] = &ffi_type_slong;
|
|
ffi->fmtc_to_type[1][FMTC_LONG] = &ffi_type_ulong;
|
|
#if (MOO_SIZEOF_LONG_LONG > 0)
|
|
ffi->fmtc_to_type[0][FMTC_LONGLONG] = &ffi_type_slonglong;
|
|
ffi->fmtc_to_type[1][FMTC_LONGLONG] = &ffi_type_ulonglong;
|
|
#endif
|
|
ffi->fmtc_to_type[0][FMTC_INT8] = &ffi_type_sint8;
|
|
ffi->fmtc_to_type[1][FMTC_INT8] = &ffi_type_uint8;
|
|
ffi->fmtc_to_type[0][FMTC_INT16] = &ffi_type_sint16;
|
|
ffi->fmtc_to_type[1][FMTC_INT16] = &ffi_type_uint16;
|
|
ffi->fmtc_to_type[0][FMTC_INT32] = &ffi_type_sint32;
|
|
ffi->fmtc_to_type[1][FMTC_INT32] = &ffi_type_uint32;
|
|
ffi->fmtc_to_type[0][FMTC_INT64] = &ffi_type_sint64;
|
|
ffi->fmtc_to_type[1][FMTC_INT64] = &ffi_type_uint64;
|
|
|
|
ffi->fmtc_to_type[0][FMTC_POINTER] = &ffi_type_pointer;
|
|
ffi->fmtc_to_type[1][FMTC_POINTER] = &ffi_type_pointer;
|
|
ffi->fmtc_to_type[0][FMTC_BCS] = &ffi_type_pointer;
|
|
ffi->fmtc_to_type[1][FMTC_BCS] = &ffi_type_pointer;
|
|
ffi->fmtc_to_type[0][FMTC_UCS] = &ffi_type_pointer;
|
|
ffi->fmtc_to_type[1][FMTC_UCS] = &ffi_type_pointer;
|
|
#endif
|
|
|
|
MOO_DEBUG3 (moo, "<ffi.open> %.*js => %p\n", MOO_OBJ_GET_SIZE(name), MOO_OBJ_GET_CHAR_SLOT(name), ffi->handle);
|
|
MOO_STACK_SETRETTORCV (moo, nargs);
|
|
return MOO_PF_SUCCESS;
|
|
|
|
softfail:
|
|
MOO_STACK_SETRETTOERRNUM (moo, nargs);
|
|
return MOO_PF_SUCCESS;
|
|
}
|
|
|
|
static moo_pfrc_t pf_close (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
|
|
{
|
|
ffi_t* ffi;
|
|
|
|
MOO_ASSERT (moo, nargs == 0);
|
|
|
|
ffi = (ffi_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL);
|
|
|
|
if (!moo->vmprim.dl_open)
|
|
{
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
goto softfail;
|
|
}
|
|
|
|
MOO_DEBUG1 (moo, "<ffi.close> %p\n", ffi->handle);
|
|
|
|
free_linked_cas (moo, ffi);
|
|
|
|
#if defined(USE_DYNCALL)
|
|
dcFree (ffi->dc);
|
|
ffi->dc = MOO_NULL;
|
|
#elif defined(USE_LIBFFI)
|
|
if (ffi->arg_types)
|
|
{
|
|
moo_freemem (moo, ffi->arg_types);
|
|
ffi->arg_types = MOO_NULL;
|
|
}
|
|
if (ffi->arg_values)
|
|
{
|
|
moo_freemem (moo, ffi->arg_values);
|
|
ffi->arg_values = MOO_NULL;
|
|
}
|
|
if (ffi->arg_svs)
|
|
{
|
|
moo_freemem (moo, ffi->arg_svs);
|
|
ffi->arg_svs = MOO_NULL;
|
|
}
|
|
ffi->arg_max = 0;
|
|
ffi->arg_count = 0;
|
|
#endif
|
|
|
|
moo->vmprim.dl_close (moo, ffi->handle);
|
|
ffi->handle = MOO_NULL;
|
|
|
|
MOO_STACK_SETRETTORCV (moo, nargs);
|
|
return MOO_PF_SUCCESS;
|
|
|
|
softfail:
|
|
MOO_STACK_SETRETTOERRNUM (moo, nargs);
|
|
return MOO_PF_SUCCESS;
|
|
}
|
|
|
|
static MOO_INLINE int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned, moo_oop_t arg)
|
|
{
|
|
#if defined(USE_LIBFFI)
|
|
if (ffi->arg_count >= ffi->arg_max)
|
|
{
|
|
ffi_type** ttmp;
|
|
void** vtmp;
|
|
ffi_sv_t* stmp;
|
|
|
|
moo_oow_t newmax;
|
|
|
|
newmax = ffi->arg_max + 16; /* TODO: adjust this? */
|
|
ttmp = moo_reallocmem(moo, ffi->arg_types, MOO_SIZEOF(*ttmp) * newmax);
|
|
if (!ttmp) goto oops;
|
|
ffi->arg_types = ttmp;
|
|
|
|
vtmp = moo_reallocmem(moo, ffi->arg_values, MOO_SIZEOF(*vtmp) * newmax);
|
|
if (!vtmp) goto oops;
|
|
ffi->arg_values = vtmp;
|
|
|
|
stmp = moo_reallocmem(moo, ffi->arg_svs, MOO_SIZEOF(*stmp) * newmax);
|
|
if (!stmp) goto oops;
|
|
ffi->arg_svs = stmp;
|
|
|
|
ffi->arg_max = newmax;
|
|
}
|
|
#endif
|
|
|
|
switch (fmtc)
|
|
{
|
|
case FMTC_INT8:
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (MOO_OOP_IS_CHAR(arg)) v = MOO_OOP_TO_CHAR(arg);
|
|
else if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt8 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ui8;
|
|
ffi->arg_svs[ffi->arg_count].ui8 = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (MOO_OOP_IS_CHAR(arg)) v = MOO_OOP_TO_CHAR(arg);
|
|
else if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt8 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].i8;
|
|
ffi->arg_svs[ffi->arg_count].i8 = v;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case FMTC_INT16:
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt16 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ui16;
|
|
ffi->arg_svs[ffi->arg_count].ui16 = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt16 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].i16;
|
|
ffi->arg_svs[ffi->arg_count].i16 = v;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
|
|
case FMTC_INT32:
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt32 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ui32;
|
|
ffi->arg_svs[ffi->arg_count].ui32 = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt32 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].i32;
|
|
ffi->arg_svs[ffi->arg_count].i32 = v;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
|
|
case FMTC_INT64:
|
|
#if (MOO_SIZEOF_INT64_T > 0)
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt64 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ui64;
|
|
ffi->arg_svs[ffi->arg_count].ui64 = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
__dcArgInt64 (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].i64;
|
|
ffi->arg_svs[ffi->arg_count].i64 = v;
|
|
#endif
|
|
}
|
|
break;
|
|
#else
|
|
goto inval_sig_ch;
|
|
#endif
|
|
|
|
case FMTC_CHAR: /* this is a byte */
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (MOO_OOP_IS_CHAR(arg)) v = MOO_OOP_TO_CHAR(arg);
|
|
else if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgChar (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].uc;
|
|
ffi->arg_svs[ffi->arg_count].uc = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (MOO_OOP_IS_CHAR(arg)) v = MOO_OOP_TO_CHAR(arg);
|
|
else if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgChar (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].c;
|
|
ffi->arg_svs[ffi->arg_count].c = v;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case FMTC_SHORT:
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgShort (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].uh;
|
|
ffi->arg_svs[ffi->arg_count].uh = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgShort (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].h;
|
|
ffi->arg_svs[ffi->arg_count].h = v;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case FMTC_INT:
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgInt (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ui;
|
|
ffi->arg_svs[ffi->arg_count].ui = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgInt (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].i;
|
|
ffi->arg_svs[ffi->arg_count].i = v;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case FMTC_LONG:
|
|
arg_as_long:
|
|
if (_unsigned)
|
|
{
|
|
moo_oow_t v;
|
|
if (moo_inttooow_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgLong (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ul;
|
|
ffi->arg_svs[ffi->arg_count].ul = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_ooi_t v;
|
|
if (moo_inttoooi_noseterr(moo, arg, &v) == 0) goto inval_arg_value;;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgLong (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].l;
|
|
ffi->arg_svs[ffi->arg_count].l = v;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case FMTC_LONGLONG:
|
|
#if (MOO_SIZEOF_LONG_LONG <= MOO_SIZEOF_LONG)
|
|
goto arg_as_long;
|
|
#else
|
|
if (_unsigned)
|
|
{
|
|
moo_uintmax_t v;
|
|
if (moo_inttouintmax_noseterr(moo, arg, &v) <= 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgLongLong (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ull;
|
|
ffi->arg_svs[ffi->arg_count].ull = v;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
moo_intmax_t v;
|
|
if (moo_inttointmax_noseterr(moo, arg, &v) == 0) goto inval_arg_value;
|
|
#if defined(USE_DYNCALL)
|
|
dcArgLongLong (ffi->dc, v);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].ll;
|
|
ffi->arg_svs[ffi->arg_count].ll = v;
|
|
#endif
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case FMTC_BCS:
|
|
{
|
|
moo_bch_t* ptr;
|
|
|
|
if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval_arg_value;
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
ptr = moo_dupootobcharswithheadroom(moo, MOO_SIZEOF_VOID_P, MOO_OBJ_GET_CHAR_SLOT(arg), MOO_OBJ_GET_SIZE(arg), MOO_NULL);
|
|
if (!ptr) goto oops; /* out of system memory or conversion error - soft failure */
|
|
link_ca (ffi, ptr);
|
|
#else
|
|
ptr = MOO_OBJ_GET_CHAR_SLOT(arg);
|
|
/*ptr = moo_dupoochars(moo, MOO_OBJ_GET_CHAR_SLOT(arg), MOO_OBJ_GET_SIZE(arg));
|
|
if (!ptr) goto oops;*/ /* out of system memory or conversion error - soft failure */
|
|
#endif
|
|
|
|
#if defined(USE_DYNCALL)
|
|
dcArgPointer (ffi->dc, ptr);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
|
|
ffi->arg_svs[ffi->arg_count].p = ptr;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case FMTC_UCS:
|
|
{
|
|
moo_uch_t* ptr;
|
|
|
|
if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval_arg_value;
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
ptr = MOO_OBJ_GET_CHAR_SLOT(arg);
|
|
/*ptr = moo_dupoochars(moo, MOO_OBJ_GET_CHAR_SLOT(arg), MOO_OBJ_GET_SIZE(arg));
|
|
if (!ptr) goto oops; */ /* out of system memory or conversion error - soft failure */
|
|
#else
|
|
ptr = moo_dupootoucharswithheadroom(moo, MOO_SIZEOF_VOID_P, MOO_OBJ_GET_CHAR_SLOT(arg), MOO_OBJ_GET_SIZE(arg), MOO_NULL);
|
|
if (!ptr) goto oops; /* out of system memory or conversion error - soft failure */
|
|
link_ca (ffi, ptr);
|
|
#endif
|
|
|
|
#if defined(USE_DYNCALL)
|
|
dcArgPointer (ffi->dc, ptr);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
|
|
ffi->arg_svs[ffi->arg_count].p = ptr;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case FMTC_BLOB:
|
|
{
|
|
void* ptr;
|
|
|
|
if (MOO_OBJ_IS_BYTE_POINTER(arg)) goto inval_arg_value;
|
|
ptr = MOO_OBJ_GET_BYTE_SLOT(arg);
|
|
|
|
#if defined(USE_DYNCALL)
|
|
dcArgPointer (ffi->dc, ptr);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
|
|
ffi->arg_svs[ffi->arg_count].p = ptr;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case FMTC_POINTER:
|
|
{
|
|
void* ptr;
|
|
|
|
/* TODO: map nil to NULL? or should #\p0 be enough? */
|
|
if (!MOO_OOP_IS_SMPTR(arg)) goto inval_arg_value;
|
|
ptr = MOO_OOP_TO_SMPTR(arg);
|
|
|
|
#if defined(USE_DYNCALL)
|
|
dcArgPointer (ffi->dc, ptr);
|
|
#elif defined(USE_LIBFFI)
|
|
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
|
|
ffi->arg_svs[ffi->arg_count].p = ptr;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
default:
|
|
inval_sig_ch:
|
|
/* invalid argument signature specifier */
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "invalid argument type signature - %jc", fmtc);
|
|
goto oops;
|
|
}
|
|
|
|
#if defined(USE_LIBFFI)
|
|
ffi->arg_types[ffi->arg_count] = ffi->fmtc_to_type[_unsigned][fmtc];
|
|
ffi->arg_count++;
|
|
#endif
|
|
return 0;
|
|
|
|
inval_arg_value:
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "invalid argument value - %O", arg);
|
|
|
|
oops:
|
|
return -1;
|
|
}
|
|
|
|
|
|
static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
|
|
{
|
|
#if defined(USE_DYNCALL) || defined(USE_LIBFFI)
|
|
ffi_t* ffi;
|
|
moo_oop_t fun, sig, args;
|
|
moo_oow_t i, j, nfixedargs, _unsigned;
|
|
void* f;
|
|
moo_oop_oop_t arr;
|
|
int vbar = 0;
|
|
moo_ooch_t fmtc;
|
|
#if defined(USE_LIBFFI)
|
|
ffi_status fs;
|
|
#endif
|
|
|
|
ffi = (ffi_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL);
|
|
|
|
fun = MOO_STACK_GETARG(moo, nargs, 0);
|
|
sig = MOO_STACK_GETARG(moo, nargs, 1);
|
|
args = MOO_STACK_GETARG(moo, nargs, 2);
|
|
|
|
if (moo_ptrtooow(moo, fun, (moo_oow_t*)&f) <= -1) goto softfail;
|
|
|
|
/* the signature must not be empty. at least the return type must be
|
|
* specified */
|
|
if (!MOO_OBJ_IS_CHAR_POINTER(sig) || MOO_OBJ_GET_SIZE(sig) <= 0) goto inval;
|
|
|
|
#if 0
|
|
/* TODO: check if arr is a kind of array??? or check if it's indexed */
|
|
if (MOO_OBJ_GET_SIZE(sig) > 1 && MOO_CLASSOF(moo,args) != moo->_array) goto inval;
|
|
#endif
|
|
|
|
arr = (moo_oop_oop_t)args;
|
|
/*MOO_DEBUG2 (moo, "<ffi.call> %p in %p\n", f, ffi->handle);*/
|
|
|
|
#if defined(USE_DYNCALL)
|
|
dcMode (ffi->dc, DC_CALL_C_DEFAULT);
|
|
dcReset (ffi->dc);
|
|
|
|
for (i = 0; i < MOO_OBJ_GET_SIZE(sig); i++)
|
|
{
|
|
fmtc = MOO_OBJ_GET_CHAR_VAL(sig, i);
|
|
if (fmtc == '>') break; /* end of arguments. start of return type */
|
|
if (fmtc == '|')
|
|
{
|
|
dcMode (ffi->dc, DC_CALL_C_ELLIPSIS); /* variadic. for arguments before ... */
|
|
/* the error code should be DC_ERROR_UNSUPPORTED_MODE */
|
|
if (dcGetError(ffi->dc) != DC_ERROR_NONE) goto noimpl;
|
|
dcReset (ffi->dc);
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
ffi->arg_count = 0;
|
|
#endif
|
|
|
|
/* check argument signature */
|
|
for (i = 0, j = 0, nfixedargs = 0, _unsigned = 0; i < MOO_OBJ_GET_SIZE(sig); i++)
|
|
{
|
|
fmtc = MOO_OBJ_GET_CHAR_VAL(sig, i);
|
|
if (fmtc == ' ')
|
|
{
|
|
continue;
|
|
}
|
|
if (fmtc == '>')
|
|
{
|
|
i++;
|
|
if (!vbar) nfixedargs = j;
|
|
break;
|
|
}
|
|
else if (fmtc == '|')
|
|
{
|
|
if (!vbar)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
dcMode (ffi->dc, DC_CALL_C_ELLIPSIS_VARARGS); /* start of arguments that fall to the ... part */
|
|
/* the error code should be DC_ERROR_UNSUPPORTED_MODE */
|
|
if (dcGetError(ffi->dc) != DC_ERROR_NONE) goto noimpl;
|
|
#endif
|
|
nfixedargs = j;
|
|
vbar = 1;
|
|
}
|
|
continue;
|
|
}
|
|
else if (fmtc == 'u')
|
|
{
|
|
_unsigned = 1;
|
|
continue;
|
|
}
|
|
|
|
/* more items in signature than the actual argument */
|
|
if (j >= MOO_OBJ_GET_SIZE(arr)) goto inval;
|
|
|
|
if (add_ffi_arg(moo, ffi, fmtc, _unsigned, MOO_OBJ_GET_OOP_VAL(arr, j)) <= -1) goto softfail;
|
|
_unsigned = 0;
|
|
j++;
|
|
}
|
|
|
|
while (i < MOO_OBJ_GET_SIZE(sig) && MOO_OBJ_GET_CHAR_VAL(sig, i) == ' ') i++; /* skip all spaces after > */
|
|
fmtc = (i >= MOO_OBJ_GET_SIZE(sig)? FMTC_NULL: MOO_OBJ_GET_CHAR_VAL(sig, i));
|
|
if (fmtc == 'u')
|
|
{
|
|
_unsigned = 1;
|
|
i++;
|
|
fmtc = (i >= MOO_OBJ_GET_SIZE(sig)? FMTC_NULL: MOO_OBJ_GET_CHAR_VAL(sig, i));
|
|
}
|
|
else
|
|
{
|
|
_unsigned = 0;
|
|
}
|
|
|
|
|
|
#if defined(USE_LIBFFI)
|
|
if (!ffi->fmtc_to_type[0][fmtc]) goto inval; /* invalid return value signature */
|
|
|
|
fs = (nfixedargs == j)? ffi_prep_cif(&ffi->cif, FFI_DEFAULT_ABI, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types):
|
|
ffi_prep_cif_var(&ffi->cif, FFI_DEFAULT_ABI, nfixedargs, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types);
|
|
if (fs != FFI_OK)
|
|
{
|
|
moo_seterrnum (moo, MOO_ESYSERR);
|
|
goto softfail;
|
|
}
|
|
|
|
ffi_call (&ffi->cif, FFI_FN(f), &ffi->ret_sv, ffi->arg_values);
|
|
#endif
|
|
|
|
|
|
/* check the return value type in signature */
|
|
switch (fmtc)
|
|
{
|
|
/* TODO: support more types... */
|
|
/* TODO: proper return value conversion */
|
|
case FMTC_INT8:
|
|
{
|
|
moo_oop_t r;
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_oowtoint(moo, __dcCallInt8(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_oowtoint(moo, ffi->ret_sv.ui8);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_ooitoint(moo, __dcCallInt8(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_ooitoint(moo, ffi->ret_sv.i8);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
}
|
|
|
|
case FMTC_INT16:
|
|
{
|
|
moo_oop_t r;
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_oowtoint(moo, __dcCallInt16(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_oowtoint(moo, ffi->ret_sv.ui16);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_ooitoint(moo, __dcCallInt16(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_ooitoint(moo, ffi->ret_sv.i16);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
}
|
|
|
|
case FMTC_INT32:
|
|
{
|
|
moo_oop_t r;
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_oowtoint(moo, __dcCallInt32(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_oowtoint(moo, ffi->ret_sv.ui32);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_ooitoint(moo, __dcCallInt32(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_ooitoint(moo, ffi->ret_sv.i32);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
}
|
|
|
|
case FMTC_INT64:
|
|
{
|
|
#if (MOO_SIZEOF_INT64_T > 0)
|
|
moo_oop_t r;
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_oowtoint(moo, __dcCallInt64(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_oowtoint(moo, ffi->ret_sv.ui64);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_ooitoint(moo, __dcCallInt64(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_ooitoint(moo, ffi->ret_sv.i64);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
#else
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "invalid return type signature - %jc", fmtc);
|
|
goto softfail;
|
|
#endif
|
|
}
|
|
|
|
|
|
case FMTC_CHAR:
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
char r = dcCallChar(ffi->dc, f);
|
|
MOO_STACK_SETRET (moo, nargs, MOO_CHAR_TO_OOP(r));
|
|
#elif defined(USE_LIBFFI)
|
|
if (_unsigned)
|
|
{
|
|
MOO_STACK_SETRET (moo, nargs, MOO_CHAR_TO_OOP(ffi->ret_sv.uc));
|
|
}
|
|
else
|
|
{
|
|
MOO_STACK_SETRET (moo, nargs, MOO_CHAR_TO_OOP(ffi->ret_sv.c));
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case FMTC_SHORT:
|
|
{
|
|
moo_oop_t r;
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_oowtoint(moo, dcCallShort(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_oowtoint(moo, ffi->ret_sv.uh);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_ooitoint(moo, dcCallShort(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_ooitoint(moo, ffi->ret_sv.h);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
}
|
|
|
|
case FMTC_INT:
|
|
{
|
|
moo_oop_t r;
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_oowtoint(moo, dcCallInt(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_oowtoint(moo, ffi->ret_sv.ui);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_ooitoint(moo, dcCallInt(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_ooitoint(moo, ffi->ret_sv.i);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
}
|
|
|
|
case FMTC_LONG:
|
|
{
|
|
moo_oop_t r;
|
|
ret_as_long:
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_oowtoint(moo, dcCallLong(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_oowtoint(moo, ffi->ret_sv.ul);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_ooitoint(moo, dcCallLong(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_ooitoint(moo, ffi->ret_sv.l);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
}
|
|
|
|
case FMTC_LONGLONG:
|
|
{
|
|
#if (MOO_SIZEOF_LONG_LONG <= MOO_SIZEOF_LONG)
|
|
goto ret_as_long;
|
|
#else
|
|
moo_oop_t r;
|
|
if (_unsigned)
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_uintmaxtoint(moo, dcCallLongLong(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_uintmaxtoint(moo, ffi->ret_sv.ull);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#if defined(USE_DYNCALL)
|
|
r = moo_intmaxtoint(moo, dcCallLongLong(ffi->dc, f));
|
|
#elif defined(USE_LIBFFI)
|
|
r = moo_intmaxtoint(moo, ffi->ret_sv.ll);
|
|
#endif
|
|
}
|
|
if (!r) goto hardfail;
|
|
MOO_STACK_SETRET (moo, nargs, r);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
case FMTC_BCS:
|
|
{
|
|
moo_oop_t s;
|
|
moo_bch_t* r;
|
|
|
|
#if defined(USE_DYNCALL)
|
|
r = dcCallPointer(ffi->dc, f);
|
|
#elif defined(USE_LIBFFI)
|
|
r = ffi->ret_sv.p;
|
|
#endif
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
s = moo_makestringwithbchars(moo, r, moo_count_bcstr(r));
|
|
#else
|
|
s = moo_makestring(moo, r, moo_count_bcstr(r));
|
|
#endif
|
|
if (!s)
|
|
{
|
|
if (moo->errnum == MOO_EOOMEM) goto hardfail; /* out of object memory - hard failure*/
|
|
goto softfail;
|
|
}
|
|
|
|
MOO_STACK_SETRET (moo, nargs, s);
|
|
break;
|
|
}
|
|
|
|
case FMTC_UCS:
|
|
{
|
|
moo_oop_t s;
|
|
moo_uch_t* r;
|
|
|
|
#if defined(USE_DYNCALL)
|
|
r = dcCallPointer(ffi->dc, f);
|
|
#elif defined(USE_LIBFFI)
|
|
r = ffi->ret_sv.p;
|
|
#endif
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
s = moo_makestring(moo, r, moo_count_ucstr(r));
|
|
#else
|
|
s = moo_makestringwithuchars(moo, r, moo_count_ucstr(r));
|
|
#endif
|
|
if (!s)
|
|
{
|
|
if (moo->errnum == MOO_EOOMEM) goto hardfail; /* out of object memory - hard failure*/
|
|
goto softfail;
|
|
}
|
|
|
|
MOO_STACK_SETRET (moo, nargs, s);
|
|
break;
|
|
}
|
|
|
|
|
|
#if 0
|
|
case FMTC_BLOB:
|
|
{
|
|
/* blob as a return type isn't sufficient as it lacks the size information.
|
|
* blob as an argument is just a pointer and the size can be yet another argument.
|
|
* it there a good way to represent this here?... TODO: */
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
case FMTC_POINTER:
|
|
{
|
|
void* r;
|
|
|
|
#if defined(USE_DYNCALL)
|
|
r = dcCallPointer(ffi->dc, f);
|
|
#elif defined(USE_LIBFFI)
|
|
r = ffi->ret_sv.p;
|
|
#endif
|
|
|
|
if (!MOO_IN_SMPTR_RANGE(r))
|
|
{
|
|
/* the returned pointer is not aligned */
|
|
goto inval;
|
|
}
|
|
|
|
MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP(r));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
#if defined(USE_DYNCALL)
|
|
dcCallVoid (ffi->dc, f);
|
|
#endif
|
|
MOO_STACK_SETRETTORCV (moo, nargs);
|
|
break;
|
|
}
|
|
|
|
free_linked_cas (moo, ffi);
|
|
return MOO_PF_SUCCESS;
|
|
|
|
noimpl:
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
goto softfail;
|
|
|
|
inval:
|
|
moo_seterrnum (moo, MOO_EINVAL);
|
|
goto softfail;
|
|
|
|
softfail:
|
|
free_linked_cas (moo, ffi);
|
|
MOO_STACK_SETRETTOERRNUM (moo, nargs);
|
|
return MOO_PF_SUCCESS;
|
|
|
|
hardfail:
|
|
free_linked_cas (moo, ffi);
|
|
return MOO_PF_HARD_FAILURE;
|
|
|
|
#else
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
MOO_STACK_SETRETTOERRNUM (moo, nargs);
|
|
return MOO_PF_SUCCESS;
|
|
#endif
|
|
}
|
|
|
|
static moo_pfrc_t pf_getsym (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
|
|
{
|
|
ffi_t* ffi;
|
|
moo_oop_t name, ret;
|
|
void* sym;
|
|
|
|
MOO_ASSERT (moo, nargs == 1);
|
|
|
|
ffi = (ffi_t*)moo_getobjtrailer(moo, MOO_STACK_GETRCV(moo, nargs), MOO_NULL);
|
|
name = MOO_STACK_GETARG(moo, nargs, 0);
|
|
|
|
if (!MOO_OBJ_IS_CHAR_POINTER(name))
|
|
{
|
|
moo_seterrnum (moo, MOO_EINVAL);
|
|
goto softfail;
|
|
}
|
|
|
|
if (!moo->vmprim.dl_getsym)
|
|
{
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
goto softfail;
|
|
}
|
|
|
|
sym = moo->vmprim.dl_getsym(moo, ffi->handle, MOO_OBJ_GET_CHAR_SLOT(name));
|
|
if (!sym) goto softfail;
|
|
|
|
MOO_DEBUG4 (moo, "<ffi.getsym> %.*js => %p in %p\n", MOO_OBJ_GET_SIZE(name), MOO_OBJ_GET_CHAR_SLOT(name), sym, ffi->handle);
|
|
|
|
ret = moo_oowtoptr(moo, (moo_oow_t)sym);
|
|
if (!ret) goto softfail;
|
|
|
|
MOO_STACK_SETRET (moo, nargs, ret);
|
|
return MOO_PF_SUCCESS;
|
|
|
|
softfail:
|
|
MOO_STACK_SETRETTOERRNUM (moo, nargs);
|
|
return MOO_PF_SUCCESS;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
#define C MOO_METHOD_CLASS
|
|
#define I MOO_METHOD_INSTANCE
|
|
|
|
#define MA MOO_TYPE_MAX(moo_oow_t)
|
|
|
|
static moo_pfinfo_t pfinfos[] =
|
|
{
|
|
{ I, "call", { pf_call, 3, 3 } },
|
|
{ I, "close", { pf_close, 0, 0 } },
|
|
{ I, "getsym", { pf_getsym, 1, 1 } },
|
|
{ I, "open", { pf_open, 1, 1 } }
|
|
};
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
static int import (moo_t* moo, moo_mod_t* mod, moo_oop_class_t _class)
|
|
{
|
|
if (moo_setclasstrsize(moo, _class, MOO_SIZEOF(ffi_t), MOO_NULL) <= -1) return -1;
|
|
return 0;
|
|
}
|
|
|
|
static moo_pfbase_t* querypf (moo_t* moo, moo_mod_t* mod, const moo_ooch_t* name, moo_oow_t namelen)
|
|
{
|
|
return moo_findpfbase (moo, pfinfos, MOO_COUNTOF(pfinfos), name, namelen);
|
|
}
|
|
|
|
static void unload (moo_t* moo, moo_mod_t* mod)
|
|
{
|
|
/* TODO: anything? close open open dll handles? For that, pf_open must store the value it returns to mod->ctx or somewhere..*/
|
|
/* TODO: track all opened shared objects... clear all external memories/resources created but not cleared (for lacking the call to 'close') */
|
|
}
|
|
|
|
int moo_mod_ffi (moo_t* moo, moo_mod_t* mod)
|
|
{
|
|
mod->import = import;
|
|
mod->querypf = querypf;
|
|
mod->querypv = MOO_NULL;
|
|
mod->unload = unload;
|
|
mod->ctx = MOO_NULL;
|
|
return 0;
|
|
}
|