summaryrefslogtreecommitdiffstats
path: root/ffi.c
Commit message (Collapse)AuthorAgeFilesLines
...
* ffi: provide support for unions.Kaz Kylheku2017-06-231-2/+269
| | | | | | | | | | | | | | | | | | | | | | | | | | * ffi.c (union_s): New symbol variable. (ffi_find_memb, ffi_memb_not_found): New static functions. (ffi_union_in, ffi_union_put, ffi_union_get): New static functions. (make_ffi_type_union): New static function. (ffi_struct_compile): Handle union syntax using ffi_struct_compile to compile the member definitions to types, and make_ffi_type_union to produce the type node. (struct uni): New struct type. (uni_struct, uni_struct_checked): New static functions. (union_destroy_op, union_mark_op): New static functions. (union_ops): New static struct. (make_union_common, make_union_tft): New static functions. (union_get_ptr, make_union, union_members, union_get, union_put, union_in, union_out): New functions. (ffi_init): Initialize union_s. Register intrinsics make-union, union-members, union-get, union-put, union-in, union-out. * ffi.h (union_s, union_get_ptr, make_union, union_members, union_get, union_put, union_in, union_out): Declared. * txr.1: Documented unions.
* ffi: add back-pointer into type structure.Kaz Kylheku2017-06-231-0/+6
| | | | | | | | | | | Upcoming work is going to benefit from a pointer for navigating from the txr_ffi_type structure to the Lisp object whose implementation is that structure. * ffi.c (struct txr_ffi_type): New member, self. (make_ffi_type_builtin, make_ffi_type_pointer, make_ffi_type_struct, make_ffi_type_array, make_ffi_type_enum): Initialize self pointer.
* ffi: override libffi size/alignment calculations.Kaz Kylheku2017-06-211-51/+16
| | | | | | | | | | | | | | | | | | Don't bother creating and filling the ffi_type elements[] array for a structs or array. Let's punch in the size and alignment fields with the values we calculate ourselves already, and set up a dummy elements[] array that contains only a null terminator. * ffi.c (struct txr_ffi_type): New member, elements: one element dummy array that holds a null pointer. (ffi_type_struct_destroy_op): Do not free ft->elements, since it isn't dynamically allocated any more. (ffi_struct_clone, ffi_array_clone): Don't copy the elements array; just set up a dummy elements array in the copied type. (make_ffi_type_struct, make_ffi_type_array): Eliminate the dynamic allocation of the elements array. Point ft->elements to the dummy array. Set up the ft->size and ft->alignment.
* ffi: fix broken float put.Kaz Kylheku2017-06-201-2/+6
| | | | | | | | * ffi.c (ffi_float_put): Fix silly range check: FLT_MIN and FLT_MAX are, of course, both positive. Also, fix num being used as an argument in the error diagnostic. It's the address of a C function, not an object.
* ffi: bool type.Kaz Kylheku2017-06-201-0/+33
| | | | | | | | | | | | * ffi.c (bool_s): New symbol variable. (ffi_bool_put, ffi_bool_get): New static functions. (ffi_type_compile): Handle (bool <type>) parametrized type. (ffi_init_types): Register bool typedef for (bool uchar). (ffi_init): Initialize bool_s. * ffi.h (bool_s): Declared. * txr.1: Documented.
* Handle returns of MPI functions that return MP_TOOBIG.Kaz Kylheku2017-06-181-6/+6
| | | | | | | | | | | * arith.c (do_mp_error): New function. (num_from_buffer, plus, minus, mul, floordiv, expt, exptmod, logtrunc, sign_extend, ash, bit): Handle errors from select MPI functions: those that have the mp_ign attribute. * ffi.c (unum_carray, num_carray): Likewise. * rand.c (random): Likewise.
* ffi: copy-carray, hooked into copy.Kaz Kylheku2017-06-151-0/+9
| | | | | | | | | | | | * ffi.c (copy_carray): New function (ffi_init): Register copy-carray intrinsic. * ffi.h (copy_carray): Declared. * lib.c (copy): Call copy_array for carray objects. * txr.1: Documented copy-carray and updated copy description.
* ffi: new put-carray and fill-carray functions.Kaz Kylheku2017-06-151-0/+26
| | | | | | | | | | * ffi.c (put_carray, fill_carray): New functions. (ffi_init): put-carray and fill-carray intrinsics registered. * ffi.h (put_carray, fill_carray): Declared. * txr.1: Documented.
* ffi: new integer-carray conversion functions.Kaz Kylheku2017-06-141-0/+110
| | | | | | | | | | | | * ffi.c (carray_unum, carray_num, unum_carray, num_carray): New functions. (ffi_init): New intrinsics registered: carray-unum, carray-num, unum-carray, num-carray. * ffi.h (carray_unum, carray_num, unum_carray, num_carray): Declared. * txr.1: Documented.
* ffi: fix buggy bitfield allocation.Kaz Kylheku2017-06-131-2/+2
| | | | | | | | | | | | | | * ffi.c (make_ffi_type_struct): When there is no room in the current bitfield, two mistakes are made. When bit_offs is reset to zero in this case, the dependent variable bits_alloc that was calculated from it (bits allocated to current unit) must also be reset. The subsequent shift depends on it. Secondly, when we establish the memb[i].offs field, that must come from offs, not from unit_offs, because unit_offs is always the base offset of the existing cell (which doesn't have room for the new bitfield in this case); the main offset variable offs is what gets gets adjusted to the cell which has room for the new bitfield.
* Follow up on C++ diagnostics.Kaz Kylheku2017-06-121-6/+6
| | | | | | | | | * ffi.c (ffi_generic_sbit_put, fi_generic_sbit_get, ffi_generic_ubit_put, fi_generic_ubit_get): Add needed coerce from zalloca to mem_t *. (make_ffi_type_struct): Fix signed/unsigned comparison. * lib.c (vector): Fix signed/unsigned comparison.
* ffi: overflow checks in type system.Kaz Kylheku2017-06-121-10/+14
| | | | | | | | | | | | | | * ffi.c (make_ffi_type_struct): Use chk_xalloc instead of chk_malloc. (make_ffi_type_array): Use chk_xalloc. Since there are multiple callers, take a self argument to pass down to chk_xalloc. (ffi_type_compile): Pass self down to make_ffi_type_array. (ffi_make_call_desc): Use chk_xalloc. (carray_ensure_artype): Take a self argument and pass down to make_ffi_type_array. (carray_get_common, carray_put_common): Pass self down to carray_ensure_artype.
* ffi: fix carray multiplication overflow checks.Kaz Kylheku2017-06-121-3/+3
| | | | | | | | * ffi.c (carray_dup): Do size multiplication using unsigned type, then coerce back to signed. Check for overflow correctly by first testing result for negative, then doing division check. (carray_replace): Add check for negative size, which confirms overflow.
* ffi: add carrayp function.Kaz Kylheku2017-06-121-0/+6
| | | | | | | | | * ffi.c (carrayp): New function. (ffi_init): Register carrayp intrinsic. * ffi.h (carrayp): Declared. * txr.1: Documented.
* ffi: new carray-replace function.Kaz Kylheku2017-06-111-0/+93
| | | | | | | | | | | | | | Thanks to this (set [ca from..to] list) works. * ffi.c (carray_replace): New function. (ffi_init): Register carray-replace intrinsic. * ffi.h (carray_replace): Declared. * ffi.c (replace): Hook in carray_replace. * txr.1: Mention carray under replace, and document carray-replace.
* ffi: new function, carray-pun.Kaz Kylheku2017-06-111-0/+21
| | | | | | | | | * ffi.c (carray_pun): New function. (ffi_init): Registered carray-pun intrinsic. * ffi.h (carray_pun): Declared. * txr.1: Documented.
* ffi: handle sub operation in carray.Kaz Kylheku2017-06-111-0/+43
| | | | | | | | | | | | | | | | Thus, [ca 3..5] syntax works for slice extraction. However, this works referentially, not by making a copy. The extracted subarray points to the original memory, until carray-dup is invoked on it. * ffi.c (carray_sub): New function. (ffi_init): carray-sub intrinsic registered. * ffi.h (carray_sub): Declared. * lib.c (sub): Handle carray via carray_sub. * txr.1: Documented changes in sub.
* ffi: support sel operation on carray.Kaz Kylheku2017-06-111-0/+18
| | | | | | | | | | | | | | | | | | | | Thus (select ca '(0 3 4 ...)) works and so does the sytnax [ca '(0 3 4 ...)]. This is inefficiently implemented. The selected elements are extracted to a list which is then converted to a carray of the same kind agan. * ffi.c (carray_list): New function. (ffi_init): Register carray-list intrinsic. * ffi.h (carray_list): Declared. * lib.c (make_like): Add carray case, so we can turn a list into a carray based on an example carray. This uses carray_list, with the type pulled from the original carray. The target isn't null terminated. (sel): Handle carray via vector case. * txr.1: Document changes in select and make-like.
* ffi: new carray-get and carray-put functions.Kaz Kylheku2017-06-101-0/+79
| | | | | | | | | | | | | | | | | * ffi.c (struct carray): New member, artype. (carray_mark_op): Mark artype member. (make_carray): Initialize artype to nil. (carray_ensure_artype, carray_get_common, carray_put_common): New static functions. (carray_get, carray_getz, carray_put, carray_putz): New functions. (ffi_init): Register intrinsics carray-get, carray-getz, carray-put, carray-putz. * ffi.h (carray_get, carray_getz, carray_put, carray_putz): Declared. * txr.1: Documented new functions.
* Rename carray_get.Kaz Kylheku2017-06-101-2/+2
| | | | | | | | * ffi.c (carray_get): Renamed to carray_ptr. (ffi_carray_put): Follow rename. * ffi.h (carray_get): Declaration removed. (carray_put): Declared.
* ffi: retain some functionality if libffi missing.Kaz Kylheku2017-06-101-2/+70
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The FFI module is more than just foreign calls and callbacks; it provides a type system and operations for working with binary data. None of it depends on libffi being present and so shouldn't be disabled if libffi is not available. * Makefile (ffi.o): Unconditionally link this object file, not subject to the have_libffi variable. * configure (have_libffi): Variable removed. (gen_config_make): Do not generate a have_libffi variable into config.make, since nothing needs it. * ffi.c (ffi_type): Fake ffi_type defined if libffi is missing. (FFI_TYPE_STRUCT): Fake macro. (ffi_type ffi_type_void, ffi_type_pointer, ffi_type_sint, ffi_type ffi_type_schar, ffi_type_uchar, ffi_type ffi_type_sshort, ffi_type_ushort, ffi_type ffi_type_sint, ffi_type_uint, ffi_type ffi_type_slong, ffi_type_ulong, ffi_type ffi_type_sint8, ffi_type_uint8, ffi_type ffi_type_sint16, ffi_type_uint16, ffi_type ffi_type_sint32, ffi_type_uint32, ffi_type ffi_type_sint64, ffi_type_uint64, ffi_type ffi_type_float, ffi_type_double): Fake libffi type objects, so that code which references these things will build without modification. (ffi_get_type): Function only defined if we have libffi. (ffi_type_struct_destroy_op, ffi_struct_clone, make_ffi_type_struct, ffi_array_clone, make_ffi_type_array): Don't work with ffi_type's element array if we don't have libffi; our fake ffi_type doesn't have such an array. (struct txr_ffi_closure): Type only defined if we have libffi. (ffi_closure_struct, ffi_closure_struct_checked, ffi_closure_print_op, ffi_closure_destroy_op, ffi_closure_mark_op, ffi_closure_put): Functions only defined if we have libffi. (ffi_closure_ops): Static structure only defined if we have libffi. (ffi_init_types): Don't register a closure type if we don't have libffi. (struct txr_ffi_call_desc): Don't define type if we don't have libffi. (ffi_call_desc, ffi_call_desc_checked, ffi_call_desc_print_op, ffi_call_desc_destroy_op, ffi_call_desc_mark_op, ffi_make_call_desc, ffi_call_wrap, ffi_closure_dispatch, ffi_closure_dispatch_safe, ffi_make_closure, ffi_closure_get_fptr): Functions only defined if we have libffi. (ffi_call_desc_ops): Static structure only defined if we have libffi. (ffi_init): Only register ffi-make-call-desc, ffi-call, and ffi-make-closure if we have libffi. * lib.c: Include "ffi.h" header unconditionally. (generic_funcall, ref, refset, int): Remove #if HAVE_LIBFFI.
* ffi: bugfix: string semantics for incomplete zarray.Kaz Kylheku2017-06-101-17/+28
| | | | | | | | | | | | The problem is that the get semantics (zarray char) produces a vector of characters, not a string. Ditto for bchar and wchar. * ffi.c (ffi_varray_null_term_in): Check for the char_conv, wchar_conv or bchar_conv flag and delegate to ffi_array_get_common. (ffi_type_compile): Set char_conv, wchar_conv or bchar_conv flag for incomplete zarray.
* ffi: bugfix: string semantics on typedef-d chars.Kaz Kylheku2017-06-101-3/+3
| | | | | | | | | | | | | | The problem is that if we have a typedef like (typedef x char) then (array 256 x) will not do string conversion in the manner of (array 256 char). This is because the raw syntax is checked for the symbol char, rather than inspecting the type object. * ffi.c (ffi_type_compile): When checking whether the array element is a char, bchar or wchar, look at the syntax in the compiled type object, not the raw syntax. The compiled type object is the original type pulled from behind the typedef alias and has the symbol char, bchar or wchar as its syntax.
* ffi: conform to GCC's bitfield layout algorithm.Kaz Kylheku2017-06-071-22/+25
| | | | | | | | | | | The way bitfields are laid out must be changed. The requirements were reverse-engineered by experimentation. * ffi.c (make_ffi_type_struct): Member allocation loop substantially rewritten. * txr.1: Documentation rewritten. Description of the bitfield allocation algorithm moved to a separate paragraph.
* ffi: support bitfields on types narrower than int.Kaz Kylheku2017-06-061-22/+95
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * ffi.c (bit_s): New symbol variable. (ffi_generic_sbit_put, ffi_generic_sbit_get, ffi_generic_ubit_put, ffi_generic_ubit_get): New static functions. (bitfield_syntax_p): Include bit symbol in the check. (make_ffi_type_pointer): Zero size is no longer an early rejection test for bitfields; don't rely on it. (make_ffi_type_struct): Revise the member calculating loop to handle bitfields of various sizes. If a bitfield follows one of a different size, it starts a new cell even if the previous one has room, et cetera. The masking and shifting is set up to work on cells of int size; however, the new ffi_generic_s?bit_{put,get} functions use a temporary buffer and transfer just the right number of bytes to and from the actual buffer. (ffi_struct_compile): The check against incomplete type members only needs to test size zero; bitfields have nonzero size now, which is the true size of the underlying storage unit. They also have true alignment, which is used in make_ffi_type_struct rather than hard-coding to alignof (int). New syntax (bit width type) is now handled, where type can be any of the signed and unsigned integral types up to int32 and int. The endian types are not supported for now. (ffi_typedef, ffi_size, ffi_alignof): Zero size is no longer an early rejection test for bitfields; don't rely on it. (ffi_init): Initialize bit_s. * ffi.h (bit_s): Declared. * txr.1: Documented.
* ffi: bugfix: assign evaluated syntax to bitfield.Kaz Kylheku2017-06-061-1/+2
| | | | | | * ffi.c (ffi_type_compile): Give the bitfield type the evaluated syntax where the width expression is reduced to an integer value.
* c++ maintenance: eliminate old-style casts.Kaz Kylheku2017-06-061-76/+76
| | | | | | | | | | | | | | | | | | | | Old style casts have crept into the code base. * buf.c (make_buf, buf_grow, buf_get_i8, buf_get_u8): Replace old style cast with macro. * ffi.c (align_sw_get, align_sw_put, ffi_be_i32_get, ffi_be_u32_get, ffi_le_i32_put, ffi_le_i32_get, ffi_le_u32_get, ffi_be_i64_put, ffi_be_i64_get, ffi_be_u64_get, ffi_le_i64_put, ffi_le_i64_get, ffi_le_u64_get, ffi_sbit_put, ffi_sbit_get, ffi_init_extra_types): Likewise. * hash.c (hash_buf): Likewise. * itypes.c (c_i32, c_i64, c_u64): Likewise. * stream.c (stdio_put_buf, stdio_fill_buf): Likewise.
* c++ maintenance: signed/unsigned comparisons.Kaz Kylheku2017-06-061-3/+3
| | | | | | | | * ffi.c (ffi_sbit_put, make_ffi_type_struct): Fix signed/unsigned comparison warning from g++. (pad_retval): Likewise. * stream.c (stdio_put_buf, stdio_fill_buf): Likewise.
* ffi: handle endian types as return values.Kaz Kylheku2017-06-051-8/+120
| | | | | | | | | | | * ffi.c (ffi_be_i16_rput, ffi_be_i16_rget, ffi_be_u16_rput, ffi_be_u16_rget, ffi_be_i32_rput, ffi_be_i32_rget, ffi_be_u32_rput, ffi_be_u32_rget, ffi_le_i16_rput, ffi_le_i16_rget, ffi_le_u16_rput, ffi_le_u16_rget, ffi_le_i32_rput, ffi_le_i32_rget, ffi_le_u32_rput, ffi_le_u32_rget): New static functions, on big endian. (ffi_init_types): Wire in these functions for their corresponding types, on big endian.
* ffi: handle misaligned access for arith types.Kaz Kylheku2017-06-051-16/+81
| | | | | | | | | | | | | | | | | | The align feature won't work properly on some machines, since the underlying get and put routines don't handle misaligned access. We address that here. * ffi.c (align_sw_get, align_sw_end, align_sw_put_end, align_sw_put): New macros. (ffi_i16_put, ffi_i16_get, ffi_u16_put, ffi_u16_get, ffi_i32_put, ffi_i32_get, ffi_u32_put, ffi_u32_get, ffi_i64_put, ffi_i64_get, ffi_u64_put, ffi_u64_get, ffi_short_put, ffi_short_get, ffi_ushort_put, ffi_ushort_get, ffi_int_get, ffi_uint_put, ffi_uint_get, ffi_long_put, ffi_long_get, ffi_ulong_put, ffi_ulong_get, ffi_float_put, ffi_float_get, ffi_double_put, ffi_double_get, ffi_val_put, ffi_val_get, ffi_wchar_put, ffi_wchar_get, ffi_sbit_put, ffi_sbit_get, ffi_ubit_put, ffi_ubit_get): Insert macros to redirect the transfer to a temporary aligned buffer if the pointer is misaligned.
* ffi: big and little endian types.Kaz Kylheku2017-06-041-0/+669
| | | | | | | | | | | | | | | | | | | | | | | | | | * ffi.c (be_uint16_s, be_int16_s, be_uint32_s, be_int32_s, be_uint64_s, be_int64_s, be_float_s, be_double_s, le_uint16_s, le_int16_s, le_uint32_s, le_int32_s, le_uint64_s, le_int64_s, le_float_s, le_double_s): New symbol variables. (ffi_be_i16_put, ffi_be_i16_get, ffi_be_u16_put, ffi_be_u16_get, ffi_le_i16_put, ffi_le_i16_get, ffi_le_u16_put, ffi_le_u16_get, ffi_be_i32_put, ffi_be_i32_get, ffi_be_u32_put, ffi_be_u32_get, ffi_le_i32_put, ffi_le_i32_get, ffi_le_u32_put, ffi_le_u32_get, ffi_be_i64_put, ffi_be_i64_get, ffi_be_u64_put, ffi_be_u64_get, ffi_le_i64_put, ffi_le_i64_get, ffi_le_u64_put, ffi_le_u64_get, ffi_be_float_put, ffi_be_float_get, ffi_le_float_put, ffi_le_float_get, ffi_be_double_put, ffi_be_double_get, ffi_le_double_put, ffi_le_double_get): New static functions. (ffi_init_types): Register new type symbols via typedef mechanism. (ffi_init): Initialize new symbol variables. * ffi.c (be_uint16_s, be_int16_s, be_uint32_s, be_int32_s, be_uint64_s, be_int64_s, be_float_s, be_double_s, le_uint16_s, le_int16_s, le_uint32_s, le_int32_s, le_uint64_s, le_int64_s, le_float_s, le_double_s): Declared.
* ffi: new type operator align for customizing alignment.Kaz Kylheku2017-06-041-0/+73
| | | | | | | | | | | | | | | | | | | | | | | * ffi.c (align_s): New symbol variable. (struct txr_ffi_type): New function pointer member, clone. (ffi_simple_clone): New static function. (make_ffi_type_builtin, make_ffi_type_pointer, make_ffi_type_enum): Wire in ffi_simple_clone as the clone function. (ffi_struct_clone): New static function. (make_ffi_type_struct): Wire in ffi_struct_clone as the clone function for struct types. (ffi_array_clone): New static function. (make_ffi_type_array): Wire in ffi_array_clone as the clone function for array types. (ffi_type_copy): New static function. (ffi_type_compile): Recognize new (align <num> <type>) syntax. This works by cloning <type>, and then punching in the specified alignment. The align syntax then denotes this modified type. (ffi_init): Initialize align_s. * ffi.h (align_s): Declared.
* ffi: use expressions for bit field width also.Kaz Kylheku2017-06-031-1/+1
| | | | | | | * ffi.c (ffi_type_compile): Evaluate width argument of sbit and ubit type as as expression. * txr.1: Documented.
* ffi: evaluate expressions in type notation.Kaz Kylheku2017-06-021-15/+29
| | | | | | | | | | | | | | | | | | | | | | | | | Places where an integer constant was previously allowed now allow an expression. The way enum syntax works is now different. A temporary lexical environment is created, and each enumeration is bound in that environment. The value expressions are evaluated in that environment. The decision to allow keyword symbols to be enumeration contants is retracted. * eval.h (special_s): Declared. * ffi.c (ffi_eval_expr): New static function. (make_ffi_type_enum): Enums are introduced into a temporary environment, in which the value expressions are evaluated. By this means, the expressions can refer can refer to previous enums and do arbitrary computation. Also, we drop the requirement that enums can be keyword symbols. (ffi_type_compile): Array dimension and buf size are evaluated as expresions. Array and buffer syntax is transformed by substitution of the evaluated size. * txr.1: Documented use of expressions in FFI type notation.
* ffi: wrong indentation.Kaz Kylheku2017-06-021-2/+2
| | | | | * ffi.c (ffi_type_compile): Fix bad indentation brought about by refactoring.
* ffi: functions and macros for basic type properties.Kaz Kylheku2017-06-021-0/+74
| | | | | | | | | | | | | | | | | | * ffi.c (ffi_alignof, ffi_offsetof, ffi_arraysize, ffi_elemsize, ffi_elemtype): New functions. (ffi_init): Registered intrinsics ffi-alignof, ffi-offsetof, ffi-arraysize, ffi-elemsize, ffi-elemtype. * ffi.h (ffi_alignof, ffi_offsetof, ffi_arraysize, ffi_elemsize, ffi_elemtype): Declared. * lisplib.c (ffi_set_entries): New autoload entries alignof, offsetof, arraysize, elemsize, elemtype. * share/txr/stdlib/ffi.tl (alignof, offsetof, arraysize, elemsize, elemtype): New macros. * txr.1: Documented new functions and macros.
* ffi: don't allow size calculation of bitfield type.Kaz Kylheku2017-06-021-0/+4
| | | | | * ffi.c (ffi_size): Check for a bitfield type and diagnose.
* ffi: new feature: enums.Kaz Kylheku2017-05-311-0/+151
| | | | | | | | | | | | | | | | * ffi.c (enum_s): New symbol variable. (struct txr_ffi_type): New member, sym_num, num_sym. (ffi_enum_type_mark): New static function. (ffi_type_enum_ops): New static structure. (ffi_enum_put, ffi_enum_get, ffi_enum_rput, ffi_enum_rget): New static functions. (make_ffi_type_enum): New static function. (ffi_type_compile): Extend with enum syntax. (ffi_init): Initialize enum_s with new interned symbol. * ffi.c (enum_s): Declared. * txr.1: Documented.
* ffi: bugfix: basic type needs proper mark function.Kaz Kylheku2017-05-311-5/+15
| | | | | | | | * ffi.c (ffi_type_common_mark, ffi_type_mark): New static function (ffi_struct_type_mark, ffi_ptr_type_mark): Use new ffi_type_common_mark function for common members. (ffi_type_builtin_ops): Wire in ffi_type_mark.
* ffi: pad retval to ffi_arg size on all platforms.Kaz Kylheku2017-05-291-4/+5
| | | | | | | | | | * ffi.c (pad_retval): Define same way regardless of big or little endian. For instance, we don't want to call alloca(1) for a char return value. It could be the case on little endian targets that libffi prepares an entire ffi_arg return value. Even though we just read the low order byte, we still have to prepare enough space for the whole thing.
* ffi: bugfix: null out return value to padded size.Kaz Kylheku2017-05-281-1/+1
| | | | | | | * ffi.c (ffi_closure_dispatch_safe): In the abort case when we put zeros in the return value, we must overwrite the entire ffi_arg cell, in adherence with the special return value quirk of libffi.
* ffi: adapt to return value braindamage in libffi.Kaz Kylheku2017-05-281-41/+301
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This change gets TXR FFI working on Power PC 64, big endian. Many thanks to the GCC Compile Farm. Turns out, the libffi API has changed some years ago, with outdated documentation lingering. Return values for the basic integral types must all be handled with a buffer of type ffi_arg and casting. This is true in both ffi_call and closures: in both directions. For instance, if a foreign function returns char, we must retrieve a ffi_arg value (which might be as large as 64 bits). Then we must cast this value to char. In actual fact, on a big endian system with an 8 byte ffi_arg, the char value may be located in byte 7 of the 8 byte buffer, not in byte 0. FFI's own test suite got this wrong and had to be patched back in 2013: it was doing things the way we are doing them: https://sourceware.org/ml/libffi-discuss/2013/msg00199.html The doc was updated at the same time to tell the truth: https://sourceware.org/ml/libffi-discuss/2013/msg00200.html Luckily, we can fix TXR's ffi module without damaging its framework. The object model is flexible enough to absorb the change. Basically, we add two new methods to the txr_ffi_type objects: virtual functions rget and rput. We only add these when targetting big endian. These have the same type signature as get and put, but are specialized for handling return values. For all integer types smaller than 64 bits, these functions are separately implemented with distinct semanics which handle the FFI API requirements with ffi_arg and casting and all. For all other types, rget and rput are identical to get and put. * ffi.c (pad_retval, ifbe, ifbe2): New macros, conditionally defined for big and little endian. (struct txr_ffi_type): New members rput and rget. (ffi_i8_rput, ffi_i8_rget, ffi_u8_rput, ffi_u8_rget, ffi_i16_rput, ffi_i16_rget, ffi_u16_rput, ffi_u16_rget, ffi_i32_rput, ffi_i32_rget, ffi_u32_rput, ffi_u32_rget, ffi_char_rput, ffi_char_rget, ffi_uchar_rput, ffi_uchar_rget, ffi_bchar_rget, ffi_short_rput, ffi_short_rget, ffi_ushort_rput, ffi_ushort_rget, ffi_int_rput, ffi_int_rget, ffi_uint_rput, ffi_uint_rget, ffi_long_rput, ffi_long_rget, ffi_ulong_rput, ffi_ulong_rget, ffi_wchar_rput): New functions. (make_ffi_type_builtin): Take rput and rget arguments, regardless of platform. On big endian, store these in the corresponding members. If they are null, duplicate get and put instead. (ffi_type_compile, ffi_init_types): Specify the rput and rget functions for the basic types, using the ifbe macro which nullifies the references to functions when they don't exist on little endian. For all other types, pass the new arguments as null. (ffi_call_wrap): Pad the return vaue buffer size to a minimum size on big endian; it must be at least sizeof (ffi_alloc). Use the rget method for the return value on big endian. (ffi_closure_dispatch, ffi_closure_dispatch_safe): Use rput on big endian for storing return value.
* ffi: remove redundant flag calc in call wrapper.Kaz Kylheku2017-05-261-1/+0
| | | | | | * ffi.c (ffi_call_wrap): Don't calculate in_pass_needed in put loop, since we already calculated it in the argument buffer allocation loop.
* ffi: bitfield support.Kaz Kylheku2017-05-251-26/+210
| | | | | | | | | | | | | | | | | | | | | | | * ffi.c (sbit_s, ubit_s): New symbol variables. (struct txr_ffi_type): New members, shift and mask. (ffi_sbit_put, ffi_sbit_get, ffi_ubit_put, ffi_ubit_get, bitfield_syntax_p): New static functions. (make_ffi_type_pointer): Disallow pointers to bitfields. (make_ffi_type_struct): Process bitfield members and set up shifts and masks accordingly. Recently introduced bug fixed here at the same time: the alignment calculation for each member must be done top-of-loop. (ffi_struct_compile): Exclude bitfields from the check against members with zero type. Compile the bitfield syntax. (ffi_typedef): Do not allow typedefs of bitfield type. Not only doesn't this make sense, but bitfield types are destructively modified in make_ffi_type_struct: they are imbued with a mask and offset tied to their position in a particular struct. * ffi.h (sbit_s, ubit_s): Delared. * txr.1: Documented bitfields.
* ffi: bugfix: remove nil slots when making struct.Kaz Kylheku2017-05-251-1/+2
| | | | | | | | | * ffi.c (ffi_type_compile): In the case when a struct type is compiled and the Lisp struct doesn't exist, the function creates the struct type. However, the FFI struct type syntax allows nil as a slot name, indicating a padding field. These nils must be scrubbed from the slot list when making the Lisp struct type, or else an error occurs.
* ffi: bugfix: gc-correct handling of memb array.Kaz Kylheku2017-05-251-2/+2
| | | | | | | | | | * ffi.c (make_ffi_type_struct): Use calloc for allocating memb, so all the Lisp objects in it are initially nil. Then install it into the structure upfront. Afterward, as we iterate over the slots and types and install them into the array, we lose references to them. But now since the array is now wired into the FFI struct type structure, these objects are now visible to GC.
* ffi: don't compile struct member type twice.Kaz Kylheku2017-05-251-1/+1
| | | | | | * ffi.c (ffi_struct_compile): Eliminate redundant call to ffi_type_compile, replacing it with the compiled type we already have.
* ffi: bugfix: incorrect error throws in buf ops.Kaz Kylheku2017-05-251-4/+4
| | | | | * ffi.c (ffi_put_into, ffi_in, ffi_get, ffi_out): Add missing error symbol argument in uw_throwf calls.
* ffi: precompute member offsets in struct type.Kaz Kylheku2017-05-251-26/+14
| | | | | | | | | | | | | | This change will make bitfield support easier. * ffi.c (struct smemb): New member, offs. (ffi_struct_in, ffi_struct_put, ffi_struct_out, ffi_struct_get, ffi_struct_release): For each member, refer to the offset in the memb array, rather than calculating it on-the-fly. (make_ffi_type_struct): Calculate the offset for each member. This is exactly the same as the total_size calculation before; just the name is changed to offs, and bit operations are used for the alignment calculations.
* ffi: use array for struct member description.Kaz Kylheku2017-05-241-40/+56
| | | | | | | | | | | | | | | | | * ffi.c (struct smemb): New struct type. (struct txr_ffi_type): Removed members mnames and mtypes. New member memb. (ffi_type_struct_destroy_op): Free the new memb descriptor array, and overwrite with null pointer. (ffi_struct_type_mark): Mark eltype only if not nil. If memb pointer is not nil, walk the array and mark it. Remove marking of removed mtypes and mnames members. (ffi_ptr_in_release, ffi_struct_in, ffi_struct_put, ffi_struct_out, ffi_struct_get, ffi_struct_release): Walk the struct members using the new array descriptor. (make_ffi_type_struct): Allocate the memb array, and initialize it. Remove initialization of mnames and mtypes. (make_ffi_type_array): Remove initialization of mnames.