| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
|
|
|
|
|
|
|
|
| |
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.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.
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.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.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.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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* 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.
|
|
* 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.
|