summaryrefslogtreecommitdiffstats
path: root/ffi.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-06-24 07:01:45 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-06-24 07:01:45 -0700
commit7de278b7c2971aef308ba43b786571fc1739aa00 (patch)
tree21e7481da7439bd8315ea4fc0d5fc114d2ba1ff5 /ffi.c
parent4cd1bf6f9fd47275e409d865c1f1c080f9e0c3ec (diff)
downloadtxr-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.
Diffstat (limited to 'ffi.c')
-rw-r--r--ffi.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/ffi.c b/ffi.c
index 78eb00b0..a337c17b 100644
--- a/ffi.c
+++ b/ffi.c
@@ -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);
}
}