summaryrefslogtreecommitdiffstats
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
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.
-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);
}
}