summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
...
* ffi: implement bchar type.Kaz Kylheku2017-05-042-2/+11
| | | | | | | | | | | | bchar is like uchar, except that in the decode direction, it produces character objects rather than integers. * ffi.c (bchar_s): New symbol variable. (ffi_bchar_get): New static function. (ffi_init_types): Register bchar type. (ffi_init): Initialize bchar_s. * ffi.h (bchar_s): Declared.
* ffi: remove redundant function.Kaz Kylheku2017-05-041-14/+1
| | | | | | * ffi.c (ffi_str_d_put): Function removed. It is identical to ffi_str_put. (ffi_init_types): Use ffi_str_put for the str-d type.
* ffi: map FFI char type to character.Kaz Kylheku2017-05-041-1/+1
| | | | | | * ffi.c (ffi_char_get): Get a char object as a Lisp character, rather than number. Users who want a byte to convert to a an integer can use one of the types int8 or uint8 instead.
* bugfix: tostringp not behaving right for floats.Kaz Kylheku2017-05-044-10/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | The obj printer is ignoring the pretty flag when rendering floating-point numbers, and just formatting them using *print-flo-format*. To address this issue, we introduce an additional *pprint-flo-format* variable. * lib.c (obj_print_impl): In the FLNUM case, use either the value of *print-flo-format* or *pprint-flo-format* based on the value of the pretty flag. * stream.c (pprint_flo_format_s): New symbol variable. (stream_init): Initialize pprint_flo_format_s with interned symbol *pprint-flo-format* and register this as a special variable. * stream.c (pprint_flo_format_s): Declared. * txr.1: Documented *pprint-flo-format*. Also put in a note in the description of the various print functions that the equivalences based on ~s and ~a only apply to floats when the special variables have their original values.
* doc: clarify when exit points are torn down.Kaz Kylheku2017-05-041-0/+11
| | | | | | * txr.1: Adding a paragraph under unwind-protect clarifying that exit points are removed during unwinding, not during the search for an exit point.
* structs: check existence of type in new and lnew.Kaz Kylheku2017-05-041-9/+23
| | | | | | | | | | | | | | | | | | | | | This achieves two objectives. The obvious one is that we get a diagnostic for new expressions that name a nonexistent type, due to a typo, before those expressions are executed. However, this also fixes an annoying issue: spurious warnings about nonexistent slots, related to structs which have not yet been autoloaded. A test case for this is an expression like (let ((b (new list-builder))) b.(add 42)). Because list-builder is auto-loaded, the add slot doesn't exist. But (new list-builder) doesn't trigger that auto-load; so the deferred warning about the nonexistent slot isn't suppressed. With this change, the existence check in (new list-builder) will trigger the auto-load for the module which defines list-builder, causing the add slot to exist before the b.(add 42) expression is visited by the expander. * share/txr/stdlib/struct.tl (sys:check-struct): New function. (new, lnew): Issue warning if the type doesn't exist.
* dlopen: add error reporting via dlerror()Kaz Kylheku2017-05-031-9/+22
| | | | | | | | | | * sysif.c (dlopen_wrap): Call dlerror() to clear the error string. Then if the call returns null, call dlerror() again and use the string in the exception if available. (dlsym_error): New static function. (dlsym_checked, dlvsym_checked): Clear error string by calling dlerror(). Afer the call, if the pointer is null call dlsym_error to report.
* dlopen: allow nil name and default both args.Kaz Kylheku2017-05-031-4/+5
| | | | | | | | | * sysif.c (dlopen_wrap): Allow the name to be null or missing, in which case a null pointer is passed to dlopen to access the program image itself. Default the flags argument to RTLD_LAZY. (sysif_init): Re-regiser dlopen intrinsic such that both arguments are optional.
* ffi: new ptr-out-s type.Kaz Kylheku2017-05-032-2/+22
| | | | | | | | | | | | | | | | | | One more ptr type is useful. This type is for objects returned via pointers embedded in arrays or structures, whereby the callee establishes both the pointer and the data. This is similar to ptr-out-d; the difference is that the data has an indefinite lifetime ("s" denotes "static") and so the pointer is not freed after the call takes place and the data is extracted into Lisp objects. * ffi.c (ptr_out_s_s): New symbol variable. (ffi_ptr_out_s_in): New function. (ffi_type_compile): Handle new ptr_out_s_s. (ffi_init): Initialize ptr_out_s. * ffi.h (ptr_out_s_s): Declared.
* ffi: fix semantics of ptr-out-d.Kaz Kylheku2017-05-031-1/+7
| | | | | | | | | | | | | | | | | | Since the callee allocates the buffer for a ptr-out-d, the FFI mechanism should not also be allocating a buffer to receive the object. The buffer pointer will just be overwritten by the callee with its own dynamic pointer. We should pass a null pointer which the callee fills in (making a ptr-out-d not suitable as a by-value parameter). Initially, ptr-out-d was envisioned for return values only and for use in callbacks, which is why I neglected this aspect. * ffi.c (ffi_ptr_out_null_put): New static function. (ffi_type_compile): Use ffi_ptr_out_null_put for the ffi_ptr_out_d case, so caller places a null pointer, then frees the pointer that the callee places there.
* ffi: rename low-level ptr function.Kaz Kylheku2017-05-031-4/+5
| | | | | | * ffi.c (ffi_ptr_put): Rnamed to ffi_ptr_in_put. (ffi_type_compile): All uses of ffi_ptr_put replaced with ffi_ptr_in_put.
* 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.
* HAVE_SYS_TYPES_H config variable.Kaz Kylheku2017-05-032-1/+17
| | | | | | | | | | | * configure (have_sys_types): New variable. Set to "y" in various tests which prove that the <sys/types.h> header is available. (HAVE_SYS_TYPES_H): Add to config.h in the dependent variale generation section, if have_sys_types is true. * sysif.c: Use HAVE_SYS_TYPES_H instead of relying on HAVE_MAKEDEV.
* 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-022-38/+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.
* Error checking in dlopen wrappers.Kaz Kylheku2017-05-021-0/+22
| | | | | | | | * sysif.c (dlopen_wrap): Throw instead of returning null cptr if the dlopen fails. (dlsym_checked, dlvsym_checked): New static functions. (sysif_init): Register dlsym-checked, dlvsym-checked intrinsics.
* ffi: simple typedef mechanism.Kaz Kylheku2017-05-012-0/+17
| | | | | | | | | | | | * 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-012-0/+37
| | | | | | | | | | | | * 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.
* buf: fix memory leak.Kaz Kylheku2017-04-301-1/+1
| | | | | | * buf.c (make_duplicate_buf): A duplicated buf is dynamic, so the size must not be nil, which indicates a static or borrowed one. Set the size properly, so finalize will free it.
* ffi: implementing FFI callback closures.Kaz Kylheku2017-04-302-2/+151
| | | | | | | | | | | | | | | | | | | * 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-302-9/+7
| | | | | | | | | | | | * 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-293-12/+56
| | | | | | | | | | | | | | * 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-292-2/+35
| | | | | | | | | | | | 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-292-4/+20
| | | | | | | | | | | | | | | | | | | | | 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-292-3/+38
| | | | | | | | | | | | | | | | | | | | 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-292-7/+7
| | | | | | | | | | | | 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-292-8/+71
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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-293-1/+8
| | | | | | | | | | | | | | 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.