From 5f4d4b36ac8ae01908a552a5740af8be5b77f831 Mon Sep 17 00:00:00 2001 From: John Viega Date: Wed, 19 Jun 2024 08:38:08 -0400 Subject: [PATCH] Foreign Function interface (#36) I took the FFI about as far as I'm going to take it for now, which is farther than it was in v2. Specifically: If the extern decl specifies cstring for a parameter, I automatically convert from c4m_utf8_t * (i.e., pass in the data pointer). For return values marked as cstring, I wrap them in a c4m_utf8_t after return. the holds parameter in is honored; the GC won't collect objects where this has been marked, until c4m_gc_remove_hold is called on the object. The things I'm deferring still: Handling varargs calls (not going to do this until I do keyword parameters). Implementing the allocs parameter. It'd be easy to put allocs in an object wrapper that has a finalizer attached to it, but I need to think about how people should specify what deallocator to use, etc. This isn't important, so I'm not in a hurry on it. --- .gitignore | 1 + deps/Darwin-arm64/libffi.a | Bin 0 -> 53368 bytes deps/linux-amd64/libffi.a | Bin 0 -> 92326 bytes deps/linux-arm64/libffi.a | Bin 0 -> 111720 bytes dev | 5 + include/compiler/datatypes/error.h | 3 + include/compiler/datatypes/file.h | 2 + include/compiler/datatypes/nodeinfo.h | 63 --------- include/compiler/datatypes/scope.h | 10 -- include/compiler/parse.h | 1 + include/con4m.h | 2 + include/con4m/datatypes.h | 8 +- include/con4m/datatypes/callbacks.h | 51 +------- include/con4m/datatypes/ffi.h | 98 ++++++++++++++ include/con4m/datatypes/literals.h | 9 ++ include/con4m/datatypes/memory.h | 1 + include/con4m/datatypes/strings.h | 2 +- include/con4m/datatypes/ufi.h | 60 +++++++++ include/con4m/datatypes/vm.h | 29 +--- include/con4m/ffi.h | 22 ++++ include/con4m/gc.h | 2 + include/con4m/math.h | 2 + include/con4m/stream.h | 1 + meson.build | 3 +- src/con4m/callback.c | 77 ++--------- src/con4m/compiler/ast_utils.c | 9 +- src/con4m/compiler/check_pass.c | 90 +++++++++++++ src/con4m/compiler/codegen.c | 124 +++++++++++------- src/con4m/compiler/decl_pass.c | 95 ++++++++++---- src/con4m/compiler/disasm.c | 4 + src/con4m/compiler/errors.c | 22 ++++ src/con4m/compiler/lex.c | 4 +- src/con4m/compiler/parse.c | 118 ++++------------- src/con4m/compiler/scope.c | 8 +- src/con4m/ffi.c | 182 ++++++++++++++++++++++++++ src/con4m/gc.c | 37 +++--- src/con4m/init.c | 16 +++ src/con4m/numbers.c | 4 +- src/con4m/path.c | 9 +- src/con4m/streams.c | 7 +- src/con4m/vm.c | 99 +++++++++++++- src/con4m/vmmarshal.c | 8 ++ src/hatrack/hash/set.c | 2 +- src/tests/test.c | 2 + tests/basic15.c4m | 6 + tests/basic16.c4m | 7 + 46 files changed, 897 insertions(+), 408 deletions(-) create mode 100644 deps/Darwin-arm64/libffi.a create mode 100644 deps/linux-amd64/libffi.a create mode 100644 deps/linux-arm64/libffi.a create mode 100644 include/con4m/datatypes/ffi.h create mode 100644 include/con4m/datatypes/ufi.h create mode 100644 include/con4m/ffi.h create mode 100644 src/con4m/ffi.c create mode 100644 tests/basic15.c4m create mode 100644 tests/basic16.c4m diff --git a/.gitignore b/.gitignore index 3b2042ce..268fa4ce 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ subprojects/*/ .meson_last .vscode .cache +deps/local diff --git a/deps/Darwin-arm64/libffi.a b/deps/Darwin-arm64/libffi.a new file mode 100644 index 0000000000000000000000000000000000000000..d0b7331e840eaa7ea816530b3995fe4e5258991a GIT binary patch literal 53368 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 L^4~(9E%v_w@`96r literal 0 HcmV?d00001 diff --git a/deps/linux-amd64/libffi.a b/deps/linux-amd64/libffi.a new file mode 100644 index 0000000000000000000000000000000000000000..8811b7ab7f0b80b368740535cfef7a075afd0a43 GIT binary patch literal 92326 zcmdSC3w%`7xi`Egi7;Hu9u<|gwhT3DQZ*z>DI-)fkiZ_82*^b(+7LqmD3F-UC|0b% z%z(SYXnJaUJgx2PIj=pXt#4~vEodz!fCNwx!3$n$Bi=H`3tkEVFM0pZTI-ovSHq8PtF{ob<7-(R*{R-T{dlpkAv_gA~w z^5pu}J#Trkzow=obuF!pEp-h`n(7*wTN^DM8SqedU45$tENyO!D)L2*k-D}>YqTL! z*WA?9));9Mbdeic8o_f}%hJXbbxWI61lfk?abvUeQRA83pMT!K_xdxvuN*hAQJ)#ZpisUfLGUFS1+hD zfo2dhWbqmrTITIw2CG&a;VEl~!+(LnrEL>AUZ>M8mS z%?lgr^n_&6rq)JfOs)0cx1^0Mxvg=zG6x3RqAe}Wt&v8lc_bo!iu!46MddhIQ7ssHb4_?kfyaZ&NIH*op_P4N6k!a{ z-dBm+D(iS_xaB1J?f78$2+j@8nLFEYKXGDjdBe$OUv1)TJH7^_q2!g8(>0hpHFZt( zTJZCN9e;t|xF1&Ttn6@N6Rb$By>YhJ>EGc#)4$7U*y{}0m_e=9GAw+*&Uf3bHV93b{{3|4@0zasS#=*Wcft=!ndBV%xkA zQmp2?d#(xjD1`!UQkK6c`2cc)5G#OEyjI_C^Gs ztg+JHgb#a^wTXh++SD$BtL*4~tf{Ho9u)_O*lV|pePDm(=-k<7rg9n({%ZS5^?55=~6 zLjmab4}fcv!$L`qljw-{gpx~qPU7uIeHg+v1-pVshg#@nR^`s#0OStZ8)qJ){*dbl z6(HMa~Pw##_;Cm50J^SI_&O2xS+Of`k_4UkN>cZ^#QFdVkhr zk3xG#Xf>l#V)6uwoT!BggI$wGLUN(zu>0)%E7SDU)J|bM(Q~T^!;Tk%viC>!s479X zsQ@GtS|0sEyU?t?t^!J(I~yv6u17l1E~$2^*S)mJ(KSmUCidF#owx?wC!yFKy~l@Q z9nkB3*6YYnvQX*u8rEwq>2rP#-vvTOQFjVMay~2Q`UZ+E^J40?E={2DA`b5u< zKhEfN9vsbDn&N+I&z?19rp=$PRa0|^F%mF+}iO^K81d7CH)HB4$y2? z$@HG=H#mg)6-D;TL%Og>L<$2}jmsgxy85NI}-#zcV@`|x#3bw2wXuyZxarjNWc&>#arGqd^ zYH}mw#qxaT63er~=lRm`!QOTl`4zxLiHz%LJX_O?eW`*;#Us}j28;b`i-N_avE!x| zR}}nUXmRP3V*ljgk&}vjlZw5QhTQ~YaGuihXMf;3rl%wb);9 z{}l!IoBp?g!S-VB)L{!q7S#Lj@-caan@9c;+N~77RNMYdQzOiQsb= z)lG0h_qfi*k8ojdxEDIbwF$pme6GubCx8>51!S;rtfwF0J{O-~11I`bieBiDJZ2h? z4c3z7OCn3^m!czBSHEacYvZE&h-|$x&9PnbI=#oiWTKtQ51D>?ro*duV6z=$Nw0M@ zbRg56%+a@}NLbcaDYL?ny2%(&nF)8d!s$X$XMD3pKSaaNR{AmNuTtq~;t#3WK{kSJb>=aA!yh{9M@hW9!9R|+!L?%Qo!$-v@V&H5aw-`9vfmPmi!!mS^aE-Le z>teoZZCqMk9%)<=vC66UYn5Ns)@GGssAC!RYRi{5M;gmfR-W4ysc*POJug}wEpKT> zx4JcQgHm1w>&(G_>5`Kwi1%A5Y@QJ_fIDEcd zfR}u)(+w8=GaZrlChau9M5@~^QF@hsKRsxU^~cavxFMdV|5D}uE+atG|CR8YEB#t1 zlfkvii%386%l4HF^=gTfiEBsj`4SKPxPw@gkziB;$kl0~n}D#Tk^E)dRiGY#CYp7}z2^b(5w5w4efe&vDi0VV3+X~Q1Vd=*VnYR*#Q zw7j*s9J3(xOI1@fgEQDH8@`{R&8uYmuUx2&N^vxslvR0{60Pn=r8Ra@n@L$6a2*vVW$3n#ZnhS(0gG|D!hc`GIknRUQBAeA*_h0IL$B$Tl{O=O!;L z!u(ZohPQv$4WoOAA4K+i@WpX=`iXqt;z=x(=iD?M}lWfxE%J-UE;)nSIPmoCW?J@Bf&6{1ce;zxDZ9mm<55QcU)vsFz`}>`;_nlbxK_~E3U8!LIi1}_A$MzN^(z$1aM?>v;KN)o{BS@F?L<4`9Zp?QVuzAdnCN)r zU}9(F3dhqGcAx7VV~<*e*B0lW6EgV+#y2qk%sKDa{BvF=uaU93*UJ0@#$k7Fm}bnn zlrn4jvdZ)AgdGcgHMOT{N<=CxqaRGfV-g&5@sB&HlYfmV)3Dp=xE~2Bq?kACHjH=N zYpN($=s7hrpO^6uMUxIwCpUsiUKSMpf7<;w_YL#S%TS$4a|YyQ$ct!?a-F(JVH0ts z`ktH^6BqLvHJSMh%uew9#$scBV-gkNrTE3kGu&}hk%;-3$;S_xdTU{-X#H`R7kO}J<~ztE9H+(ExEJ#m z0<|nokBb!Et#F>Fn2l#jQ`3D5KrZ|m;Kbjr8WKX^z*gj;U#;k?R2xI+9@vlb(EnD^ zuTu0v|G+G6JjmWDmLV-~TZ(yHk+A93;Y#SoFJBlbc>J zez(FYF60>JHad^&F}_~Wv&}KSO5t1{G0yWb+&5voN6~W`#rRta_X}yV@+?+(iGjbW za8VX$^7H(u$wzs&*j_o@1?q*Pu8eo9=UWV1C<@qp2G03yzkzeUDpK+?f6hOjeI815 z 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 literal 0 HcmV?d00001 diff --git a/deps/linux-arm64/libffi.a b/deps/linux-arm64/libffi.a new file mode 100644 index 0000000000000000000000000000000000000000..b0112f1a2abd7d2cc6cae02a5d2bf3c74b1a6ca6 GIT binary patch literal 111720 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 F{~xXCY}5b% literal 0 HcmV?d00001 diff --git a/dev b/dev index 3fa74c1d..15277e60 100755 --- a/dev +++ b/dev @@ -20,6 +20,9 @@ function color { } OS=$(uname -o 2>/dev/null) +ARCH=$(uname -m 2>/dev/null) +PWD=$(pwd) + if [[ $? -ne 0 ]] ; then # Older macOS/OSX versions of uname don't support -o OS=$(uname -s) @@ -32,6 +35,8 @@ function log { function meson_build { echo ${1} > .meson_last + rm deps/local 2>/dev/null + ln -s ${PWD}/deps/${OS}-${ARCH} ${PWD}/deps/local if [[ ! -d ${1} ]]; then diff --git a/include/compiler/datatypes/error.h b/include/compiler/datatypes/error.h index 989cee89..3fb1c482 100644 --- a/include/compiler/datatypes/error.h +++ b/include/compiler/datatypes/error.h @@ -173,6 +173,9 @@ typedef enum { c4m_err_augmented_assign_to_slice, c4m_warn_cant_export, c4m_err_assigned_void, + c4m_err_callback_no_match, + c4m_err_callback_bad_target, + c4m_err_callback_type_mismatch, c4m_err_last, } c4m_compile_error_t; diff --git a/include/compiler/datatypes/file.h b/include/compiler/datatypes/file.h index 3684a189..25d45b65 100644 --- a/include/compiler/datatypes/file.h +++ b/include/compiler/datatypes/file.h @@ -46,6 +46,8 @@ typedef struct c4m_file_compile_ctx { c4m_xlist_t *fn_def_syms; // Cache of fns defined. c4m_zmodule_info_t *module_object; c4m_xlist_t *call_patch_locs; + c4m_xlist_t *callback_literals; + c4m_xlist_t *extern_decls; int32_t static_size; uint32_t num_params; uint16_t local_module_id; diff --git a/include/compiler/datatypes/nodeinfo.h b/include/compiler/datatypes/nodeinfo.h index 942d2981..f5798f3a 100644 --- a/include/compiler/datatypes/nodeinfo.h +++ b/include/compiler/datatypes/nodeinfo.h @@ -1,69 +1,6 @@ #pragma once #include "con4m.h" -typedef struct { - c4m_utf8_t *litmod; - c4m_lit_syntax_t st; - c4m_type_t *cast_to; - c4m_builtin_t base_type; // only set for containers from here down. - int num_items; - c4m_type_t *type; -} c4m_lit_info_t; - -typedef struct { - c4m_type_t *full_type; - c4m_scope_t *fn_scope; - c4m_scope_t *formals; - c4m_fn_param_info_t *param_info; - c4m_fn_param_info_t return_info; - int num_params; - unsigned int pure : 1; - unsigned int void_return : 1; -} c4m_sig_info_t; - -typedef struct { - c4m_utf8_t *short_doc; - c4m_utf8_t *long_doc; - c4m_sig_info_t *signature_info; - struct c4m_cfg_node_t *cfg; - int32_t frame_size; - // sc = 'short circuit' - // If we are a 'once' function, this is the offset into static data, - // where we will place: - // - // - A boolean. - // - A pthread_mutex_t - // - A void * - // - // The idea is, if the boolean is true, we only ever read and - // return the cached (memoized) result, stored in the void *. If - // it's false, we grab the lock, check the boolean a second time, - // run thecm function, set the memo and the boolean, and then - // unlock. - int32_t sc_lock_offset; - int32_t sc_bool_offset; - int32_t sc_memo_offset; - int32_t local_id; - int32_t offset; - int32_t module_id; - - unsigned int private : 1; - unsigned int once : 1; -} c4m_fn_decl_t; - -typedef struct { - c4m_utf8_t *short_doc; - c4m_utf8_t *long_doc; - c4m_utf8_t *local_name; - c4m_sig_info_t *local_params; - int num_params; - c4m_utf8_t *external_name; - uint8_t *external_params; - uint8_t external_return_type; - int holds; - int allocs; -} c4m_ffi_decl_t; - // This data structure is the first bytes of the extra_info field for anything // that might be a jump target, including loops, conditionals, case statements, // etc. diff --git a/include/compiler/datatypes/scope.h b/include/compiler/datatypes/scope.h index 02237fc6..88e0f798 100644 --- a/include/compiler/datatypes/scope.h +++ b/include/compiler/datatypes/scope.h @@ -51,16 +51,6 @@ typedef struct { c4m_utf8_t *specified_uri; } c4m_module_info_t; -// For extern entries, the data structure will be in the `value` -// field. - -typedef struct { - c4m_utf8_t *name; - c4m_type_t *type; - unsigned int ffi_holds : 1; - unsigned int ffi_allocs : 1; -} c4m_fn_param_info_t; - typedef struct c4m_scope_entry_t { // The `value` field gets the proper value for vars and enums, but // for other types, it gets a pointer to one of the specific data diff --git a/include/compiler/parse.h b/include/compiler/parse.h index eee7c1a8..f04d1a52 100644 --- a/include/compiler/parse.h +++ b/include/compiler/parse.h @@ -109,6 +109,7 @@ typedef struct pass1_ctx { c4m_file_compile_ctx *file_ctx; c4m_scope_t *static_scope; bool in_func; + c4m_xlist_t *extern_decls; } pass1_ctx; static inline c4m_tree_node_t * diff --git a/include/con4m.h b/include/con4m.h index e2451c1f..d929c758 100644 --- a/include/con4m.h +++ b/include/con4m.h @@ -103,3 +103,5 @@ #include "compiler/codegen.h" #include "con4m/set.h" + +#include "con4m/ffi.h" diff --git a/include/con4m/datatypes.h b/include/con4m/datatypes.h index 9b85f312..2c86d8f3 100644 --- a/include/con4m/datatypes.h +++ b/include/con4m/datatypes.h @@ -5,8 +5,8 @@ typedef struct hatrack_set_st c4m_set_t; #include "con4m/datatypes/box.h" #include "con4m/datatypes/memory.h" #include "con4m/datatypes/kargs.h" -#include "con4m/datatypes/literals.h" #include "con4m/datatypes/objects.h" +#include "con4m/datatypes/literals.h" #include "con4m/datatypes/colors.h" #include "con4m/datatypes/codepoints.h" #include "con4m/datatypes/styles.h" @@ -23,14 +23,16 @@ typedef struct hatrack_set_st c4m_set_t; #include "con4m/datatypes/exceptions.h" #include "con4m/datatypes/mixed.h" #include "con4m/datatypes/tuples.h" -#include "con4m/datatypes/callbacks.h" #include "con4m/datatypes/streams.h" #include "con4m/datatypes/format.h" -#include "con4m/datatypes/vm.h" #include "compiler/datatypes/lex.h" #include "compiler/datatypes/error.h" #include "compiler/datatypes/parse.h" #include "compiler/datatypes/scope.h" +#include "con4m/datatypes/ffi.h" +#include "con4m/datatypes/ufi.h" +#include "con4m/datatypes/vm.h" +#include "con4m/datatypes/callbacks.h" #include "compiler/datatypes/nodeinfo.h" #include "compiler/datatypes/spec.h" #include "compiler/datatypes/cfg.h" diff --git a/include/con4m/datatypes/callbacks.h b/include/con4m/datatypes/callbacks.h index 993aa70c..e8eea3ec 100644 --- a/include/con4m/datatypes/callbacks.h +++ b/include/con4m/datatypes/callbacks.h @@ -1,54 +1,11 @@ #pragma once - -typedef enum { - FFI_ABI_0 = 0, - FFI_ABI_1 = 1, - FFI_ABI_2 = 2, -} c4m_ffi_abi; - -typedef struct _c4m_ffi_type { - size_t size; - unsigned short alignment; - unsigned short type; - struct _c4m_ffi_type **elements; -} c4m_ffi_type; - -typedef enum { - FFI_OK = 0, - FFI_BAD_TYPEDEF, - FFI_BAD_ABI -} c4m_ffi_status; - -typedef struct { - c4m_ffi_abi abi; - unsigned nargs; - c4m_ffi_type **arg_types; - c4m_ffi_type *rtype; - unsigned bytes; - unsigned flags; -} c4m_ffi_cif; - #include "con4m.h" typedef struct { - c4m_ffi_cif call_interface; - c4m_ffi_abi abi; - c4m_ffi_type return_type; - unsigned int fixedargs; - c4m_ffi_type *arg_types; -} c4m_ffi_info_t; - -typedef struct { - void *fn; // Can point into the VM or to ELF fn - c4m_ffi_info_t *ffi; - c4m_type_t *type; - char *name; - uint8_t flags; -} c4m_funcinfo_t; - -typedef struct { - c4m_funcinfo_t *info; // Shared when possible. - bool bound; + c4m_utf8_t *target_symbol_name; + c4m_type_t *target_type; + c4m_funcinfo_t binding; + c4m_tree_node_t *decl_loc; } c4m_callback_t; #define C4M_CB_FLAG_FFI 1 diff --git a/include/con4m/datatypes/ffi.h b/include/con4m/datatypes/ffi.h new file mode 100644 index 00000000..7a84e0ca --- /dev/null +++ b/include/con4m/datatypes/ffi.h @@ -0,0 +1,98 @@ +#pragma once +#include "con4m.h" + +// For the foreign function interface, it's easier to redeclare +// libffi's structures than to deal w/ ensuring we have the right .h +// on each architecture. The only thing we need that might be +// different on different platforms is the ABI; hopefully +// FFI_DEFAUL T_ABI is the same everywhere, but if it isn't, that's +// easier to deal with than the header file situation. +// + +typedef enum { + C4M_FFI_FIRST_ABI = 0, + C4M_FFI_DEFAULT_ABI, + C4M_FFI_LAST_ABI, +} c4m_ffi_abi; + +// This is libffi's `ffi_type`. +typedef struct c4m_ffi_type { + size_t size; + unsigned short alignment; + unsigned short ffitype; + struct c4m_ffi_type **elements; +} c4m_ffi_type; + +// This is libffi's `ffi_cif` type. +typedef struct { + c4m_ffi_abi abi; + unsigned nargs; + c4m_ffi_type **arg_types; + c4m_ffi_type *rtype; + unsigned bytes; + unsigned flags; + // Currently, no platform in libffi takes more than two 'unsigned int's + // worth of space, so only one of these should be necessary, but + // adding an extra one just in case; enough platforms take two fields + // that I can see there eventually being a platform w/ 2 64-bit slots. + // We alloc ourselves based on this size, so no worries there. + uint64_t extra_cif1; + uint64_t extra_cif2; +} c4m_ffi_cif; + +typedef struct { + void *fptr; + c4m_utf8_t *local_name; + c4m_utf8_t *extern_name; + uint64_t str_convert; + uint64_t hold_info; + uint64_t alloc_info; + c4m_ffi_cif cif; + c4m_ffi_type **args; + c4m_ffi_type *ret; +} c4m_zffi_cif; + +typedef enum { + C4M_FFI_OK = 0, + C4M_FFI_BAD_TYPEDEF, + C4M_FFI_BAD_ABI, + C4M_FFI_BAD_ARGTYPE +} c4m_ffi_status; + +typedef struct c4m_ffi_decl_t { + c4m_utf8_t *short_doc; + c4m_utf8_t *long_doc; + c4m_utf8_t *local_name; + struct c4m_sig_info_t *local_params; + int num_ext_params; + int global_ffi_call_ix; + c4m_utf8_t *external_name; + uint8_t *external_params; + uint8_t external_return_type; + c4m_xlist_t *dll_list; + c4m_zffi_cif cif; +} c4m_ffi_decl_t; + +extern c4m_ffi_type ffi_type_void; +extern c4m_ffi_type ffi_type_uint8; +extern c4m_ffi_type ffi_type_sint8; +extern c4m_ffi_type ffi_type_uint16; +extern c4m_ffi_type ffi_type_sint16; +extern c4m_ffi_type ffi_type_uint32; +extern c4m_ffi_type ffi_type_sint32; +extern c4m_ffi_type ffi_type_uint64; +extern c4m_ffi_type ffi_type_sint64; +extern c4m_ffi_type ffi_type_float; +extern c4m_ffi_type ffi_type_double; +extern c4m_ffi_type ffi_type_pointer; + +#define ffi_type_uchar ffi_type_uint8 +#define ffi_type_schar ffi_type_sint8 +#define ffi_type_ushort ffi_type_uint16 +#define ffi_type_sshort ffi_type_sint16 +#define ffi_type_ushort ffi_type_uint16 +#define ffi_type_sshort ffi_type_sint16 +#define ffi_type_uint ffi_type_uint32 +#define ffi_type_sint ffi_type_sint32 +#define ffi_type_ulong ffi_type_uint64 +#define ffi_type_slong ffi_type_sint64 diff --git a/include/con4m/datatypes/literals.h b/include/con4m/datatypes/literals.h index ebafb7ff..dc239963 100644 --- a/include/con4m/datatypes/literals.h +++ b/include/con4m/datatypes/literals.h @@ -13,3 +13,12 @@ typedef enum { ST_Tuple = 8, ST_MAX = 9 } c4m_lit_syntax_t; + +typedef struct { + struct c4m_str_t *litmod; + c4m_lit_syntax_t st; + struct c4m_type_t *cast_to; + c4m_builtin_t base_type; // only set for containers from here down. + struct c4m_type_t *type; + int num_items; +} c4m_lit_info_t; diff --git a/include/con4m/datatypes/memory.h b/include/con4m/datatypes/memory.h index 243a3de2..872f0069 100644 --- a/include/con4m/datatypes/memory.h +++ b/include/con4m/datatypes/memory.h @@ -74,6 +74,7 @@ typedef struct c4m_finalizer_info_t { typedef struct c4m_arena_t { c4m_alloc_hdr *next_alloc; c4m_dict_t *roots; + c4m_set_t *external_holds; // queue_t *late_mutations; uint64_t *heap_end; c4m_finalizer_info_t *to_finalize; diff --git a/include/con4m/datatypes/strings.h b/include/con4m/datatypes/strings.h index 476de97b..bf688283 100644 --- a/include/con4m/datatypes/strings.h +++ b/include/con4m/datatypes/strings.h @@ -6,7 +6,7 @@ ** NOT to distinguish whether strings are UTF-8 (the high bit will ** always be 0 with UTF-8). **/ -typedef struct { +typedef struct c4m_str_t { // clang-format off alignas(8) int32_t codepoints; diff --git a/include/con4m/datatypes/ufi.h b/include/con4m/datatypes/ufi.h new file mode 100644 index 00000000..92f6f808 --- /dev/null +++ b/include/con4m/datatypes/ufi.h @@ -0,0 +1,60 @@ +#pragma once +#include "con4m.h" + +typedef struct { + c4m_utf8_t *name; + c4m_type_t *type; + unsigned int ffi_holds : 1; + unsigned int ffi_allocs : 1; +} c4m_fn_param_info_t; + +typedef struct c4m_sig_info_t { + c4m_type_t *full_type; + c4m_fn_param_info_t *param_info; + c4m_fn_param_info_t return_info; + int num_params; + unsigned int pure : 1; + unsigned int void_return : 1; + c4m_scope_t *fn_scope; + c4m_scope_t *formals; +} c4m_sig_info_t; + +typedef struct { + c4m_utf8_t *short_doc; + c4m_utf8_t *long_doc; + c4m_sig_info_t *signature_info; + struct c4m_cfg_node_t *cfg; + int32_t frame_size; + // sc = 'short circuit' + // If we are a 'once' function, this is the offset into static data, + // where we will place: + // + // - A boolean. + // - A pthread_mutex_t + // - A void * + // + // The idea is, if the boolean is true, we only ever read and + // return the cached (memoized) result, stored in the void *. If + // it's false, we grab the lock, check the boolean a second time, + // run thecm function, set the memo and the boolean, and then + // unlock. + int32_t sc_lock_offset; + int32_t sc_bool_offset; + int32_t sc_memo_offset; + int32_t local_id; + int32_t offset; + int32_t module_id; + + unsigned int private : 1; + unsigned int once : 1; +} c4m_fn_decl_t; + +typedef struct c4m_funcinfo_t { + union { + c4m_ffi_decl_t *ffi_interface; + c4m_fn_decl_t *local_interface; + } implementation; + + unsigned int ffi : 1; + unsigned int va : 1; +} c4m_funcinfo_t; diff --git a/include/con4m/datatypes/vm.h b/include/con4m/datatypes/vm.h index b597d7cd..71d78539 100644 --- a/include/con4m/datatypes/vm.h +++ b/include/con4m/datatypes/vm.h @@ -407,36 +407,15 @@ typedef union c4m_stack_value_t { void *vptr; uint64_t uint; int64_t sint; // signed int values. + c4m_box_t box; double dbl; bool boolean; char *cptr; union c4m_stack_value_t *fp; // saved fp } c4m_stack_value_t; -typedef struct { - // whether passing a pointer to the thing causes it to hold the pointer, - // in which case decref must be explicit. - bool held; - // this passes a value back that was allocated in the FFI. - bool alloced; - // an index into the CTypeNames data structure in ffi.nim. - int16_t arg_type; - // To look up any FFI processing we do for the type. - int32_t our_type; - c4m_str_t *name; -} c4m_zffi_arg_info_t; - -typedef struct { - int64_t nameoffset; - int64_t localname; - int32_t mid; // module_id - c4m_type_t *tid; - bool va; - c4m_xlist_t *dlls; // int64_t - c4m_xlist_t *arg_info; // tspec_ref: c4m_zffi_arg_info_t - c4m_str_t *shortdoc; - c4m_str_t *longdoc; -} c4m_zffi_info_t; +// Might want to trim a bit out of it, but for right now, an going to not. +typedef struct c4m_ffi_decl_t c4m_zffi_info_t; typedef struct { int64_t offset; @@ -555,6 +534,8 @@ typedef struct { c4m_dict_t *attrs; // string, c4m_attr_contents_t (tspec_ref) c4m_set_t *all_sections; // string c4m_dict_t *section_docs; // string, c4m_docs_container_t (tspec_ref) + c4m_xlist_t *ffi_info; + int ffi_info_entries; bool using_attrs; } c4m_vm_t; diff --git a/include/con4m/ffi.h b/include/con4m/ffi.h new file mode 100644 index 00000000..92fde203 --- /dev/null +++ b/include/con4m/ffi.h @@ -0,0 +1,22 @@ +#pragma once +#include "con4m.h" + +extern void c4m_add_static_function(c4m_utf8_t *, void *); +extern void *c4m_ffi_find_symbol(c4m_utf8_t *, c4m_xlist_t *); +extern int64_t c4m_lookup_ctype_id(char *); +extern c4m_ffi_type *c4m_ffi_arg_type_map(uint8_t); +extern void *c4m_ref_via_ffi_type(c4m_box_t *, c4m_ffi_type *); +extern c4m_ffi_status ffi_prep_cif(c4m_ffi_cif *, + c4m_ffi_abi, + unsigned int, + c4m_ffi_type *, + c4m_ffi_type **); +extern c4m_ffi_status ffi_prep_cif_var(c4m_ffi_cif *, + c4m_ffi_abi, + unsigned int, + unsigned int, + c4m_ffi_type *, + c4m_ffi_type **); +extern void ffi_call(c4m_ffi_cif *, void *, void *, void **); + +#define C4M_CSTR_CTYPE_CONST 24 diff --git a/include/con4m/gc.h b/include/con4m/gc.h index 16517c22..b4a90b75 100644 --- a/include/con4m/gc.h +++ b/include/con4m/gc.h @@ -181,6 +181,8 @@ c4m_gc_malloc(size_t len) extern void c4m_get_stack_scan_region(uint64_t *top, uint64_t *bottom); extern void c4m_initialize_gc(); extern void c4m_gc_heap_stats(uint64_t *, uint64_t *, uint64_t *); +extern void c4m_gc_add_hold(c4m_obj_t); +extern void c4m_gc_remove_hold(c4m_obj_t); extern c4m_arena_t *c4m_internal_stash_heap(); extern void c4m_internal_unstash_heap(); extern void c4m_internal_set_heap(c4m_arena_t *); diff --git a/include/con4m/math.h b/include/con4m/math.h index ffdfd67b..ca5c64a5 100644 --- a/include/con4m/math.h +++ b/include/con4m/math.h @@ -1,6 +1,8 @@ // Random math stuff #include "con4m.h" +extern uint64_t c4m_clz(uint64_t); + static inline uint64_t c4m_int_log2(uint64_t n) { diff --git a/include/con4m/stream.h b/include/con4m/stream.h index 4e58618e..f493d630 100644 --- a/include/con4m/stream.h +++ b/include/con4m/stream.h @@ -159,6 +159,7 @@ c4m_file_iostream(c4m_str_t *filename, bool no_create) c4m_stream_t *c4m_get_stdin(); c4m_stream_t *c4m_get_stdout(); c4m_stream_t *c4m_get_stderr(); +void c4m_init_std_streams(); static inline bool c4m_stream_using_cookie(c4m_stream_t *s) diff --git a/meson.build b/meson.build index bf3336c1..c654c759 100644 --- a/meson.build +++ b/meson.build @@ -94,6 +94,7 @@ c4m_src = ['src/con4m/style.c', 'src/con4m/path.c', 'src/con4m/flags.c', 'src/con4m/box.c', + 'src/con4m/ffi.c', 'src/con4m/crypto/sha.c', 'src/con4m/compiler/compile.c', 'src/con4m/compiler/lex.c', @@ -165,7 +166,7 @@ test_src = ['src/tests/test.c'] threads = dependency('threads') math = cc.find_library('m', required : false) -ffi = cc.find_library('ffi') +ffi = cc.find_library('ffi', required : true, dirs: meson.current_source_dir() + '/deps/local/') crypto = cc.find_library('crypto') ssl = cc.find_library('ssl') diff --git a/src/con4m/callback.c b/src/con4m/callback.c index 2be8ee77..a6f439e0 100644 --- a/src/con4m/callback.c +++ b/src/con4m/callback.c @@ -1,73 +1,24 @@ #include "con4m.h" -static c4m_dict_t *bound_functions = NULL; +// At least for the time being, we will statically ensure that there +// is a function in the compilation context with the right name and +// signature. For extern stuff, we will not attempt to bind until +// runtime. +// +// Eventually (when we go the REPL) we might want to revise this +// depending on how hot reloading is handled for bindings. +// +// To that end, all callback objects should currently be statically +// bound and unmarshaled from const space. static void callback_init(c4m_callback_t *cb, va_list args) { - c4m_type_t *type = NULL; - void *address = NULL; - c4m_str_t *symbol_name = NULL; - c4m_xlist_t *libraries = NULL; // of c4m_str_t - int32_t static_link = 0; - bool ffi = false; - // bool bind_now = false; + c4m_str_t *symbol_name = va_arg(args, c4m_utf8_t *); + c4m_type_t *type = va_arg(args, c4m_type_t *); - c4m_karg_va_init(args); - c4m_kw_ptr("type", type); - c4m_kw_ptr("address", address); - c4m_kw_ptr("symbol_name", symbol_name); - c4m_kw_int32("static_linking", static_link); - c4m_kw_bool("ffi", ffi); - // c4m_kw_bool("bind_now", bind_now); - - c4m_funcinfo_t *info = NULL; - - if (bound_functions == NULL) { - bound_functions = c4m_new(c4m_tspec_dict(c4m_tspec_ref(), - c4m_tspec_ref())); - c4m_gc_register_root(&bound_functions, 1); - } - - if (address == NULL) { - if (!symbol_name) { - C4M_CRAISE("Not enough information for callback."); - } - - address = dlsym(RTLD_DEFAULT, symbol_name->data); - - if (!address && libraries != NULL) { - for (int i = 0; i < c4m_xlist_len(libraries); i++) { - c4m_utf8_t *s = c4m_to_utf8(c4m_xlist_get(libraries, i, NULL)); - address = dlopen(s->data, RTLD_NOW | RTLD_GLOBAL); - - if (address != NULL) { - break; - } - } - } - } - - if (address != NULL) { - info = hatrack_dict_get(bound_functions, address, NULL); - } - - if (info == NULL) { - info = c4m_gc_alloc(c4m_funcinfo_t); - info->fn = address; - info->name = symbol_name->data; - info->type = type; - - if (ffi) { - info->flags = C4M_CB_FLAG_FFI; - } - - if (static_link) { - info->flags |= C4M_CB_FLAG_STATIC; - } - } - - cb->info = info; + cb->target_symbol_name = c4m_to_utf8(symbol_name); + cb->target_type = type; } const c4m_vtable_t c4m_callback_vtable = { diff --git a/src/con4m/compiler/ast_utils.c b/src/con4m/compiler/ast_utils.c index c89adea5..2c67665b 100644 --- a/src/con4m/compiler/ast_utils.c +++ b/src/con4m/compiler/ast_utils.c @@ -209,11 +209,10 @@ node_to_callback(c4m_file_compile_ctx *ctx, c4m_tree_node_t *n) c4m_utf8_t *name = node_text(c4m_tree_get_child(n, 0)); c4m_type_t *type = c4m_node_to_type(ctx, c4m_tree_get_child(n, 1), NULL); - return c4m_new(c4m_tspec_callback(), - c4m_kw("symbol_name", - c4m_ka(name), - "type", - c4m_ka(type))); + c4m_callback_t *result = c4m_new(c4m_tspec_callback(), name, type); + result->decl_loc = n; + + return result; } c4m_type_t * diff --git a/src/con4m/compiler/check_pass.c b/src/con4m/compiler/check_pass.c index aaca9a5f..8028a5e2 100644 --- a/src/con4m/compiler/check_pass.c +++ b/src/con4m/compiler/check_pass.c @@ -1911,6 +1911,7 @@ check_literal(pass2_ctx *ctx) break; case c4m_nt_lit_callback: pnode->value = node_to_callback(ctx->file_ctx, ctx->node); + c4m_xlist_append(ctx->file_ctx->callback_literals, pnode->value); break; case c4m_nt_lit_tspec: do { @@ -2838,6 +2839,93 @@ process_deferred_calls(c4m_compile_ctx *cctx, } } +static void +process_deferred_callbacks(c4m_compile_ctx *cctx) +{ + // Now that we have a 'whole program view', go ahead and + // try to find a match for any callback literals used. + // + // Meaning, there must either be an in-scope con4m function, or + // an extern declaration that matches the callback, as viewed from + // the module in which the symbol was declared. + + int n = c4m_xlist_len(cctx->module_ordering); + c4m_utf8_t *s; + + for (int i = 0; i < n; i++) { + c4m_file_compile_ctx *f = c4m_xlist_get(cctx->module_ordering, i, NULL); + int m = c4m_xlist_len(f->callback_literals); + for (int j = 0; j < m; j++) { + c4m_callback_t *cb = c4m_xlist_get(f->callback_literals, j, NULL); + + c4m_scope_entry_t *sym = c4m_symbol_lookup(NULL, + f->module_scope, + f->global_scope, + NULL, + cb->target_symbol_name); + + if (!sym) { + c4m_add_error(f, c4m_err_callback_no_match, cb->decl_loc); + return; + } + + switch (sym->kind) { + case sk_func: + cb->binding.ffi = 0; + cb->binding.implementation.ffi_interface = sym->value; + break; + case sk_extern_func: + cb->binding.ffi = 1; + cb->binding.implementation.local_interface = sym->value; + break; + default:; + c4m_tree_node_t *l = sym->declaration_node; + if (l == NULL) { + l = c4m_xlist_get(sym->sym_defs, 0, NULL); + } + s = c4m_node_get_loc_str(l); + c4m_add_error(f, c4m_err_callback_bad_target, cb->decl_loc, s); + return; + } + + c4m_type_t *sym_type = c4m_global_copy(sym->type); + c4m_type_t *lit_type = cb->target_type; + c4m_type_t *merged = c4m_merge_types(sym_type, lit_type); + + if (c4m_tspec_is_error(merged)) { + s = c4m_node_get_loc_str(sym->declaration_node); + c4m_add_error(f, + c4m_err_callback_type_mismatch, + cb->decl_loc, + lit_type, + sym_type, + s); + } + } + } +} + +static void +order_ffi_decls(c4m_compile_ctx *cctx) +{ + // TODO: when incrementally compiling we need to take into + // acount existing FFI decl indexing. + int n = c4m_xlist_len(cctx->module_ordering); + int ix = 0; + + for (int i = 0; i < n; i++) { + c4m_file_compile_ctx *f = c4m_xlist_get(cctx->module_ordering, i, NULL); + int m = c4m_xlist_len(f->extern_decls); + + for (int j = 0; j < m; j++) { + c4m_scope_entry_t *sym = c4m_xlist_get(f->extern_decls, j, NULL); + c4m_ffi_decl_t *decl = (c4m_ffi_decl_t *)sym->value; + + decl->global_ffi_call_ix = ix++; + } + } +} + void c4m_check_pass(c4m_compile_ctx *cctx) { @@ -2874,7 +2962,9 @@ c4m_check_pass(c4m_compile_ctx *cctx) } } + order_ffi_decls(cctx); process_deferred_calls(cctx, all_deferred, num_deferred); + process_deferred_callbacks(cctx); for (int i = 0; i < n; i++) { c4m_file_compile_ctx *f = c4m_xlist_get(cctx->module_ordering, i, NULL); diff --git a/src/con4m/compiler/codegen.c b/src/con4m/compiler/codegen.c index d8ba6eca..222f282d 100644 --- a/src/con4m/compiler/codegen.c +++ b/src/con4m/compiler/codegen.c @@ -535,7 +535,7 @@ static inline void gen_run_callback(gen_ctx *ctx, c4m_callback_t *cb) { uint32_t offset = c4m_layout_const_obj(ctx->cctx, cb); - c4m_type_t *t = cb->info->type; + c4m_type_t *t = cb->target_type; int nargs = c4m_tspec_get_num_params(t) - 1; c4m_type_t *ret_type = c4m_tspec_get_param(t, nargs); bool useret = !(c4m_tspecs_are_compat(ret_type, @@ -597,6 +597,71 @@ gen_unbox_if_needed(gen_ctx *ctx, } } +static void +gen_native_call(gen_ctx *ctx, c4m_scope_entry_t *fsym) +{ + // Needed to calculate the loc of module variables. + // Currently that's done at runtime, tho could be done in + // a proper link pass in the future. + int target_module; + // Index into the object file's cache. + int target_fn_id; + int loc = ctx->instruction_counter; + // When the call is generated, we might not have generated the + // function we're calling. In that case, we will just generate + // a stub and add the actual call instruction to a backpatch + // list that gets processed at the end of compilation. + // + // To test this reliably, we can check the 'offset' field of + // the function info object, as a function never starts at + // offset 0. + c4m_fn_decl_t *decl = fsym->value; + target_module = decl->module_id; + target_fn_id = decl->local_id; + + emit(ctx, + C4M_Z0Call, + c4m_kw("arg", c4m_ka(target_fn_id), "module_id", target_module)); + + if (target_fn_id == 0) { + call_backpatch_info_t *bp; + + bp = c4m_gc_alloc(call_backpatch_info_t); + bp->decl = decl; + bp->i = c4m_xlist_get(ctx->instructions, loc, NULL); + + c4m_xlist_append(ctx->call_backpatches, bp); + } + + int n = decl->signature_info->num_params; + + if (n != 0) { + emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(-n))); + } + + if (!decl->signature_info->void_return) { + emit(ctx, C4M_ZPushFromR0); + gen_unbox_if_needed(ctx, ctx->cur_node, fsym); + } +} + +static void +gen_extern_call(gen_ctx *ctx, c4m_scope_entry_t *fsym) +{ + c4m_ffi_decl_t *decl = (c4m_ffi_decl_t *)fsym->value; + + emit(ctx, C4M_ZFFICall, c4m_kw("arg", c4m_ka(decl->global_ffi_call_ix))); + + if (decl->num_ext_params != 0) { + emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(-decl->num_ext_params))); + } + + if (!decl->local_params->void_return) { + emit(ctx, C4M_ZPushFromR0); + gen_unbox_if_needed(ctx, ctx->cur_node, fsym); + } +} + static void gen_call(gen_ctx *ctx) { @@ -612,51 +677,10 @@ gen_call(gen_ctx *ctx) } if (fsym->kind != sk_func) { - // emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(-1 * nargs))); + gen_extern_call(ctx, fsym); } else { - // Needed to calculate the loc of module variables. - // Currently that's done at runtime, tho could be done in - // a proper link pass in the future. - int target_module; - // Index into the object file's cache. - int target_fn_id; - int loc = ctx->instruction_counter; - // When the call is generated, we might not have generated the - // function we're calling. In that case, we will just generate - // a stub and add the actual call instruction to a backpatch - // list that gets processed at the end of compilation. - // - // To test this reliably, we can check the 'offset' field of - // the function info object, as a function never starts at - // offset 0. - c4m_fn_decl_t *decl = fsym->value; - target_module = decl->module_id; - target_fn_id = decl->local_id; - - emit(ctx, - C4M_Z0Call, - c4m_kw("arg", c4m_ka(target_fn_id), "module_id", target_module)); - - if (target_fn_id == 0) { - call_backpatch_info_t *bp; - - bp = c4m_gc_alloc(call_backpatch_info_t); - bp->decl = decl; - bp->i = c4m_xlist_get(ctx->instructions, loc, NULL); - - c4m_xlist_append(ctx->call_backpatches, bp); - } - - n = decl->signature_info->num_params; - - if (n != 0) { - emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(-n))); - } - if (!decl->signature_info->void_return) { - emit(ctx, C4M_ZPushFromR0); - gen_unbox_if_needed(ctx, ctx->cur_node, fsym); - } + gen_native_call(ctx, fsym); } } @@ -2034,6 +2058,18 @@ gen_module_code(gen_ctx *ctx, c4m_vm_t *vm) gen_function(ctx, sym, module, vm); } + int l = c4m_xlist_len(ctx->fctx->extern_decls); + if (l != 0) { + for (int j = 0; j < l; j++) { + c4m_scope_entry_t *d = c4m_xlist_get(ctx->fctx->extern_decls, + j, + NULL); + c4m_ffi_decl_t *decl = d->value; + + c4m_xlist_append(vm->obj->ffi_info, decl); + } + } + // Version is not used yet. // Init size not done yet. // datasyms not set yet. diff --git a/src/con4m/compiler/decl_pass.c b/src/con4m/compiler/decl_pass.c index 46571328..337ed988 100644 --- a/src/con4m/compiler/decl_pass.c +++ b/src/con4m/compiler/decl_pass.c @@ -502,10 +502,29 @@ handle_param_block(pass1_ctx *ctx) switch (prop_name->data[0]) { case 'v': - prop->validator = lit; + prop->validator = node_to_callback(ctx->file_ctx, lit); + if (!prop->validator) { + c4m_add_error(ctx->file_ctx, + c4m_err_spec_callback_required, + prop_node); + } + else { + c4m_xlist_append(ctx->file_ctx->callback_literals, + prop->validator); + } + break; case 'c': - prop->callback = lit; + prop->callback = node_to_callback(ctx->file_ctx, lit); + if (!prop->callback) { + c4m_add_error(ctx->file_ctx, + c4m_err_spec_callback_required, + prop_node); + } + else { + c4m_xlist_append(ctx->file_ctx->callback_literals, + prop->callback); + } break; case 'd': prop->default_value = lit; @@ -603,6 +622,7 @@ one_section_prop(pass1_ctx *ctx, } else { section->validator = callback; + c4m_xlist_append(ctx->file_ctx->callback_literals, callback); } break; case 'r': // require @@ -740,6 +760,7 @@ one_field(pass1_ctx *ctx, } else { f->validator = callback; + c4m_xlist_append(ctx->file_ctx->callback_literals, callback); } break; default: @@ -1098,16 +1119,17 @@ handle_func_decl(pass1_ctx *ctx) static void handle_extern_block(pass1_ctx *ctx) { - c4m_ffi_decl_t *info = c4m_gc_alloc(c4m_ffi_info_t); + c4m_ffi_decl_t *info = c4m_gc_alloc(c4m_ffi_decl_t); c4m_utf8_t *external_name = node_text(get_match(ctx, c4m_first_kid_id)); - c4m_xlist_t *ext_params = apply_pattern(ctx, c4m_extern_params); c4m_tree_node_t *ext_ret = get_match(ctx, c4m_extern_return); - c4m_pnode_t *pnode = get_pnode(cur_node(ctx)); + c4m_tree_node_t *cur = cur_node(ctx); c4m_tree_node_t *ext_pure = get_match(ctx, c4m_find_pure); c4m_tree_node_t *ext_holds = get_match(ctx, c4m_find_holds); c4m_tree_node_t *ext_allocs = get_match(ctx, c4m_find_allocs); + c4m_tree_node_t *csig = cur_node(ctx)->children[1]; c4m_tree_node_t *ext_lsig = get_match(ctx, c4m_find_extern_local); + c4m_pnode_t *pnode = get_pnode(cur); if (pnode->short_doc) { info->short_doc = c4m_token_raw_content(pnode->short_doc); @@ -1117,14 +1139,27 @@ handle_extern_block(pass1_ctx *ctx) } } - if (ext_params != NULL) { - int64_t n = c4m_xlist_len(ext_params); - info->num_params = n; - info->external_name = external_name; + for (int i = 2; i < cur->num_kids; i++) { + c4m_pnode_t *kid = get_pnode(cur->children[i]); + + if (kid->kind == c4m_nt_extern_dll) { + if (info->dll_list == NULL) { + info->dll_list = c4m_xlist(c4m_tspec_utf8()); + } + c4m_utf8_t *s = node_text(cur->children[i]->children[0]); + c4m_xlist_append(info->dll_list, s); + } + } + + int64_t n = csig->num_kids - 1; + info->num_ext_params = n; + info->external_name = external_name; + + if (n) { info->external_params = c4m_gc_array_alloc(uint8_t, n); for (int64_t i = 0; i < n; i++) { - c4m_tree_node_t *tnode = c4m_xlist_get(ext_params, i, NULL); + c4m_tree_node_t *tnode = csig->children[i]; c4m_pnode_t *pnode = c4m_tree_get_contents(tnode); uint64_t val = (uint64_t)pnode->extra_info; @@ -1171,11 +1206,13 @@ handle_extern_block(pass1_ctx *ctx) continue; } param->ffi_holds = 1; - uint64_t flag = (uint64_t)(1 << j); - if (bitfield & flag) { - c4m_add_warning(ctx->file_ctx, c4m_warn_dupe_hold, kid); + if (j < 64) { + uint64_t flag = (uint64_t)(1 << j); + if (bitfield & flag) { + c4m_add_warning(ctx->file_ctx, c4m_warn_dupe_hold, kid); + } + bitfield |= flag; } - bitfield |= flag; goto next_i; } c4m_add_error(ctx->file_ctx, c4m_err_bad_hold_name, kid); @@ -1183,6 +1220,7 @@ handle_extern_block(pass1_ctx *ctx) next_i: /* nothing. */; } + info->cif.hold_info = bitfield; } if (ext_allocs) { @@ -1210,11 +1248,15 @@ handle_extern_block(pass1_ctx *ctx) continue; } param->ffi_allocs = 1; - uint64_t flag = (uint64_t)(1 << j); - if (bitfield & flag) { - c4m_add_warning(ctx->file_ctx, c4m_warn_dupe_alloc, kid); + if (j < 63) { + uint64_t flag = (uint64_t)(1 << j); + if (bitfield & flag) { + c4m_add_warning(ctx->file_ctx, + c4m_warn_dupe_alloc, + kid); + } + bitfield |= flag; } - bitfield |= flag; goto next_alloc; } c4m_add_error(ctx->file_ctx, c4m_err_bad_alloc_name, kid); @@ -1222,6 +1264,7 @@ handle_extern_block(pass1_ctx *ctx) next_alloc: /* nothing. */; } + info->cif.alloc_info = bitfield; } c4m_scope_entry_t *sym = declare_sym(ctx, @@ -1236,6 +1279,8 @@ handle_extern_block(pass1_ctx *ctx) sym->type = info->local_params->full_type; sym->value = (void *)info; } + + c4m_xlist_append(ctx->file_ctx->extern_decls, sym); } static void @@ -1406,14 +1451,16 @@ c4m_file_decl_pass(c4m_compile_ctx *cctx, c4m_file_compile_ctx *file_ctx) set_current_node(&ctx, file_ctx->parse_tree); - file_ctx->global_scope = c4m_new_scope(NULL, C4M_SCOPE_GLOBAL); - file_ctx->module_scope = c4m_new_scope(file_ctx->global_scope, + file_ctx->global_scope = c4m_new_scope(NULL, C4M_SCOPE_GLOBAL); + file_ctx->module_scope = c4m_new_scope(file_ctx->global_scope, C4M_SCOPE_MODULE); - file_ctx->attribute_scope = c4m_new_scope(NULL, C4M_SCOPE_ATTRIBUTES); - file_ctx->imports = c4m_new_scope(NULL, C4M_SCOPE_IMPORTS); - file_ctx->parameters = c4m_new(c4m_tspec_dict(c4m_tspec_utf8(), + file_ctx->attribute_scope = c4m_new_scope(NULL, C4M_SCOPE_ATTRIBUTES); + file_ctx->imports = c4m_new_scope(NULL, C4M_SCOPE_IMPORTS); + file_ctx->parameters = c4m_new(c4m_tspec_dict(c4m_tspec_utf8(), c4m_tspec_ref())); - file_ctx->fn_def_syms = c4m_new(c4m_tspec_xlist(c4m_tspec_ref())); + file_ctx->fn_def_syms = c4m_new(c4m_tspec_xlist(c4m_tspec_ref())); + file_ctx->callback_literals = c4m_new(c4m_tspec_xlist(c4m_tspec_ref())); + file_ctx->extern_decls = c4m_new(c4m_tspec_xlist(c4m_tspec_ref())); ctx.cur->static_scope = file_ctx->module_scope; ctx.static_scope = file_ctx->module_scope; diff --git a/src/con4m/compiler/disasm.c b/src/con4m/compiler/disasm.c index 6a8f0df0..8d76fef0 100644 --- a/src/con4m/compiler/disasm.c +++ b/src/con4m/compiler/disasm.c @@ -306,6 +306,10 @@ const inst_info_t inst_info[256] = { .arg_fmt = fmt_hex, // Should add a fmt here. .show_module = 1, }, + [C4M_ZFFICall] = { + .name = "ZFFICall", + .arg_fmt = fmt_hex, + }, [C4M_ZLockOnWrite] = { .name = "ZLockOnWrite", }, diff --git a/src/con4m/compiler/errors.c b/src/con4m/compiler/errors.c index 7803ba21..24fba00f 100644 --- a/src/con4m/compiler/errors.c +++ b/src/con4m/compiler/errors.c @@ -1108,6 +1108,28 @@ static error_info_t error_info[] = { "return values.", false, }, + [c4m_err_callback_no_match] = { + c4m_err_callback_no_match, + "callback_no_match", + "Callback does not have a matching declaration. It requires either a " + "con4m function, or an [em]extern[/] declaration.", + false, + }, + [c4m_err_callback_bad_target] = { + c4m_err_callback_bad_target, + "callback_bad_target", + "Callback matches a symbol that is defined, but not as a callable " + "function. First definition is here: {}", + true, + }, + [c4m_err_callback_type_mismatch] = { + c4m_err_callback_type_mismatch, + "callback_type_mismatch", + "Declared callback type is not compatable with the implementation " + "callback type ([em]{}[/] vs declared type [em]{}[/]). " + " Declaration is here: {}", + true, + }, [c4m_err_last] = { c4m_err_last, "last", diff --git a/src/con4m/compiler/lex.c b/src/con4m/compiler/lex.c index af37ceb9..3d7eb313 100644 --- a/src/con4m/compiler/lex.c +++ b/src/con4m/compiler/lex.c @@ -427,14 +427,13 @@ scan_int_or_float_literal(lex_state_t *state) goto finished_int; } } -finished_int: { +finished_int:; uint64_t n = (uint64_t)val; state->pos = state->start + i; LITERAL_TOK(c4m_tt_int_lit); state->last_token->literal_value = (void *)n; return; } -} static inline void scan_hex_literal(lex_state_t *state) @@ -483,6 +482,7 @@ scan_int_float_or_hex_literal(lex_state_t *state) switch (peek(state)) { case 'x': case 'X': + advance(state); scan_hex_literal(state); return; default: diff --git a/src/con4m/compiler/parse.c b/src/con4m/compiler/parse.c index 8ca48799..710c35c3 100644 --- a/src/con4m/compiler/parse.c +++ b/src/con4m/compiler/parse.c @@ -142,65 +142,6 @@ static c4m_tree_node_t *bit_or_expr_rhs(parse_ctx *); static c4m_tree_node_t *ne_expr_rhs(parse_ctx *); static c4m_tree_node_t *and_expr_rhs(parse_ctx *); -typedef struct { - char *ctype_name; - int index; - bool can_take_param; -} ctype_name_info_t; - -static const ctype_name_info_t ctype_info[] = { - // clang-format off - { "void", 0, false, }, - { "cvoid", 0, false, }, - { "u8", 1, false, }, - { "cu8", 1, false, }, - { "i8", 2, false, }, - { "ci8", 2, false, }, - { "u16", 3, false, }, - { "cu16", 3, false, }, - { "i16", 4, false, }, - { "ci16", 4, false, }, - { "u32", 5, false, }, - { "cu32", 5, false, }, - { "i32", 6, false, }, - { "ci32", 6, false, }, - { "u64", 7, false, }, - { "cu64", 7, false, }, - { "i64", 8, false, }, - { "ci64", 8, false, }, - { "cfloat", 9, false, }, - { "cdouble", 10, false, }, - { "double", 10, false, }, - { "cuchar", 11, false, }, - { "cchar", 12, false, }, - { "short", 13, false, }, - { "cshort", 13, false, }, - { "ushort", 14, false, }, - { "cushort", 14, false, }, - { "cint", 15, false, }, - { "cuint", 16, false, }, - { "long", 17, false, }, - { "ulong", 18, false, }, - { "bool", 19, false, }, - { "size_t", 20, false, }, - { "size", 20, false, }, - { "size_t", 20, false, }, - { "csize", 20, false, }, - { "csize_t", 20, false, }, - { "ssize", 21, false, }, - { "ssize_t", 21, false, }, - { "cssize", 21, false, }, - { "ssize_t", 21, false, }, - { "cssize_t", 21, false, }, - { "ptr", 22, true, }, - { "pointer", 22, true, }, - { "cstring", 23, true, }, - { "carray", 24, true, }, - { "array", 24, true, }, - { NULL, 0, false, }, - // clang-format on -}; - typedef struct { char *name; unsigned int show_contents : 1; @@ -294,23 +235,6 @@ static const node_type_info_t node_type_info[] = { // clang-format on }; -static int -lookup_ctype_id(char *found) -{ - ctype_name_info_t *info = (ctype_name_info_t *)&ctype_info[0]; - - while (true) { - if (info->ctype_name == NULL) { - return -1; - } - if (!strcmp(info->ctype_name, found)) { - return info->index; - } - - info++; - } -} - #ifdef PARSE_DEBUG static inline c4m_token_t * _tok_cur(parse_ctx *ctx, int line) @@ -1182,7 +1106,7 @@ extern_local(parse_ctx *ctx) static void extern_dll(parse_ctx *ctx) { - start_node(ctx, c4m_nt_extern_local, true); + start_node(ctx, c4m_nt_extern_dll, true); if (!expect(ctx, c4m_tt_colon)) { end_node(ctx); return; @@ -1263,6 +1187,24 @@ extern_allocs(parse_ctx *ctx) return; } +static void +extern_sig_item(parse_ctx *ctx, c4m_node_kind_t kind) +{ + char *txt = identifier_text(tok_cur(ctx))->data; + int64_t ctype_id = (int64_t)c4m_lookup_ctype_id(txt); + if (ctype_id == -1) { + add_parse_error(ctx, c4m_err_parse_bad_ctype_id); + consume(ctx); + } + else { + start_node(ctx, kind, true); + c4m_pnode_t *n = current_parse_node(ctx); + + n->extra_info = (void *)(uint64_t)ctype_id; + end_node(ctx); + } +} + static void extern_signature(parse_ctx *ctx) { @@ -1274,7 +1216,9 @@ extern_signature(parse_ctx *ctx) if (tok_kind(ctx) == c4m_tt_rparen) { consume(ctx); end_node(ctx); - opt_return_type(ctx); + expect(ctx, c4m_tt_arrow); + extern_sig_item(ctx, c4m_nt_lit_tspec_return_type); + return; } while (true) { @@ -1283,20 +1227,7 @@ extern_signature(parse_ctx *ctx) consume(ctx); } else { - char *txt = identifier_text(tok_cur(ctx))->data; - int64_t ctype_id = (int64_t)lookup_ctype_id(txt); - - if (ctype_id == -1) { - add_parse_error(ctx, c4m_err_parse_bad_ctype_id); - consume(ctx); - } - else { - start_node(ctx, c4m_nt_extern_param, true); - c4m_pnode_t *n = current_parse_node(ctx); - - n->extra_info = (void *)(uint64_t)ctype_id; - end_node(ctx); - } + extern_sig_item(ctx, c4m_nt_extern_param); } if (tok_kind(ctx) != c4m_tt_comma) { @@ -1306,7 +1237,8 @@ extern_signature(parse_ctx *ctx) } expect(ctx, c4m_tt_rparen); - opt_return_type(ctx); + expect(ctx, c4m_tt_arrow); + extern_sig_item(ctx, c4m_nt_lit_tspec_return_type); end_node(ctx); } diff --git a/src/con4m/compiler/scope.c b/src/con4m/compiler/scope.c index 59420088..54a3f3c5 100644 --- a/src/con4m/compiler/scope.c +++ b/src/con4m/compiler/scope.c @@ -404,8 +404,12 @@ c4m_format_scope(c4m_scope_t *scope) c4m_utf8_t *kind; c4m_scope_entry_t *entry = values[i]; - kind = c4m_type_is_declared(entry) ? decl_const : inf_const; - row = c4m_new_table_row(); + kind = inf_const; + + if (c4m_type_is_declared(entry) || entry->kind == sk_extern_func) { + kind = decl_const; + } + row = c4m_new_table_row(); c4m_xlist_append(row, entry->name); diff --git a/src/con4m/ffi.c b/src/con4m/ffi.c new file mode 100644 index 00000000..4e42aefc --- /dev/null +++ b/src/con4m/ffi.c @@ -0,0 +1,182 @@ +#include "con4m.h" + +typedef struct { + char *ctype_name; + uint8_t index; + bool can_take_param; +} ctype_name_info_t; + +static const ctype_name_info_t ctype_name_info[] = { + // clang-format off + { "void", 0, false, }, + { "cvoid", 0, false, }, + { "u8", 1, false, }, + { "cu8", 1, false, }, + { "i8", 2, false, }, + { "ci8", 2, false, }, + { "u16", 3, false, }, + { "cu16", 3, false, }, + { "i16", 4, false, }, + { "ci16", 4, false, }, + { "u32", 5, false, }, + { "cu32", 5, false, }, + { "i32", 6, false, }, + { "ci32", 6, false, }, + { "u64", 7, false, }, + { "cu64", 7, false, }, + { "i64", 8, false, }, + { "ci64", 8, false, }, + { "cfloat", 9, false, }, + { "cdouble", 10, false, }, + { "double", 10, false, }, + { "cuchar", 11, false, }, + { "cchar", 12, false, }, + { "short", 13, false, }, + { "cshort", 13, false, }, + { "ushort", 14, false, }, + { "cushort", 14, false, }, + { "cint", 15, false, }, + { "cuint", 16, false, }, + { "ulong", 17, false, }, + { "long", 18, false, }, + { "bool", 19, false, }, + { "size_t", 20, false, }, + { "size", 20, false, }, + { "size_t", 20, false, }, + { "csize", 20, false, }, + { "csize_t", 20, false, }, + { "ssize", 21, false, }, + { "ssize_t", 21, false, }, + { "cssize", 21, false, }, + { "ssize_t", 21, false, }, + { "cssize_t", 21, false, }, + { "ptr", 22, true, }, + { "pointer", 22, true, }, + { "carray", 23, true, }, + { "array", 23, true, }, + { "cstring", C4M_CSTR_CTYPE_CONST, true, }, + { NULL, 0, false, }, + // clang-format on +}; + +static const c4m_ffi_type *ffi_type_map[] = { + &ffi_type_void, + &ffi_type_uint8, + &ffi_type_sint8, + &ffi_type_uint16, + &ffi_type_sint16, + &ffi_type_uint32, + &ffi_type_sint32, + &ffi_type_uint64, + &ffi_type_sint64, + &ffi_type_float, + &ffi_type_double, + &ffi_type_uchar, + &ffi_type_schar, + &ffi_type_ushort, + &ffi_type_sshort, + &ffi_type_uint, + &ffi_type_sint, + &ffi_type_ulong, + &ffi_type_slong, + &ffi_type_sint8, // Bool is 1 byte per the C standard. + &ffi_type_uint, // I believe size_t is always a unsigned integer. + &ffi_type_sint, + &ffi_type_pointer, + &ffi_type_pointer, + &ffi_type_pointer, + NULL, +}; + +void * +c4m_ref_via_ffi_type(c4m_box_t *box, c4m_ffi_type *t) +{ + if (t == &ffi_type_uint8 || t == &ffi_type_sint8) { + return &box->u8; + } + if (t == &ffi_type_uint16 || t == &ffi_type_sint16) { + return &box->u16; + } + if (t == &ffi_type_uint32 || t == &ffi_type_sint32) { + return &box->u32; + } + + return box; +} + +static c4m_dict_t *c4m_symbol_cache = NULL; + +static inline void +ffi_init() +{ + if (c4m_symbol_cache == NULL) { + c4m_symbol_cache = c4m_new(c4m_tspec_dict(c4m_tspec_utf8(), + c4m_tspec_ref())); + c4m_gc_register_root(&c4m_symbol_cache, 1); + } +} + +int64_t +c4m_lookup_ctype_id(char *found) +{ + ctype_name_info_t *info = (ctype_name_info_t *)&ctype_name_info[0]; + + while (true) { + if (info->ctype_name == NULL) { + return -1; + } + if (!strcmp(info->ctype_name, found)) { + return (int64_t)info->index; + } + + info++; + } +} + +c4m_ffi_type * +c4m_ffi_arg_type_map(uint8_t ix) +{ + return (c4m_ffi_type *)ffi_type_map[ix]; +} + +void +c4m_add_static_function(c4m_utf8_t *name, void *symbol) +{ + ffi_init(); + + hatrack_dict_put(c4m_symbol_cache, name, symbol); +} + +void * +c4m_ffi_find_symbol(c4m_utf8_t *name, c4m_xlist_t *opt_libs) +{ + ffi_init(); + + void *ptr = hatrack_dict_get(c4m_symbol_cache, name, NULL); + + if (ptr != NULL) { + return ptr; + } + + ptr = dlsym(RTLD_DEFAULT, name->data); + + if (ptr != NULL) { + return ptr; + } + + if (opt_libs == NULL) { + int n = c4m_xlist_len(opt_libs); + + for (int i = 0; i < n; i++) { + c4m_utf8_t *s = c4m_xlist_get(opt_libs, i, NULL); + if (dlopen(s->data, RTLD_NOW | RTLD_GLOBAL) != NULL) { + ptr = dlsym(RTLD_DEFAULT, name->data); + if (ptr != NULL) { + return ptr; + } + } + } + } + + return NULL; +} diff --git a/src/con4m/gc.c b/src/con4m/gc.c index 14c06910..cd755262 100644 --- a/src/con4m/gc.c +++ b/src/con4m/gc.c @@ -14,6 +14,7 @@ static c4m_dict_t *global_roots; uint64_t c4m_gc_guard = 0; static thread_local c4m_arena_t *current_heap = NULL; +static c4m_set_t *external_holds = NULL; static c4m_system_finalizer_fn system_finalizer = NULL; static uint64_t page_bytes; static uint64_t page_modulus; @@ -86,29 +87,35 @@ c4m_initialize_gc() static bool once = false; if (!once) { - c4m_gc_guard = c4m_rand64(); - global_roots = c4m_rc_alloc(sizeof(c4m_dict_t)); - once = true; - page_bytes = getpagesize(); - page_modulus = page_bytes - 1; // Page size is always a power of 2. - modulus_mask = ~page_modulus; + c4m_gc_guard = c4m_rand64(); + global_roots = c4m_rc_alloc(sizeof(c4m_dict_t)); + external_holds = c4m_rc_alloc(sizeof(c4m_set_t)); + once = true; + page_bytes = getpagesize(); + page_modulus = page_bytes - 1; // Page size is always a power of 2. + modulus_mask = ~page_modulus; c4m_gc_trace("init:set_guard:%llx", c4m_gc_guard); c4m_gc_trace("init:global_root_addr:@%p", global_roots); - // use c4m_gc_malloc_wrapper for hatrack's zalloc function since our - // gc allocator always returns zeroed memory. - // hatrack_setmallocfns(NULL, - // NULL, - // NULL, - // NULL, - // c4m_gc_malloc_wrapper, - // NULL); - hatrack_dict_init(global_roots, HATRACK_DICT_KEY_TYPE_PTR); + hatrack_set_init(external_holds, HATRACK_DICT_KEY_TYPE_PTR); + hatrack_dict_put(global_roots, &external_holds, (void *)1); } } +void +c4m_gc_add_hold(c4m_obj_t obj) +{ + hatrack_set_add(external_holds, obj); +} + +void +c4m_gc_remove_hold(c4m_obj_t obj) +{ + hatrack_set_remove(external_holds, obj); +} + // The idea here is once the object unmarshals the object file and // const objects, it can make the heap up till that point read-only. // We definitely won't want to allocate anything that will need diff --git a/src/con4m/init.c b/src/con4m/init.c index 3d0273e4..43a4c66e 100644 --- a/src/con4m/init.c +++ b/src/con4m/init.c @@ -6,6 +6,20 @@ char **c4m_stashed_argv; char **c4m_stashed_envp; +uint64_t +c4m_clz(uint64_t n) +{ + return __builtin_clzll(n); +} + +static void +c4m_register_builtins() +{ + c4m_add_static_function(c4m_new_utf8("c4m_clz"), c4m_clz); + c4m_add_static_function(c4m_new_utf8("c4m_gc_remove_hold"), + c4m_gc_remove_hold); +} + __attribute__((constructor)) void c4m_init(int argc, char **argv, char **envp) { @@ -16,6 +30,8 @@ c4m_init(int argc, char **argv, char **envp) c4m_initialize_gc(); c4m_gc_set_finalize_callback((void *)c4m_finalize_allocation); c4m_initialize_global_types(); + c4m_init_std_streams(); + c4m_register_builtins(); } c4m_xlist_t * diff --git a/src/con4m/numbers.c b/src/con4m/numbers.c index 2f04bc29..3a4c626c 100644 --- a/src/con4m/numbers.c +++ b/src/con4m/numbers.c @@ -115,7 +115,7 @@ raw_hex_parse(c4m_utf8_t *u8, c4m_compile_error_t *err) // Here we expect *s to point to the first // character after any leading '0x'. __uint128_t cur = 0; - char *s = u8->data; + char *s = u8->data + 2; char c; bool even = true; @@ -199,7 +199,7 @@ raw_hex_parse(c4m_utf8_t *u8, c4m_compile_error_t *err) return c4m_box_##magic_type(-1 * val); \ } \ else { \ - if (val > overflow_val) { \ + if (st == ST_Base10 && val > overflow_val) { \ *code = c4m_err_parse_lit_overflow; \ return NULL; \ } \ diff --git a/src/con4m/path.c b/src/con4m/path.c index 9db27f86..67dcc21d 100644 --- a/src/con4m/path.c +++ b/src/con4m/path.c @@ -36,8 +36,13 @@ c4m_get_user_dir(c4m_utf8_t *user) if (user == NULL) { result = c4m_get_env(c4m_new_utf8("HOME")); if (!result) { - pw = getpwent(); - result = c4m_new_utf8(pw->pw_dir); + pw = getpwent(); + if (pw == NULL) { + result = c4m_new_utf8("/"); + } + else { + result = c4m_new_utf8(pw->pw_dir); + } } } else { diff --git a/src/con4m/streams.c b/src/con4m/streams.c index 9fe7ab8f..a574900c 100644 --- a/src/con4m/streams.c +++ b/src/con4m/streams.c @@ -724,8 +724,8 @@ static c4m_stream_t *c4m_stream_stdin = NULL; static c4m_stream_t *c4m_stream_stdout = NULL; static c4m_stream_t *c4m_stream_stderr = NULL; -static inline void -init_std_streams() +void +c4m_init_std_streams() { if (c4m_stream_stdin == NULL) { c4m_stream_stdin = c4m_new(c4m_tspec_stream(), @@ -743,21 +743,18 @@ init_std_streams() c4m_stream_t * c4m_get_stdin() { - init_std_streams(); return c4m_stream_stdin; } c4m_stream_t * c4m_get_stdout() { - init_std_streams(); return c4m_stream_stdout; } c4m_stream_t * c4m_get_stderr() { - init_std_streams(); return c4m_stream_stderr; } diff --git a/src/con4m/vm.c b/src/con4m/vm.c index 4b17aa20..774ca4e0 100644 --- a/src/con4m/vm.c +++ b/src/con4m/vm.c @@ -638,7 +638,58 @@ c4m_vm_call_module(c4m_vmthread_t *tstate, c4m_zinstruction_t *i) static void c4m_vm_ffi_call(c4m_vmthread_t *tstate, c4m_zinstruction_t *i, int64_t ix) { - // TODO ffi_call + c4m_ffi_decl_t *decl = c4m_xlist_get(tstate->vm->obj->ffi_info, + i->arg, + NULL); + + if (decl == NULL) { + fprintf(stderr, "Could not load external function.\n"); + abort(); + } + + c4m_zffi_cif *ffiinfo = &decl->cif; + void **args; + + if (!ffiinfo->cif.nargs) { + args = NULL; + } + else { + args = c4m_gc_array_alloc(void *, ffiinfo->cif.nargs); + int n = ffiinfo->cif.nargs; + + for (unsigned int i = 0; i < ffiinfo->cif.nargs; i++) { + // clang-format off + --n; + + if (ffiinfo->str_convert && + n < 63 && + ((1 << n) & ffiinfo->str_convert)) { + + c4m_utf8_t *s = (c4m_utf8_t *)tstate->sp[i].rvalue.obj; + s = c4m_to_utf8(s); + args[n] = &s->data; + } + // clang-format on + else { + c4m_box_t value = {.u64 = tstate->sp[i].uint}; + c4m_box_t *box = c4m_new(c4m_tspec_box(c4m_tspec_ref()), + value); + args[n] = c4m_ref_via_ffi_type(box, + ffiinfo->cif.arg_types[n]); + } + + if (n < 63 && ((1 << n) & ffiinfo->hold_info)) { + c4m_gc_add_hold(tstate->sp[i].rvalue.obj); + } + } + } + + ffi_call(&ffiinfo->cif, ffiinfo->fptr, &tstate->r0, args); + + if (ffiinfo->str_convert & (1UL << 63)) { + char *s = (char *)tstate->r0.obj; + tstate->r0.obj = c4m_new_utf8(s); + } } static void @@ -1469,10 +1520,56 @@ c4m_vm_load_const_data(c4m_vm_t *vm) c4m_internal_lock_then_unstash_heap(); } +static inline void +c4m_vm_setup_ffi(c4m_vm_t *vm) +{ + vm->ffi_info_entries = c4m_xlist_len(vm->obj->ffi_info); + + if (vm->ffi_info_entries == 0) { + return; + } + + for (int i = 0; i < vm->ffi_info_entries; i++) { + c4m_ffi_decl_t *ffi_info = c4m_xlist_get(vm->obj->ffi_info, i, NULL); + c4m_zffi_cif *cif = &ffi_info->cif; + + cif->fptr = c4m_ffi_find_symbol(ffi_info->external_name, + ffi_info->dll_list); + + if (!cif->fptr) { + // TODO: warn. For now, just error if it gets called. + continue; + } + + int n = ffi_info->num_ext_params; + c4m_ffi_type **arglist = c4m_gc_array_alloc(c4m_ffi_type *, n); + + for (int j = 0; j < n; j++) { + uint8_t param = ffi_info->external_params[j]; + arglist[j] = c4m_ffi_arg_type_map(param); + + if (param == C4M_CSTR_CTYPE_CONST && j < 63) { + cif->str_convert |= (1UL << j); + } + } + + if (ffi_info->external_return_type == C4M_CSTR_CTYPE_CONST) { + cif->str_convert |= (1UL << 63); + } + + ffi_prep_cif(&cif->cif, + C4M_FFI_DEFAULT_ABI, + n, + c4m_ffi_arg_type_map(ffi_info->external_return_type), + arglist); + } +} + void c4m_vm_setup_runtime(c4m_vm_t *vm) { c4m_vm_load_const_data(vm); + c4m_vm_setup_ffi(vm); } void diff --git a/src/con4m/vmmarshal.c b/src/con4m/vmmarshal.c index a6e9f8f9..bc292ea1 100644 --- a/src/con4m/vmmarshal.c +++ b/src/con4m/vmmarshal.c @@ -84,6 +84,7 @@ unmarshal_instruction(c4m_stream_t *in, c4m_dict_t *memos) return out; } +#if 0 // Removing for now static void marshal_ffi_arg_info(void *ref, c4m_stream_t *out, c4m_dict_t *memos, int64_t *mid) { @@ -99,6 +100,7 @@ marshal_ffi_arg_info(void *ref, c4m_stream_t *out, c4m_dict_t *memos, int64_t *m static void * unmarshal_ffi_arg_info(c4m_stream_t *in, c4m_dict_t *memos) { + c4m_zffi_arg_info_t *out = c4m_gc_alloc(c4m_zffi_arg_info_t); out->held = c4m_unmarshal_bool(in); @@ -109,10 +111,12 @@ unmarshal_ffi_arg_info(c4m_stream_t *in, c4m_dict_t *memos) return out; } +#endif static void marshal_ffi_info(void *ref, c4m_stream_t *out, c4m_dict_t *memos, int64_t *mid) { +#if 0 c4m_zffi_info_t *in = ref; c4m_marshal_i64(in->nameoffset, out); @@ -124,11 +128,13 @@ marshal_ffi_info(void *ref, c4m_stream_t *out, c4m_dict_t *memos, int64_t *mid) marshal_xlist_ref(in->arg_info, out, memos, mid, marshal_ffi_arg_info); c4m_sub_marshal(in->shortdoc, out, memos, mid); c4m_sub_marshal(in->longdoc, out, memos, mid); +#endif } static void * unmarshal_ffi_info(c4m_stream_t *in, c4m_dict_t *memos) { +#if 0 c4m_zffi_info_t *out = c4m_gc_alloc(c4m_zffi_info_t); out->nameoffset = c4m_unmarshal_i64(in); @@ -142,6 +148,8 @@ unmarshal_ffi_info(c4m_stream_t *in, c4m_dict_t *memos) out->longdoc = c4m_sub_unmarshal(in, memos); return out; +#endif + return NULL; } static void diff --git a/src/hatrack/hash/set.c b/src/hatrack/hash/set.c index 044ae6d5..d17f00b5 100644 --- a/src/hatrack/hash/set.c +++ b/src/hatrack/hash/set.c @@ -980,5 +980,5 @@ hatrack_set_epoch_sort_cmp(const void *b1, const void *b2) item1 = (hatrack_set_view_t *)b1; item2 = (hatrack_set_view_t *)b2; - return item2->sort_epoch - item1->sort_epoch; + return item1->sort_epoch - item2->sort_epoch; } diff --git a/src/tests/test.c b/src/tests/test.c index 25455c55..03e840c6 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -635,6 +635,8 @@ test_compiler() return; } + c4m_add_static_function(c4m_new_utf8("strndup"), strndup); + for (int64_t i = 0; i < l; i++) { c4m_utf8_t *fname = c4m_xlist_get(files, i, NULL); c4m_utf8_t *path; diff --git a/tests/basic15.c4m b/tests/basic15.c4m new file mode 100644 index 00000000..11d2b9dd --- /dev/null +++ b/tests/basic15.c4m @@ -0,0 +1,6 @@ +extern c4m_clz(i64) -> i64 { + local: clz(x: int) -> int +} + +print clz(0x0fffffffffffffff) + diff --git a/tests/basic16.c4m b/tests/basic16.c4m new file mode 100644 index 00000000..c15d6caa --- /dev/null +++ b/tests/basic16.c4m @@ -0,0 +1,7 @@ +extern strndup(cstring, csize_t) -> cstring { + local: test(s: string, n: int) -> string +} + +x = "Hello, world!" +print x +print(test(x, 4)) \ No newline at end of file