diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-06-24 07:01:45 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-06-24 07:01:45 -0700 |
commit | 7de278b7c2971aef308ba43b786571fc1739aa00 (patch) | |
tree | 21e7481da7439bd8315ea4fc0d5fc114d2ba1ff5 | |
parent | 4cd1bf6f9fd47275e409d865c1f1c080f9e0c3ec (diff) | |
download | txr-7de278b7c2971aef308ba43b786571fc1739aa00.tar.gz txr-7de278b7c2971aef308ba43b786571fc1739aa00.tar.bz2 txr-7de278b7c2971aef308ba43b786571fc1739aa00.zip |
ffi: elide useless by-value in calls.
We can avoid calling in methods in the by-value nuance
(copy == 0) on types known not to have by-value in semantics.
Basic types have no by-value in.
Pointers inherently have by-value in.
An aggregate has by-value in semantics if any of one
of its members does, otherwise not.
* ffi.c (struct txr_ffi_type): New bitfield member,
by_value_in.
(ffi_ptr_in_in, ffi_ptr_in_d_in): Elite in call if target
type's by_value_in flag is clear.
(ffi_struct_in): Short-circuit to a return if doing by-value,
and the FFI struct type has no by-value semantics.
(ffi_array_in_common): Likewise. In this code change, we
just have to replace the test whether the element type has
an in method with a test of its by_value_in flag.
(make_ffi_type_pointer): Set by_value_in flag to 1, since
pointers have by value in semantics. This is true also of
ptr-in, because a structure passed as an in parameter to a
function via ptr-in could itself contain ptr or ptr-out
elements.
(make_ffi_type_struct): Set the type's by_value_in if
any element type's by_value_in is true.
(make_ffi_type_array): Propagate the by_value_in flag from
the element type to the array type.
(ffi_call_wrap): Calculate the in_pass_needed local flag
from the by_value_in flags of the arguments, not from whether
or not they have an in function. Only call the in function
for arguments which have the flag set.
-rw-r--r-- | ffi.c | 27 |
1 files changed, 16 insertions, 11 deletions
@@ -170,6 +170,7 @@ struct txr_ffi_type { struct smemb *memb; val sym_num, num_sym; unsigned null_term : 1; + unsigned by_value_in : 1; unsigned char_conv : 1; unsigned wchar_conv : 1; unsigned bchar_conv : 1; @@ -1969,7 +1970,7 @@ static val ffi_ptr_in_in(struct txr_ffi_type *tft, int copy, mem_t *src, val tgttype = tft->eltype; struct txr_ffi_type *tgtft = ffi_type_struct(tgttype); mem_t **loc = coerce(mem_t **, src); - if (tgtft->in != 0) + if (tgtft->in != 0 && tgtft->by_value_in) tgtft->in(tgtft, 0, *loc, obj, self); tgtft->free(*loc); *loc = 0; @@ -1982,7 +1983,7 @@ static val ffi_ptr_in_d_in(struct txr_ffi_type *tft, int copy, mem_t *src, val tgttype = tft->eltype; struct txr_ffi_type *tgtft = ffi_type_struct(tgttype); mem_t **loc = coerce(mem_t **, src); - if (tgtft->in != 0) + if (tgtft->in != 0 && tgtft->by_value_in) tgtft->in(tgtft, 0, *loc, obj, self); return obj; } @@ -2107,13 +2108,12 @@ static val ffi_struct_in(struct txr_ffi_type *tft, int copy, mem_t *src, cnum i, nmemb = tft->nelem; struct smemb *memb = tft->memb; + if (!copy && (!tft->by_value_in || strct == nil)) + return strct; + if (strct == nil) { - if (!copy) { - return nil; - } else { - args_decl(args, 0); - strct = make_struct(tft->lt, nil, args); - } + args_decl(args, 0); + strct = make_struct(tft->lt, nil, args); } for (i = 0; i < nmemb; i++) { @@ -2320,7 +2320,7 @@ static val ffi_array_in_common(struct txr_ffi_type *tft, int copy, cnum znelem = if3(tft->null_term && nelem > 0 && vec && length(vec) < num_fast(nelem), nelem - 1, nelem); - if (!copy && (etft->in == 0 || vec == nil)) + if (!copy && (!tft->by_value_in || vec == nil)) return vec; if (vec == nil) @@ -2776,6 +2776,7 @@ static val make_ffi_type_pointer(val syntax, val lisp_type, tft->release = release; tft->alloc = ffi_fixed_alloc; tft->free = free; + tft->by_value_in = 1; return obj; } @@ -2902,6 +2903,9 @@ static val make_ffi_type_struct(val syntax, val lisp_type, } need_out_handler = need_out_handler || mtft->out != 0; + + if (mtft->by_value_in) + tft->by_value_in = 1; } if (bit_offs > 0) { @@ -3043,6 +3047,7 @@ static val make_ffi_type_array(val syntax, val lisp_type, tft->release = ffi_array_release; tft->alloc = ffi_fixed_alloc; tft->free = free; + tft->by_value_in = etft->by_value_in; for (i = 0; i < nelem; i++) { if (i == 0) { @@ -4038,7 +4043,7 @@ val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args) for (i = 0; i < n; i++) { struct txr_ffi_type *mtft = type[i] = ffi_type_struct(pop(&types)); values[i] = zalloca(mtft->size); - in_pass_needed = in_pass_needed || mtft->in != 0; + in_pass_needed = in_pass_needed || mtft->by_value_in; } uw_simple_catch_begin; @@ -4070,7 +4075,7 @@ val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args) if (in_pass_needed) { for (i = 0; i < n; i++) { struct txr_ffi_type *mtft = type[i]; - if (mtft->in != 0) + if (mtft->by_value_in) mtft->in(mtft, 0, convert(mem_t *, values[i]), args->arg[i], self); } } |