summaryrefslogtreecommitdiffstats
path: root/ffi.c
Commit message (Collapse)AuthorAgeFilesLines
...
* ffi: remove put functions which duplicate others.Kaz Kylheku2017-05-031-31/+2
| | | | | | | | | | * ffi.c (ffi_ptr_in_put): Static function removed. It was functionally identical to ffi_ptr_put, plus a memory leak bug in the nil object case. (ffi_ptr_in_d_put): Static function removed, also identical to ffi_ptr_put. (ffi_type_compile): Replace references to removed functions with ffi_ptr_put.
* ffi: issue with struct/vector slots that are nil.Kaz Kylheku2017-05-031-19/+33
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The problem is as follows. When an aggregate is being passed by pointer, the C code can update its elements. If any of those elements are declared arrays or structs to FFI, but the actual Lips object has nil slot values for those elements, then things don't work, because nil cannot be mutated in place to become a filled vector or struct. The solution is to alter the in virtual function so that it can return a value, just like the get virtual function. When the in function for an array or struct finds it is working with a nil Lisp object, it can construct a representative instance and fill in that one, then return it. * ffi.c (struct txr_ffi_type): Change return type of in function to val. (ffi_freeing_in, ffi_ptr_in_in, ffi_ptr_out_in): Return type changes to val, obj that is passed in is returned. (ffi_struct_in): Return type changes to val. If the Lisp structure passed in is nil, then construct a default instance of the structure by invoking make_struct on the type, with no arguments, and then operate on that structure. In either case, return the structure. (ffi_array_in): Similar change to ffi_struct_in. In the cases when we are converting character arrays to strings, if the Lisp object is nil, we just take the decoded string as the array and return that. In the regular array case, we check for the object being nil, and if so, construct an empty vector in the right size, then fill it. (make_ffi_type_pointer): in parameter's return type changes to val.
* ffi: define various C and POSIX types as typedefs.Kaz Kylheku2017-05-031-0/+97
| | | | | | * ffi.c (ffi_type_lookup, ffi_init_extra_types): New functions. (ffi_init): Call ffi_init_extra_types.
* ffi: instantiate simple types just once.Kaz Kylheku2017-05-031-123/+119
| | | | | | | | | * ffi.c (ffi_type_compile): All cases where the syntax is an atom just go through the ffi_typedef_hash lookup to retrieve a single type instance. (ffi_init_types): New function. Populates typedefs using construction code that was previously in ffi_type_compile. (ffi_init): Call ffi_init_types.
* ffi: use single type node in arrays.Kaz Kylheku2017-05-021-44/+35
| | | | | | | | | | | | | Since we don't have the rtidx members in the txr_ffi_type structure, there is no need to instantiate a type for each element of an array. All elements can now share the one type. * ffi.c (ffi_array_in, ffi_array_put, ffi_array_out, ffi_array_get, make_ffi_type_array): Refactor according to tft->mtypes no longer being a list but a single type. (ffi_type_compile): Do not recompile the syntax n times for each element.
* ffi: remove ffi-copy-type.Kaz Kylheku2017-05-021-37/+1
| | | | | | | | | | | | | | | | | We don't need type copying because the need for this was driven by the rtvec implementation, which assigned a unique rtidx to the nodes in a type tree, requiring like types to be separately instantiated. * ffi.c (struct txr_ffi_type): Remove member dup. (ffi_struct_dup, ffi_ptr_dup): Function removed. (make_ffi_type_builtin, make_ffi_type_struct, make_ffi_type_array): Don't initialize dup. (ffi_copy_type): Function removed. (ffi_type_compile): don't call ffi_copy_type. (ffi_init): ffi-copy-type intrinsic removed. * ffi.h (ffi_copy_type): Declaration removed.
* ffi: remove rtidx, rtsize, walk.Kaz Kylheku2017-05-021-64/+1
| | | | | | | | | | | | | | | | | Remove features related to the supporting the removed rtvec mechanism. * ffi.c (struct txr_ffi_type): Member rtidx, rtsize and walk removed. (ffi_ptr_walk, ffi_struct_walk, ffi_type_walk, assign_rtindices_visit, ffi_type_assign_rtindices, ffi_compile_toplevel): Functions removed. (make_ffi_type_pointer, make_ffi_type_struct, make_ffi_type_array): Don't initialize rtsize and walk. (ffi_type_compile): Don't initialize a type's rtsize. (ffi_init): ffi-type-compile registereed to ffi_type_compile rather than ffi_type_compile_toplevel, as was originally the case.
* ffi: remove the rtvec mechanism.Kaz Kylheku2017-05-021-90/+61
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Removing the rtvec[] mechanism for tracking temporary allocations. The tft->in() calls are already walking the object layout and so pointers can just be retrieved from the object memory. This changes the semantics: for the better, I think. For example if a struct contains a (ptr str) and is passed as (ptr (struct ...)), the C string is temporarily allocated and stored in the C structure before the call, then freed after the call. Now the freeing action retrieves the char * pointer from the structure itself rather than rtvec. The semantics change is that the pointer may have been altered by the C function. We may be freeing a pointer other than the one we allocated. C code which replaces the pointer must malloc it, and free the original. * ffi.c (struct txr_ffi_type): put and in virtual function pointers lose the rtvec parameter. (ffi_void_put ffi_i8_put, ffi_u8_put, ffi_i16_put, ffi_u16_put, ffi_i32_put, ffi_u32_put, ffi_i64_put, ffi_u64_put, ffi_char_put, ffi_uchar_put, ffi_short_put, ffi_ushort_put, ffi_int_put, ffi_uint_put, ffi_long_put, ffi_ulong_put, ffi_float_put, ffi_double_put, ffi_wchar_put, ffi_cptr_put, ffi_str_d_put, ffi_wstr_put, ffi_wstr_d_put, ffi_buf_put, ffi_buf_d_put, ffi_closure_put): Drop unused rtvec parameter. (freeing_in, ffi_ptr_in_in, ffi_ptr_out_in): Drop rtvec parameter. Obtain pointer from src buffer instead. (ffi_str_put, ffi_ptr_in_put, ffi_ptr_out_put, ffi_ptr_put): Drop rtvec parameter and remove code which stored into rtvec. (ffi_ptr_in_d_put, ffi_struct_put, ffi_array_put): Drop rtvec parameter; don't pass to recursive put call. (ffi_struct_in, ffi_array_in): Drop rtvec parameter; don't pass to recursive in call. (make_ffi_type_builtin, make_ffi_type_pointer): Adjust pointer parameter declarators for put and in parameters. (ffi_call_wrap): Remove allocation and use of rtvec. Pass the values[i] pointer as the src parameter in the to level in call. (ffi_closure_dispatch): Don't pass rtvec parameter to put call.
* ffi: remove void casts for unused parameters.Kaz Kylheku2017-05-021-117/+0
| | | | | | | | | | | | | | | | | | | * ffi.c (ffi_void_put, ffi_fixed_alloc, ffi_noop_free, ffi_void_get, ffi_i8_put, ffi_i8_get, ffi_u8_put, ffi_u8_get, 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_char_put, ffi_char_get, ffi_uchar_put, ffi_uchar_get, ffi_short_put, ffi_short_get, ffi_ushort_put, ffi_ushort_get, ffi_int_put, 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_wchar_put, ffi_wchar_get, ffi_cptr_put, ffi_cptr_get, ffi_cptr_alloc, ffi_freeing_in, ffi_str_d_put, ffi_str_get, ffi_str_d_get, ffi_wstr_put, ffi_wstr_get, ffi_wstr_d_put, ffi_wstr_d_get, ffi_buf_put, ffi_buf_get, ffi_buf_d_put, ffi_buf_d_get, ffi_buf_alloc, ffi_ptr_in_d_put): Removed void casts from these functions.
* ffi: simple typedef mechanism.Kaz Kylheku2017-05-011-0/+16
| | | | | | | | | | | | * ffi.c (ffi_typedef_hash): New static variable. (ffi_type_compile): Handle undefined atom case by trying through typedef hash. (ffi_typedef): New function. (ffi_init): gc-protect ffi_type_compile variable and initialize it with a hash table. Register ffi-typedef intrinsic. * ffi.h (ffi_typedef): Declared
* ffi: support for duplicating type objects.Kaz Kylheku2017-05-011-0/+36
| | | | | | | | | | | | * ffi.c (struct txr_ffi_type): New member, dup. (ffi_struct_dup, ffi_ptr_dup): New static functions. (make_ffi_type_pointer, make_ffi_type_struct, make_ffi_type_array): Set up dup virtual function for these types. (ffi_copy_type): New function. (ffi_init): Register ffi-copy-type intrinsic. * ffi.h (ffi_copy_type): Declared.
* ffi: more complete string semantics for char arrays.Kaz Kylheku2017-05-011-12/+50
| | | | | | | * ffi.c (ffi_array_in): Support the char_conv and wchar_conv flags similarly in ffi_array_get. This allows (ptr (array n char)) to receive data from the C buffer as a string, storing it into the string object.
* ffi: memory handling in callback interface.Kaz Kylheku2017-05-011-9/+108
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We need to extend the existing framework to handle the requirement that the callback can update objects passed by pointer, such that the changes are propagated to the original C objects. For instance, a callback receives a pointer to a struct with some strings. The Lisp code updates the strings and we would like the strings to appear back in the C code. The functions which support this sort of thing in the call direction are not quite suitable for this purpose, because that system relies on being able to nail temporary buffers into a stack-allocated rtvec[] which is cleaned up after the FFI call. Anything we write back to a C structure in a FFI callback is is gone out the door; we don't get to clean up any temporary malloced storage. * ffi.c (struct txr_ffi_type): New member out: a virtual fucnction which is like in, but in the opposite direction, and not relying in rtvec. The copy flag argument tells the function whether to just recurse, or whether perform copying, or just recursion. (ffi_ptr_in_out, ffi_ptr_out_out, ffi_struct_out, ffi_array_out): New static functions. (make_ffi_type_pointer): Take an a new parameter for specifying out functions, and store it. (make_ffi_type_struct): Set up an out handler for a struct type or array which needs one. It is needed if any of the element types have an out handler. Basic types don't have out handlers; ptr types do. What if a struct is full of basic types and has no out handler, and is the object of an out pointer? In that case, the logic in ffi_ptr_out_out handles it; it notices that its target type has no out handler, and uses the struct's put function instead to update the underlying C buffer. (ffi_type_compile): Add in functions to ptr types. (ffi_closure_dispatch): After calling the Lisp function, perform a pass of out calls over the parameters, if necessary.
* ffi: bugfix: aggregate fill logic doesn't recurse.Kaz Kylheku2017-05-011-67/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Removing the fill virtual function, because it stops the in recursion, failing to reach out pointers at deeper nesting levels. The fill responsibility is moved into in. Aggregates now unconditionally have an in, which takes a src parameter that can be null to indicate that no copying should take place, only recursion. * ffi.c (struct txr_ffi_type): Member function pointer in gets new parameter src. Member fill is removed. (ffi_freeing_in, ffi_ptr_in_in): Add ignored src parameter. (ffi_ptr_out_in): Add ignored parameter. Instead of calling the target type's fill, recurse on its in. The src location in the recursive call is the previously allocated buffer. (ffi_struct_in): Take src parameter. Walk the object's layout, skipping through src buffer. For any member type which has an in handler, recurse on that, using the displaced src location, and the corresponding struct element object. For members which don't have an in handler, do the logic that was previously done by fill logic: get the value from the displaced src location, and store into the struct slot. (ffi_struct_fill): Function removed. (ffi_array_in): Analogous change to one done to ffi_struct_in. (ffi_array_fill): Function removed. (make_ffi_type_pointer): Declaration adjusted due to change in in pointer parameter. (make_ffi_type_struct, make_ffi_type_array): Set up in function unconditionally. (ffi_call_wrap): Pass new src argument to in calls. This is specified as null since the top level is by-value arguments.
* ffi: allow get for ptr-in and ptr-in-d.Kaz Kylheku2017-05-011-7/+7
| | | | | | This supports some benign ambiguity, allowing the user to specify an extracted ptr return value as ptr-in or ptr-in-d, and have it work.
* ffi: closure leak.Kaz Kylheku2017-04-301-0/+1
| | | | * ffi.c (ffi_closure_destroy_op): Free the closure descriptor.
* ffi: support anonymous padding in structs.Kaz Kylheku2017-04-301-7/+14
| | | | | | | | | | | | | | | If the ffi struct type operator specifies nil as a slot name, then we treat the member as anonymous padding. When reading a struct from a buffer, we skip the padding. When writing out a struct to a buffer, we generate zeros in the size of the anonymous member. The type of the member is ignored, except for calculating the size. * ffi.c (ffi_struct_put): If the slot name is nil, don't recursively call put; just use memset to fill the target with zero bytes. (ffi_struct_get, ffi_struct_fill): If the slot name is nil, don't call get to fetch data. Just skip the area.
* ffi: fix destructor related leaks and corruption.Kaz Kylheku2017-04-301-12/+3
| | | | | | | | | * ffi.c (ffi_type_struct_destroy_op): Do not free the elements[] array of the ffi_type. They are often not dynamically allocated at all, and if they are, the management of that belongs to the child object. On the other hand, the elements array itself must be freed, which was not being done! (ffi_call_desc_destroy_op): Forgot to free the COBJ handle.
* ffi: implementing FFI callback closures.Kaz Kylheku2017-04-301-1/+146
| | | | | | | | | | | | | | | | | | | * ffi.c (closure_s, ffi_closure_s): New symbol vars. (struct txr_ffi_closure): New type. (ffi_closure_struct, ffi_closure_struct_checked, ffi_closure_print_op, ffi_closure_destroy_op, ffi_closure_mark_op): New static functions. (ffi_closure_ops): New static struct. (ffi_closure_put): New static function. (ffi_type_compile): Handle closure_s to support closure type specifier. (ffi_closure_dispatch): New static function. (ffi_make_closure, ffi_closure_get_fptr): New function. (ffi_init): Initialize closure_ and ffi_closure_s. Register ffi-make-closure intrinsic. * ffi.c (closure_s, ffi_closure_s, ffi_make_closure, ffi_closure_get_fptr): Likewise.
* ffi: put function for str-d needed.Kaz Kylheku2017-04-301-1/+16
| | | | | | | | | | * ffi.c (ffi_str_d_put): New static function. (ffi_type_compile): Use ffi_str_d_put for str-d instead of ffi_str_put. The difference is that ffi_str_d_put doesn't place the pointer into the rtvec[] array. Doing so is wrong because this ttype of string has no reserved place in that array, and no registered in handler to free it (which would be wrong).
* ffi: housecleaning: reorder type sym declarations.Kaz Kylheku2017-04-301-4/+2
| | | | | | | | | | | | * ffi.c: Move declarations of array_s and zarray_s after void_s, to keep built-in FFI types together. Eliminate some blank lines. (ffi_init): Move initialization of void_s to to match declaration order. * ffi.h: Update declarations of type symbol variables to match ffi.c. (struct_s): Now declared.
* ffi: str, wstr and buf convert nil and null pointers.Kaz Kylheku2017-04-291-26/+47
| | | | | | | | | | * ffi.c (ffi_str_put, ffi_wstr_put, ffi_wstr_d_put, ffi_buf_put, ffi_d_put): If the object is nil, store a null pointer into the target buffer, and into the rtvec. (ffi_str_get, ffi_str_d_get, ffi_wstr_get, ffi_wstr_d_get, ffi_buf_get, ffi_d_get): Return nil if the pointer is null.
* ffi: conv between strings and char/wchar_t arrays.Kaz Kylheku2017-04-291-12/+47
| | | | | | | | | | | | | | * ffi.c (struct txr_ffi_type): New bitfield members char_conv, wchar_conv. (ffi_array_put): Check char_conv and wchar_conv flags and perform conversion to string, watching out for the presence or absence of null termination. (ffi_type_compile): When compiling array, check for the str and wstr element type, and set the flags. * utf8.c (ut8f_dup_from_buf): New function. * utf8.c (ut8f_dup_from_buf): Declared.
* ffi: add support for wchar_t type.Kaz Kylheku2017-04-291-1/+34
| | | | | | | | | | | | We have wstr strings already but no wchar type. * ffi.c (wchar_s): New symbol variable. (ffi_type_wchar): New macro. (ffi_wchar_put, ffi_wchar_get): New static functions. (ffi_type_compile): Handle wchar_s. (ffi_init): Initialize wchar_s. * ffi.h (wchar_s): Declared.
* ffi: ptr types map between nil and null pointers.Kaz Kylheku2017-04-291-16/+33
| | | | | | | | | | | On the way out, if a ptr or ptr-in type encounters nil, it passes a null pointer. On the way in, a null C pointer received by a ptr type turns to the nil object. * ffi.c (ffi_ptr_in_put, ffi_ptr_in_d_put, ffi_ptr_out_put, ffi_ptr_put): Check for nil, and put out null pointer in that case. (ffi_ptr_out_get, ffi_ptr_out_d_get): Check for null pointer coming in and turn to nil.
* ffi: zarray type for null terminated array support.Kaz Kylheku2017-04-291-3/+19
| | | | | | | | | | | | | | | | | | | | | A zarray is null terminated when we convert from Lisp to C representation. The last element of the Lisp vector is ignored and all zero bits are written to the destination buffer in the size of the element. * ffi.c (zarray_s): New symbol variable. (struct txr_ffi_type): New bitfield member, null_term. (ffi_array_in): If the array's null_term flag is set, then don't process the last element, since the corresponding put call wasn't done for that element in ffi_array_put. (ffi_array_put): If the array's null_term flag is set, then when processing the last element, just memset the output element to zero and don't call put. (ffi_type_compile): Recognize zarray_s and set up the flag accordingly. (ffi_init): Initialize zarray_s. * ffi.h (zarray_s): Declared.
* ffi: add ptr-in-d and ptr-out-d.Kaz Kylheku2017-04-291-2/+37
| | | | | | | | | | | | | | | | | | | | ptr-in-d means we pass a buffer to the foreign function, which it owns and must free. We don't touch it. ptr-out-d is meaningful for returned values. It means that the function returned the object in a malloced buffer which the caller owns. It will be freed. * ffi.c (ptr_in_d_s, ptr_out_d_s): New symbol variables. (ffi_ptr_in_d_put, ffi_ptr_out_d_get): New static functions. (make_ffi_type_pointer): Don't set rtsize unconditionally to 1. If we are passed a null pointer for the in function, set it to zero. ptr-in-d does this: it has no need to free the buffer since the called function owns it and so there is no in function for that type. (ffi_type_compile): Handle ptr_in_d_s and ptr_out_d_s. (ffi_init): Initialize ptr_in_d_s and ptr_out_d_s. * ffi.h (ptr_in_d_s, ptr_out_d_s): Declared.
* ffi: nicer messages from type compiler.Kaz Kylheku2017-04-291-2/+3
| | | | * ffi.c (ffi_type_compile): Improved error reporting.
* ffi: rename ptr-in-out to just ptr.Kaz Kylheku2017-04-291-6/+6
| | | | | | | | | | | | Why have this verbose naming for the most basic case. Rather, ptr-in and ptr-out are optimizations of ptr which just avoid copying the object in one direction. * ffi.c (ptr_in_out_s): Renamed to ptr_s. (ffi_ptr_in_out_put): Renamed to ffi_ptr_put. (ffi_type_compile, ffi_init): Follow rename. * ffi.h (ptr_in_out_s): Declaration updated
* ffi: malloc-free variants for str, dstr and buf.Kaz Kylheku2017-04-291-7/+68
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The FFI types str-d, wstr-d and buf-d are like their unsuffixed counterparts, but indicate that ownership of a dynamically allocated object is being passed which the receiver is responsible for freeing. If we pass a str, wstr or buf into a foreign function, we are generally only guaranteeing the lifetime of the buffer over the function call. If we pass a str-d or buf-d, then the callee keeps the pointer indefinitely, and must free it. If we get str or buf return value from a function, it is assumed that the pointer is static or something borrowed with some limited lifetime. A copy of it is made. If we get a str-d, wstr-d or buf-d, it is assumed that the pointer has been malloc-ed for us. The object is either duplicated, and the original one immediately freed, or else the pointer is retained directly in the Lisp object and freed if that object becomes garbage. * ffi.c (str_d_s, wstr_d_s, buf_d_s): New symbol variables. (ffi_str_get): Coalesce assignment with declaration. (ffi_str_d_get, ffi_str_d_put): New static functions. (ffi_buf_d_get, ffi_buf_d_put): New static functions. (ffi_type_compile): Handle buf_d_s, str_d_s and wstr_d_s. (ffi_init): Initialize str_d_s, wstr_d_s and buf_d_s. * ffi.c (str_d_s, wstr_d_s, buf_d_s): Declared.
* ffi: correct treatment of (ptr buf).Kaz Kylheku2017-04-291-1/+1
| | | | | | | | | | | | | | The buf FFI type's alloc virtual should return a pointer to the buffer's pointer, not the buffer itself. What's currently going on is something silly, whereby the pointer to the buffer is stored into the buffer itself. * buf.c (buf_addr_of): New function. * buf.c (buf_addr_of): Declared. * ffi.c (ffi_buf_alloc): Use buf_addr_of instead of buf_get.
* ffi: bugfix: ptr-in doesn't write pointer.Kaz Kylheku2017-04-281-0/+1
| | | | | | * ffi.c (ffi_ptr_in_put): We must write the allocated buffer's pointer to the destination memory location, otherwise nothing is passed, but garbage.
* ffi: drop obsolete restrictions in type compiler.Kaz Kylheku2017-04-281-8/+0
| | | | | | * ffi.c (ffi_type_compile): The ptr-out and ptr-in-out types can work with target types that don't have a fill function and fixed allocation.
* ffi: sane calculation of rtsize.Kaz Kylheku2017-04-281-9/+7
| | | | | | | | | | | | | | | | | | | | | | | | | We are wastefully giving structs and arrays a position in the rtvec. They do not need one. Let's calculate like this. During compilation, let's assign a rtsize value of 1 to types which need to occupy a position. During the tree walk which assigns the positions, let's use this as a Boolean value indicating whether to assign and index or not. After the tree walk, the final counter value indictates the rtsize for the whole aggregate, and we store that in the rtsize of the root type node. * ffi.c (make_ffi_type_struct, make_ffi_type_array): Do not add up the rtsizes of the elements/members and thus do not install the total size as this type's rtsize. Leave the rtsize zero. We revert to a variation of the previous method of determining whether to install the in handler, but using a slightly different criterion: if any child element has a nonzero rtsize or if it has an in handler. (assign_rtindices_visit): Use nonzero rtsize as the condition for whether to give the node an rtindex or not. (ffi_type_assign_rtindices): Store the final count as the rtsize of the root type node. This is then used to allocate the rtvec for that type in ffi_call_wrap.
* ffi: assign better Lisp types to some ffi types.Kaz Kylheku2017-04-281-4/+4
| | | | | | * ffi.c (ffi_type_compile): Type descriptors for str, wstr, buf and void are being tagged with the Lisp type cptr. Let's give them str, str, buf and null, respectively.
* ffi: move run-time state out of txr_ffi_type.Kaz Kylheku2017-04-281-112/+200
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The txr_ffi_type has the buf member, which is manipulated when FFI calls are being dispatched. That is wrongly non-reentrant; it will interfere with the same type structure being used recursively. The objects describing FFI types must be treated as immutable with respect to dynamic FFI processing. The approach here is is to move these buf pointers into a a run-time vector ("rtvec"). The types whose handling requires the temporary buf pointer are assigned a position in that vector (the "rtidx"). These positions are assigned to the nodes of a type by a tree walking step after compilation. When performing a FFI call, we allocate space for the rtvec for each argument type. This is vector is passed down into the data transfer calls, and is used wherever needed, using a type's rtidx to find its buffer pointer location. * ffi.c (struct txr_ffi_type): function functoin poiner member, walk. The put and in functions get a new argument: the rtvec. New members rtidx and rtsize. The buf member is removed. (ffi_builtin_type_destruct_destroy_op): Static function removed. There is no need to clean any run-time buffer from a type, since types are no longer associated with any such thing. And that leaves the function just freeing the obj->co.handle which is already done by cobj_destroy_free_op. (ffi_type_struct_destroy_op, ffi_type_struct_destroy_op): Remove the call to the in virtual function for the same reason. (ffi_type_builtin_ops, ffi_type_ptr_ops): Replace removed ffi_builtin_type_struct_destroy_op with cobj_destroy_free_op. (ffi_void_put, ffi_i8_put, ffi_u8_put, ffi_i16_put, ffi_u16_put, ffi_i32_put, ffi_u32_put, ffi_i64_put, ffi_u64_put, ffi_char_put, ffi_uchar_put, ffi_short_put, ffi_ushort_put, ffi_int_put, ffi_uint_put, ffi_long_put, ffi_ulong_put, ffi_float_put, ffi_double_put, ffi_cptr_put): Conform to new put interface with the rtvec argument. It is ignored in all these functions. (ffi_freeing_in, ffi_str_put, ffi_wstr_put, ffi_buf_put, ffi_ptr_in_in, ffi_ptr_in_put, ffi_ptr_out_in, ffi_ptr_out_put, ffi_ptr_in_out_put, ffi_struct_in, ffi_struct_put, ffi_array_in, ffi_array_put) Conform to new function interface with the rtvec and use it together with the rtidx from the type to store and retrieve the buf, if necessary. (ffi_ptr_walk, ffi_struct_walk): New functions. (make_ffi_type_builtin): Parameter declaration updated due to changes in put and in function pointer types. (make_ffi_type_pointer): Configure pointer's rtsize to 1 since pointers manage temporary buffers, and give it the ffi_ptr_walk function, since it has a subordinate type which it must visit. (make_ffi_type_struct): Calculate the size of the rtvec which a struct's members need. Use the nonzero value of this as the indication that the structure need's an in function, thus eliminating the loop flag being used for this purpose. Install the ffi_struct_walk function for walk. (make_ffi_type_array): Similar changes as in make_ffi_type_struct. Calculate rtsize from element rtsize times number of elements. If that is nonzero wire in ffi_array_in. Also wire in ffi_struct_walk. (ffi_type_walk): New static function. (assign_rtindices_visit, ffi_type_assign_rtindices): New functions. (ffi_type_compile): Set the rtsize for the str type to 1, because it manages a temporary buffer across the FFI call, and thus needs a slot in the rtvec. (ffi_type_compile_toplevel): New function. (ffi_call_wrap): Allocate vector of rtvectors based on total number of arguments. For each argument allocate an rtvector in this vector, if necessary and pass down to the put calls. Then pass to the in calls after the FFI call returns. Thus the framework has the proper environment where to store all the temporary buffer pointers that need to be communicated from the pre-call data transfer pass to the subsequent cleanup. (ffi_init): Register the ffi_type_compile_toplevel function as the ffi-type-compile intrinsic, rather than the ffi_type_compile function. Application space probably doesn't need to have exposure to compiler output which doesn't have the correct rtidx values, and there is a risk it could be accidentally used.
* ffi: setup in functions at type compile time.Kaz Kylheku2017-04-281-18/+19
| | | | | | | | | | | | | | | | | | | | * ffi.c (ffi_str_put, ffi_ptr_in_put, ffi_ptr_out_put, ffi_ptr_in_out_put): Don't set up tft->in pointer at dynamic time; this is now being done at static time, in ffi_type_compile. (ff_struct_put, ffi_array_put): Similarly, don't calculate whether an in handler is needed or not based on the child type elements; this is determined statically. (make_ffi_type_pointer): Take an in function pointer argument, since all callers need to set this up. (make_ffi_type_struct): Set up an in handler for this type if any of the structure element types need one. (make_ffi_type_array): Set up an in handler for this type if the element type needs it. (ffi_type_compile): For the three ptr types, pass the appropriate in function to make_ffi_type_pointer. For the str type, set up the in pointer to ffi_freeing_in, after constructing as a builtin type.
* ffi: rename cptr-related functions.Kaz Kylheku2017-04-281-5/+5
| | | | | | | | | | This naming is confusing because a ptr is something else and other functions with _ptr_ in their name pertain to the ptr -type for referential passing. * ffi.c (ffi_ptr_put, ffi_ptr_get, ffi_ptr_alloc): Rename to ffi_cptr_put, ffi_cptr_get, ffi_cptr_alloc. (ffi_type_compile): Follow rename.
* ffi: allow ptr-in-out passing of cptr.Kaz Kylheku2017-04-281-3/+20
| | | | | | | | | | | | | | | * ffi.c (ffi_ptr_alloc): New static function. (ffi_type_compile): Give the cptr type alloc and free functions: alloc just retrives the address of the pointer inside the cptr object (pointer to pointer); free is a noop. (cptr_make): New static function. (ffi_init): Register cptr_make as cptr intrinsic. Register cptr-null intrinsic variable denoting a ready-made null pointer. * lib.c (cptr_addr_of): New function. * lib.h (cptr_addr_of): Declared.
* ffi: use chk_calloc for txr_ffi_type.Kaz Kylheku2017-04-281-4/+2
| | | | | | | | | Let's defend against uninitialized struct member bugs over this type which has grown somewhat complicated. * ffi.c (make_ffi_type_struct): Use chk_calloc for tft. (make_ffi_type_array): Likewise, and remove a couple of explicit zero initializations.
* ffi: buf type doesn't need fill function.Kaz Kylheku2017-04-281-11/+2
| | | | | | | | | | | | | The fill function is useless, because the object is already filled directly. It's just performing an exactly overlapping memcpy. * ffi.c (ffi_buf_alloc): Function removed. (ffi_type_compile): We can't use the presence or absence of the fill function as the test whether a type can be passed by ptr-in-out or ptr-out, since buf can be passed that way and has no fill. A better criterion is "has no fill and use the fixed size allocation". Removing the assignment statements which set up the fill function for buffers.
* ffi: properly recurse the handling of pointers.Kaz Kylheku2017-04-271-18/+64
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | The FFI type system needs to handle out and in-out pointers at nested levels. We are only doing the tft->in(...) calls on the top-level parameters so this doesn't happen. What's worse, because the tft->put(...) calls recurse, they prepare buffers which are not being freed because freeing is the responsibility of tft->in(...) calls. Because the type descriptor structures also store run-time state, this change requires us to change how arrays are treated. The array elements cannot share the same type descriptor since each could hold a different buffer. * ffi.c (ffi_struct_in): New static function. (ffi_struct_put): Determine whether any of the members need their in function called. If so, set this struct type's in to point to ffi_struct_in. (ffi_array_in): New static function. (ffi_array_put): Determine whether any of the array elements need their in function called. If so, set this struct type's in to point to ffi_array_in. Treat tft->mtypes as a type descriptor list, rather than a single type. (ffi_array_get, ffi_array_fill, make_ffi_type_array): Treat tft->mtypes as a type descriptor list, rather than a single type. (ffi_type_compile): Compile the type expression of an array as many times as the number of dimensions and gather into a list, then pass that list to make_ffi_type_array.
* ffi: fix problems caught by g++.Kaz Kylheku2017-04-271-7/+4
| | | | | | | | | | | | | | * ffi.c (float_s): Variable removed. This is a duplicate definition; we already have this symbol in lib.c. (ffi_type_s): Duplicate definition removed; it is repeated two lines below. (ffi_str_put): Remove pointless const qualifier on u8s variable. (ffi_call_wrap): Cast return value of alloca. Also, rc pointer needs to be cast to mem_t *. (ffi_init): Remove initialization of float_s. * ffi.h (float_s): Declaration removed.
* ffi: sane in/out protocol; buffers work directly.Kaz Kylheku2017-04-271-6/+46
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fix incorrect memory allocation in (ptr-in buf) and (ptr-in-out buf) passing. Buffer arguments passed to a function as (ptr-in buf) or (ptr-in-out buf) now pass the buffer directly without allocating another copy, as in the case of arrays or structs. * ffi.c (struct txr_ffi_type): New members alloc, free. The pointer types use these functions, together with fill, for the management of the buffering of their target type. (ffi_fixed_alloc, ffi_noop_free, ffi_buf_alloc, ffi_ptr_in_in): New static functions. (ffi_ptr_in_put): Use target type's alloc function, rather than chk_malloc. A struct or array will actually allocate the buffer needed for their C version. A buffer will not; it will just return its internal pointer, just like what the wstr type does with strings. This function now sets up ffi_ptr_in_in as the in handler for this pointer type, rather than ffi_freeing_in, because the freeing has to go through the target type interface, and not directly to free. Buffers use the no-op free function. (ffi_ptr_out_in): Use the target type's free function rathr than free. (ffi_ptr_out_put, ffi_ptr_in_out_put): Use the target type's allocator instead of chk_malloc. (make_ffi_type_pointer, make_ffi_type_struct, make_ffi_type_array): Initialize the alloc and free function pointer members of the txr_ffi_type struct. (ffi_type_compile): Set up alloc and free for buffers.
* ffi: array support.Kaz Kylheku2017-04-261-0/+96
| | | | | | | | | | | * ffi.c (array_s): New symbol variable. (ffi_array_put, ffi_array_get, ffi_array_fill, make_ffi_type_array): New static functions. (ffi_type_compile): Support (array <dim> <type>) syntax. (ffi_init): Initialize array_s. * ffi.h (array_s): Declared.
* ffi: incorrect handling of struct element array.Kaz Kylheku2017-04-261-6/+11
| | | | | | | | | | | | | | | * ffi.c (ffi_type_struct_destroy_op): Fix silly code. The size field most certainly doesn't indicate the number of elements, but rather the byte size. The array is documented by libffi as null-pointer terminated, so let's take advantage of that. (make_ffi_type_struct): Speaking of the array being null-terminated, it is we who are required to ensure this representation and we are not. Let's fix it. Also, we are here wrongly storing the number of elements into the struct type's size field, which is the basis for misusing that in the destroy op. The documentation says that the size field should be initialized to zero.
* ffi: no memcpy for string pointers.Kaz Kylheku2017-04-261-7/+6
| | | | | | ffi.c (ffi_str_put, ffi_str_get, ffi_wstr_put, ffi_wstr_get): Use assignment instead of memcpy to move the string pointer to and from the buffer.
* ffi: support buf objects.Kaz Kylheku2017-04-261-0/+39
| | | | | | | | | | | | | | | | * buf.c (make_duplicate_buf, buf_get, buf_fill): New functions. * buf.h (make_duplicate_buf, buf_get, buf_fill): Declared. * ffi.c (struct txr_ffi_type): New member, nelem. Keeps track of number of elements, for types that are FFI pointers. This lets us support the get method so that a buf can be a C function return value, if its size is declared in our FFI type system. (ffi_buf_put, ffi_buf_get, ffi_buf_fill): New functions. (ffi_type_compile): Handle two new cases of syntax for buffers: (buf <size>) and buf.
* Start of FFI implementation based on libffi.Kaz Kylheku2017-04-241-0/+1133
* Makefile (OBJS): Add ffi.o. * configure (have_libffi): New variable. (gen_config_make): Generate have_libffi make variable. New check for availability of libffi. * ffi.c, ffi.h: New files. * lib.c (init): Call ffi_init.