| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
| |
* txr.1: Adding a paragraph under unwind-protect clarifying
that exit points are removed during unwinding, not during the
search for an exit point.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.c (ffi_type_lookup, ffi_init_extra_types): New
functions.
(ffi_init): Call ffi_init_extra_types.
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.
|
|
|
|
|
|
|
|
| |
* 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.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.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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
| |
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.c (ffi_closure_destroy_op): Free the closure descriptor.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.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.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.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.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.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.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.
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.c (ffi_type_compile): Improved error reporting.
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|