From 70c97f5ab5da756783cd28090339cae3dc357e1e Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Fri, 9 Aug 2019 18:19:13 +0000 Subject: [PATCH] started using libffi in mod/ffi.c if it's available. work in progress --- moo/Makefile.in | 6 +- moo/bin/Makefile.in | 2 + moo/configure | 65 ++++- moo/configure.ac | 10 +- moo/kernel/Mill.moo | 6 +- moo/kernel/test-005.moo | 4 +- moo/kernel/test-bi.moo | 42 +-- moo/lib/Makefile.in | 2 + moo/lib/moo-cfg.h.in | 6 + moo/mod/Makefile.am | 2 +- moo/mod/Makefile.in | 5 +- moo/mod/ffi.c | 568 ++++++++++++++++++++++++++++++---------- moo/t/Makefile.in | 2 + moo/wasm/Makefile.in | 2 + 14 files changed, 552 insertions(+), 170 deletions(-) diff --git a/moo/Makefile.in b/moo/Makefile.in index 5c57e16..e5941b7 100644 --- a/moo/Makefile.in +++ b/moo/Makefile.in @@ -166,8 +166,8 @@ am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/ac/ar-lib \ $(top_srcdir)/ac/compile $(top_srcdir)/ac/config.guess \ $(top_srcdir)/ac/config.sub $(top_srcdir)/ac/install-sh \ $(top_srcdir)/ac/ltmain.sh $(top_srcdir)/ac/missing ac/ar-lib \ - ac/compile ac/config.guess ac/config.sub ac/install-sh \ - ac/ltmain.sh ac/missing + ac/compile ac/config.guess ac/config.sub ac/depcomp \ + ac/install-sh ac/ltmain.sh ac/missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) @@ -241,6 +241,7 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +FFI_LIBS = @FFI_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HAVE_CXX = @HAVE_CXX@ @@ -355,6 +356,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/moo/bin/Makefile.in b/moo/bin/Makefile.in index f373b58..00444f7 100644 --- a/moo/bin/Makefile.in +++ b/moo/bin/Makefile.in @@ -225,6 +225,7 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +FFI_LIBS = @FFI_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HAVE_CXX = @HAVE_CXX@ @@ -339,6 +340,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/moo/configure b/moo/configure index 606fe6b..7a1b36a 100755 --- a/moo/configure +++ b/moo/configure @@ -678,6 +678,7 @@ UNICOWS_LIBS SOCKET_LIBS TERMINAL_LIBS UNWIND_LIBS +FFI_LIBS DYNCALL_LIBS LTDL_LIBS DL_LIBS @@ -792,6 +793,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -891,6 +893,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1143,6 +1146,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1280,7 +1292,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1433,6 +1445,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -18304,7 +18317,7 @@ fi done -for ac_header in dyncall.h libunwind.h +for ac_header in ffi.h dyncall.h libunwind.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -18608,6 +18621,54 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ffi_call in -lffi" >&5 +$as_echo_n "checking for ffi_call in -lffi... " >&6; } +if ${ac_cv_lib_ffi_ffi_call+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lffi $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ffi_call (); +int +main () +{ +return ffi_call (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_ffi_ffi_call=yes +else + ac_cv_lib_ffi_ffi_call=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ffi_ffi_call" >&5 +$as_echo "$ac_cv_lib_ffi_ffi_call" >&6; } +if test "x$ac_cv_lib_ffi_ffi_call" = xyes; then : + + FFI_LIBS="-lffi" + +$as_echo "#define HAVE_FFI_LIB 1" >>confdefs.h + + + +fi + + + if test "x${ac_cv_header_libunwind_h}" = "xyes" then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unw_backtrace in -lunwind" >&5 diff --git a/moo/configure.ac b/moo/configure.ac index ad423f5..8c5db5d 100644 --- a/moo/configure.ac +++ b/moo/configure.ac @@ -138,7 +138,7 @@ AC_CHECK_HEADERS([dlfcn.h ltdl.h sys/mman.h]) AC_CHECK_HEADERS([sys/devpoll.h sys/epoll.h poll.h]) AC_CHECK_HEADERS([netinet/in.h sys/un.h netpacket/packet.h net/if_dl.h]) AC_CHECK_HEADERS([xcb/xcb.h]) -AC_CHECK_HEADERS([dyncall.h libunwind.h]) +AC_CHECK_HEADERS([ffi.h dyncall.h libunwind.h]) dnl check data types dnl AC_CHECK_TYPE([wchar_t], @@ -188,6 +188,14 @@ AC_CHECK_LIB([dyncall_s], [dcNewCallVM], ) AC_SUBST(DYNCALL_LIBS) +AC_CHECK_LIB([ffi], [ffi_call], + [ + FFI_LIBS="-lffi" + AC_DEFINE([HAVE_FFI_LIB], [1], [libffi library is available]) + ] +) +AC_SUBST(FFI_LIBS) + if test "x${ac_cv_header_libunwind_h}" = "xyes" then AC_CHECK_LIB([unwind], [unw_backtrace], diff --git a/moo/kernel/Mill.moo b/moo/kernel/Mill.moo index 6176b54..5b69305 100644 --- a/moo/kernel/Mill.moo +++ b/moo/kernel/Mill.moo @@ -91,9 +91,9 @@ class MyObject(Object) } else { - (ffi call: #getpid signature: ")i" arguments: nil) dump. - (ffi call: #printf signature: "s|iis)i" arguments: #("A=>%d B=>%d Hello, world %s\n" 1 2 "fly away")) dump. - (ffi call: #printf signature: "s|iis)i" arguments: #("A=>%d B=>%d Hello, world %s\n" 1 2 "jump down")) dump. + (ffi call: #getpid signature: ">i" arguments: nil) dump. + (ffi call: #printf signature: "s|iis>i" arguments: #("A=>%d B=>%d Hello, world %s\n" 1 2 "fly away")) dump. + (ffi call: #printf signature: "s|iis>i" arguments: #("A=>%d B=>%d Hello, world %s\n" 1 2 "jump down")) dump. ffi close. }. diff --git a/moo/kernel/test-005.moo b/moo/kernel/test-005.moo index 4e61565..6fd1f01 100644 --- a/moo/kernel/test-005.moo +++ b/moo/kernel/test-005.moo @@ -255,8 +255,8 @@ class MyObject(TestObject) ffi := FFI new: "libc.so.6". // ffi call: #printf with: #((str "%d") (int 10) (long 20)). - ffi call: #printf signature: "|s|ici)i" arguments: #("hello world %d %c %d\n" 11123 $X 9876543). - //ffi call: #puts signature: "s)i" arguments: #("hello world"). + ffi call: #printf signature: "s|ici>i" arguments: #("hello world %d %c %d\n" 11123 $X 9876543). + //ffi call: #puts signature: "s>i" arguments: #("hello world"). ffi close. } diff --git a/moo/kernel/test-bi.moo b/moo/kernel/test-bi.moo index 7da996d..35ea872 100644 --- a/moo/kernel/test-bi.moo +++ b/moo/kernel/test-bi.moo @@ -41,9 +41,9 @@ class MyObject(Object) ffi := FFI new: 'libc.so.6'. - now := ffi call: #time signature: 'l)i' arguments: #(0). - ////ffi call: #srand signature: 'i)' arguments: ##(now). - ffi call: #srandom signature: 'i)' arguments: ##(now). + now := ffi call: #time signature: 'l>i' arguments: #(0). + ////ffi call: #srand signature: 'i>' arguments: ##(now). + ffi call: #srandom signature: 'i>' arguments: ##(now). [ divr_ubound := 16rFFFFFFFFFFFFFFFFFFFFFFFF. @@ -51,32 +51,42 @@ class MyObject(Object) while (true) { - //x := (ffi call: #rand signature: ')i' arguments: nil) rem: 20. - //divd := (ffi call: #rand signature: ')i' arguments: nil). - x := (ffi call: #random signature: ')l' arguments: nil) rem: 20. - divd := (ffi call: #random signature: ')l' arguments: nil). + //x := (ffi call: #rand signature: '>i' arguments: nil) rem: 20. + //divd := (ffi call: #rand signature: '>i' arguments: nil). + x := (ffi call: #random signature: '>l' arguments: nil) rem: 20. + divd := (ffi call: #random signature: '>l' arguments: nil). while (x > 0) { - //divd := (divd bitShift: 7) bitOr: (ffi call: #rand signature: ')i' arguments: nil). - divd := (divd bitShift: 7) bitOr: (ffi call: #random signature: ')l' arguments: nil). + //divd := (divd bitShift: 7) bitOr: (ffi call: #rand signature: '>i' arguments: nil). + divd := (divd bitShift: 7) bitOr: (ffi call: #random signature: '>l' arguments: nil). x := x - 1. }. - //x := (ffi call: #rand signature: ')i' arguments: nil) rem: 20. - //divr := (ffi call: #rand signature: ')i' arguments: nil). - x := (ffi call: #random signature: ')l' arguments: nil) rem: 20. - divr := (ffi call: #random signature: ')l' arguments: nil). + //x := (ffi call: #rand signature: '>i' arguments: nil) rem: 20. + //divr := (ffi call: #rand signature: '>i' arguments: nil). + x := (ffi call: #random signature: '>l' arguments: nil) rem: 20. + divr := (ffi call: #random signature: '>l' arguments: nil). while (x > 0) { - //divr := (divr bitShift: 7) bitOr: (ffi call: #rand signature: ')i' arguments: nil). - divr := (divr bitShift: 7) bitOr: (ffi call: #random signature: ')l' arguments: nil). + //divr := (divr bitShift: 7) bitOr: (ffi call: #rand signature: '>i' arguments: nil). + divr := (divr bitShift: 7) bitOr: (ffi call: #random signature: '>l' arguments: nil). x := x - 1. }. if (divr = 0) { divr := 1 }. q := divd div: divr. r := divd rem: divr. - if (divd ~= (q * divr + r)) { i dump. divd dump. divr dump. q dump. r dump. (q * divr + r) dump. ^false. }. + if (divd ~= (q * divr + r)) + { + // dump numbers if result is wrong + i dump. + divd dump. + divr dump. + q dump. + r dump. + (q * divr + r) dump. + ^false. + }. ////((q asString) & ' ' & (r asString)) dump }. ] ensure: [ ffi close. ]. diff --git a/moo/lib/Makefile.in b/moo/lib/Makefile.in index 2b5fd34..642a228 100644 --- a/moo/lib/Makefile.in +++ b/moo/lib/Makefile.in @@ -308,6 +308,7 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +FFI_LIBS = @FFI_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HAVE_CXX = @HAVE_CXX@ @@ -422,6 +423,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/moo/lib/moo-cfg.h.in b/moo/lib/moo-cfg.h.in index b235eca..fcf6256 100644 --- a/moo/lib/moo-cfg.h.in +++ b/moo/lib/moo-cfg.h.in @@ -75,6 +75,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_FFI_H + +/* libffi library is available */ +#undef HAVE_FFI_LIB + /* Define to 1 if you have the `floorq' function. */ #undef HAVE_FLOORQ diff --git a/moo/mod/Makefile.am b/moo/mod/Makefile.am index 75f79cf..0966cbc 100644 --- a/moo/mod/Makefile.am +++ b/moo/mod/Makefile.am @@ -79,7 +79,7 @@ if ENABLE_MOD_FFI libmoo_ffi_la_SOURCES = ffi.c _ffi.h libmoo_ffi_la_CPPFLAGS = $(CPPFLAGS_COMMON) libmoo_ffi_la_LDFLAGS = $(LDFLAGS_COMMON) -libmoo_ffi_la_LIBADD = $(LIBADD_COMMON) $(DYNCALL_LIBS) +libmoo_ffi_la_LIBADD = $(LIBADD_COMMON) $(DYNCALL_LIBS) $(FFI_LIBS) endif if ENABLE_MOD_SCK diff --git a/moo/mod/Makefile.in b/moo/mod/Makefile.in index 993233e..0c7be37 100644 --- a/moo/mod/Makefile.in +++ b/moo/mod/Makefile.in @@ -160,6 +160,7 @@ libmoo_con_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ @ENABLE_MOD_CON_TRUE@@ENABLE_STATIC_MODULE_TRUE@am_libmoo_con_la_rpath = @ENABLE_MOD_FFI_TRUE@libmoo_ffi_la_DEPENDENCIES = \ @ENABLE_MOD_FFI_TRUE@ $(am__DEPENDENCIES_1) \ +@ENABLE_MOD_FFI_TRUE@ $(am__DEPENDENCIES_1) \ @ENABLE_MOD_FFI_TRUE@ $(am__DEPENDENCIES_1) am__libmoo_ffi_la_SOURCES_DIST = ffi.c _ffi.h @ENABLE_MOD_FFI_TRUE@am_libmoo_ffi_la_OBJECTS = libmoo_ffi_la-ffi.lo @@ -311,6 +312,7 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +FFI_LIBS = @FFI_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HAVE_CXX = @HAVE_CXX@ @@ -425,6 +427,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -467,7 +470,7 @@ CPPFLAGS_COMMON = \ @ENABLE_MOD_FFI_TRUE@libmoo_ffi_la_SOURCES = ffi.c _ffi.h @ENABLE_MOD_FFI_TRUE@libmoo_ffi_la_CPPFLAGS = $(CPPFLAGS_COMMON) @ENABLE_MOD_FFI_TRUE@libmoo_ffi_la_LDFLAGS = $(LDFLAGS_COMMON) -@ENABLE_MOD_FFI_TRUE@libmoo_ffi_la_LIBADD = $(LIBADD_COMMON) $(DYNCALL_LIBS) +@ENABLE_MOD_FFI_TRUE@libmoo_ffi_la_LIBADD = $(LIBADD_COMMON) $(DYNCALL_LIBS) $(FFI_LIBS) @ENABLE_MOD_SCK_TRUE@libmoo_sck_la_SOURCES = sck.c sck-addr.c _sck.h @ENABLE_MOD_SCK_TRUE@libmoo_sck_la_CPPFLAGS = $(CPPFLAGS_COMMON) @ENABLE_MOD_SCK_TRUE@libmoo_sck_la_LDFLAGS = $(LDFLAGS_COMMON) diff --git a/moo/mod/ffi.c b/moo/mod/ffi.c index 08e4a87..473a7cc 100644 --- a/moo/mod/ffi.c +++ b/moo/mod/ffi.c @@ -32,18 +32,61 @@ #if defined(HAVE_DYNCALL_LIB) && defined(HAVE_DYNCALL_H) # define USE_DYNCALL +#elif defined(HAVE_FFI_LIB) && defined(HAVE_FFI_H) +# define USE_LIBFFI #endif #if defined(USE_DYNCALL) # include +#elif defined(USE_LIBFFI) +# include +# 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 #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_POINTER 'p' +#define FMTC_BCS 's' +#define FMTC_UCS 'S' + 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 +}; +#endif + typedef struct ffi_t ffi_t; struct ffi_t { @@ -51,7 +94,18 @@ struct ffi_t #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 */ }; @@ -106,11 +160,11 @@ static moo_pfrc_t pf_open (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) goto softfail; } - handle = moo->vmprim.dl_open (moo, MOO_OBJ_GET_CHAR_SLOT(name), 0); + 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? */ + dc = dcNewCallVM(4096); /* TODO: right size? */ if (!dc) { moo_seterrwithsyserr (moo, 0, errno); @@ -123,6 +177,29 @@ static moo_pfrc_t pf_open (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) #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_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, " %.*js => %p\n", MOO_OBJ_GET_SIZE(name), MOO_OBJ_GET_CHAR_SLOT(name), ffi->handle); @@ -156,6 +233,25 @@ static moo_pfrc_t pf_close (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) dcFree (ffi->dc); ffi->dc = MOO_NULL; #endif +#if 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; @@ -168,19 +264,249 @@ softfail: return MOO_PF_SUCCESS; } + +static 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; + vtmp = moo_reallocmem(moo, ffi->arg_values, MOO_SIZEOF(*vtmp) * newmax); + if (!vtmp) goto oops; + stmp = moo_reallocmem(moo, ffi->arg_svs, MOO_SIZEOF(*stmp) * newmax); + if (!stmp) goto oops; + + ffi->arg_types = ttmp; + ffi->arg_values = vtmp; + ffi->arg_svs = stmp; + ffi->arg_max = newmax; + } +#endif + + switch (fmtc) + { + case FMTC_CHAR: + if (!MOO_OOP_IS_CHAR(arg)) goto inval; + if (_unsigned) + { + #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 = MOO_OOP_TO_CHAR(arg); + #endif + } + else + { + #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 = MOO_OOP_TO_CHAR(arg); + #endif + } + break; + + case FMTC_SHORT: + if (_unsigned) + { + moo_oow_t v; + if (moo_inttooow(moo, arg, &v) == 0) goto inval; + #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(moo, arg, &v) == 0) goto inval; + #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(moo, arg, &v) == 0) goto inval; + #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(moo, arg, &v) == 0) goto inval; + #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(moo, arg, &v) == 0) goto inval; + #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(moo, arg, &v) == 0) goto inval; + #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 <= 0) + goto arg_as_long; + #else + if (_unsigned) + { + moo_oow_t v; + /* TODO: if (MOO_SIZEOF_LONG_LONG > MOO_SIZEOF_OOI_T) use moo_inttointmax() or something */ + if (moo_inttooow(moo, arg, &v) == 0) goto inval; + #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_ooi_t v; + if (moo_inttoooi(moo, arg, &v) == 0) goto inval; + #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 + +#if 0 + case 'B': /* byte array */ +#endif + case FMTC_BCS: + { + moo_bch_t* ptr; + + if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval; + + #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] = ptr; + #endif + break; + } + + case FMTC_UCS: + { + moo_uch_t* ptr; + + if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval; + + #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] = ptr; + #endif + break; + } + + default: + /* invalid argument signature specifier */ + goto inval; + } + +#if defined(USE_LIBFFI) + ffi->arg_types[ffi->arg_count] = ffi->fmtc_to_type[_unsigned][fmtc]; + ffi->arg_count++; +#endif + return 0; + +inval: + moo_seterrnum (moo, MOO_EINVAL); + +oops: + return -1; +} + + static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { -#if defined(USE_DYNCALL) +#if defined(USE_DYNCALL) || defined(USE_LIBFFI) ffi_t* ffi; moo_oop_t fun, sig, args; - moo_oow_t i, j; + moo_oow_t i, j, nfixedargs; void* f; moo_oop_oop_t arr; - int ellipsis = 0; + 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); - MOO_ASSERT (moo, nargs == 3); fun = MOO_STACK_GETARG(moo, nargs, 0); sig = MOO_STACK_GETARG(moo, nargs, 1); args = MOO_STACK_GETARG(moo, nargs, 2); @@ -201,198 +527,148 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) /*MOO_DEBUG2 (moo, " %p in %p\n", f, ffi->handle);*/ +#if defined(USE_DYNCALL) dcMode (ffi->dc, DC_CALL_C_DEFAULT); dcReset (ffi->dc); - i = 0; - if (i < MOO_OBJ_GET_SIZE(sig) && MOO_OBJ_GET_CHAR_VAL(sig, i) == '|') + for (i = 0; i < MOO_OBJ_GET_SIZE(sig); i++) { - dcMode (ffi->dc, DC_CALL_C_ELLIPSIS); - - /* the error code should be DC_ERROR_UNSUPPORTED_MODE */ - if (dcGetError(ffi->dc) != DC_ERROR_NONE) goto noimpl; - dcReset (ffi->dc); - ellipsis = 1; - 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 (j = 0; i < MOO_OBJ_GET_SIZE(sig); i++) + for (i = 0, j = 0, nfixedargs = 0; i < MOO_OBJ_GET_SIZE(sig); i++) { - moo_ooch_t fmtc; - moo_oop_t arg; - fmtc = MOO_OBJ_GET_CHAR_VAL(sig, i); - if (fmtc == ')') + if (fmtc == '>') { i++; + if (!vbar) nfixedargs = j; break; } else if (fmtc == '|') { - if (ellipsis) + if (!vbar) { - dcMode (ffi->dc, DC_CALL_C_ELLIPSIS_VARARGS); - + #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; } - /* more items in signature than the actual argument */ + /* more items in signature than the actual argument */ if (j >= MOO_OBJ_GET_SIZE(arr)) goto inval; - arg = MOO_OBJ_GET_OOP_VAL(arr, j); - switch (fmtc) - { - /* TODO: support more types... */ - case 'c': - if (!MOO_OOP_IS_CHAR(arg)) goto inval; - dcArgChar (ffi->dc, MOO_OOP_TO_CHAR(arg)); - j++; - break; - -/* TODO: add unsigned types */ - case 'i': - { - moo_ooi_t v; - if (moo_inttoooi(moo, arg, &v) == 0) goto inval; - dcArgInt (ffi->dc, v); - j++; - break; - } - - case 'l': - { - moo_ooi_t v; - arg_as_long: - if (moo_inttoooi(moo, arg, &v) == 0) goto inval; - dcArgLong (ffi->dc, v); - j++; - break; - } - - case 'L': - { - #if (MOO_SIZEOF_LONG_LONG > 0) - # if (MOO_SIZEOF_LONG_LONG <= MOO_SIZEOF_OOI_T) - moo_ooi_t v; - if (moo_inttoooi(moo, arg, &v) == 0) goto inval; - # else - /* TODO: IMPLEMENT THIS moo_intmax_t v; - if (moo_inttointmax(moo, arg, &v) == 0) goto inval; */ - long long v; - goto arg_as_long; - # endif - - dcArgLongLong (ffi->dc, v); - j++; - break; - #else - goto arg_as_long; - #endif - } - -#if 0 - case 'B': /* byte array */ -#endif - case 's': - { - moo_bch_t* ptr; - - if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval; - - #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 softfail; /* 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 softfail;*/ /* out of system memory or conversion error - soft failure */ - #endif - - dcArgPointer (ffi->dc, ptr); - j++; - break; - } - - case 'S': - { - moo_uch_t* ptr; - - if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval; - - #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 softfail; */ /* 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 softfail; /* out of system memory or conversion error - soft failure */ - link_ca (ffi, ptr); - #endif - - dcArgPointer (ffi->dc, ptr); - j++; - break; - } - - default: - /* invalid argument signature specifier */ - goto inval; - } + if (add_ffi_arg(moo, ffi, fmtc, 0, MOO_OBJ_GET_OOP_VAL(arr, j)) <= -1) goto softfail; + j++; } - if (i >= MOO_OBJ_GET_SIZE(sig)) goto call_void; + fmtc = (i >= MOO_OBJ_GET_SIZE(sig)? FMTC_NULL: MOO_OBJ_GET_CHAR_VAL(sig, i)); +#if defined(USE_LIBFFI) +/* TODO: handle unsigned */ +//printf ("XXXXXXXXXXXXXXXXXXXXXXXXXXXxAAAAAAAA %d %d %d %p %p [%s] [%s] %ld\n", (int)j, (int)nfixedargs, (int)ffi->arg_count, ffi->fmtc_to_type[0][fmtc], &ffi_type_sint32, ffi->arg_values[0], ffi->arg_values[1], *(long*)ffi->arg_values[2]); + 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 (MOO_OBJ_GET_CHAR_VAL(sig, i)) + switch (fmtc) { /* TODO: support more types... */ /* TODO: proper return value conversion */ - case 'c': + 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) + MOO_STACK_SETRET (moo, nargs, MOO_CHAR_TO_OOP(ffi->ret_sv.c)); + #endif break; } - case 'i': + case FMTC_SHORT: { moo_oop_t r; + #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 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 'l': + case FMTC_LONG: { moo_oop_t r; ret_as_long: + #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 'L': + case FMTC_LONGLONG: { - #if (MOO_SIZEOF_LONG_LONG > 0) - moo_oop_t r; - # if (MOO_SIZEOF_LONG_LONG <= MOO_SIZEOF_OOI_T) - r = moo_ooitoint(moo, dcCallLongLong(ffi->dc, f)); - # else + #if (MOO_SIZEOF_LONG_LONG <= 0) goto ret_as_long; - # endif + #else + moo_oop_t r; + #if defined(USE_DYNCALL) + + r = moo_ooitoint(moo, dcCallLongLong(ffi->dc, f)); + #elif defined(USE_LIBFFI) + /* TODO: use moo_intmaxtoint()... */ + /* TODO: unsigned */ + r = moo_ooitoint(moo, ffi->ret_sv.ll); + #endif if (!r) goto hardfail; MOO_STACK_SETRET (moo, nargs, r); break; - #else - goto ret_as_long; #endif } @@ -402,13 +678,16 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { } #endif - - case 's': + case FMTC_BCS: { moo_oop_t s; moo_bch_t* r; + #if defined(USE_DYNCALL) r = dcCallPointer(ffi->dc, f); + #else + r = ffi->ret_sv.p; + #endif #if defined(MOO_OOCH_IS_UCH) s = moo_makestringwithbchars(moo, r, moo_count_bcstr(r)); @@ -425,12 +704,16 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) break; } - case 'S': + case FMTC_UCS: { moo_oop_t s; moo_uch_t* r; + #if defined(USE_DYNCALL) r = dcCallPointer(ffi->dc, f); + #else + r = ffi->ret_sv.p; + #endif #if defined(MOO_OOCH_IS_UCH) s = moo_makestring(moo, r, moo_count_ucstr(r)); @@ -448,8 +731,9 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) } default: - call_void: + #if defined(USE_DYNCALL) dcCallVoid (ffi->dc, f); + #endif MOO_STACK_SETRETTORCV (moo, nargs); break; } diff --git a/moo/t/Makefile.in b/moo/t/Makefile.in index 07cafd4..37ea0ba 100644 --- a/moo/t/Makefile.in +++ b/moo/t/Makefile.in @@ -220,6 +220,7 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +FFI_LIBS = @FFI_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HAVE_CXX = @HAVE_CXX@ @@ -334,6 +335,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/moo/wasm/Makefile.in b/moo/wasm/Makefile.in index 85f5fae..3234859 100644 --- a/moo/wasm/Makefile.in +++ b/moo/wasm/Makefile.in @@ -155,6 +155,7 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +FFI_LIBS = @FFI_LIBS@ FGREP = @FGREP@ GREP = @GREP@ HAVE_CXX = @HAVE_CXX@ @@ -269,6 +270,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@