summaryrefslogtreecommitdiffstats
path: root/ffi.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-05-01 06:27:08 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-05-01 06:27:08 -0700
commit1b8f2a5dcbe6211163ebf3495eeb0cd448c838e9 (patch)
treeafaef499ce28f655597bb0d1c7f18689594b0ffb /ffi.c
parent46df2055f1775e509aedb914a8315ed620111e21 (diff)
downloadtxr-1b8f2a5dcbe6211163ebf3495eeb0cd448c838e9.tar.gz
txr-1b8f2a5dcbe6211163ebf3495eeb0cd448c838e9.tar.bz2
txr-1b8f2a5dcbe6211163ebf3495eeb0cd448c838e9.zip
ffi: bugfix: aggregate fill logic doesn't recurse.
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.
Diffstat (limited to 'ffi.c')
-rw-r--r--ffi.c107
1 files changed, 40 insertions, 67 deletions
diff --git a/ffi.c b/ffi.c
index 16bedd40..43ae753c 100644
--- a/ffi.c
+++ b/ffi.c
@@ -95,11 +95,10 @@ struct txr_ffi_type {
void (*put)(struct txr_ffi_type *, val obj, mem_t *dst,
mem_t *rtvec[], val self);
val (*get)(struct txr_ffi_type *, mem_t *src, val self);
- void (*in)(struct txr_ffi_type *, val obj,
+ void (*in)(struct txr_ffi_type *, mem_t *src, val obj,
mem_t *rtvec[], val self);
mem_t *(*alloc)(struct txr_ffi_type *, val obj, val self);
void (*free)(void *);
- void (*fill)(struct txr_ffi_type *, mem_t *src, val obj, val self);
};
static struct txr_ffi_type *ffi_type_struct(val obj)
@@ -653,10 +652,11 @@ static mem_t *ffi_cptr_alloc(struct txr_ffi_type *tft, val ptr, val self)
return coerce(mem_t *, cptr_addr_of(ptr));
}
-static void ffi_freeing_in(struct txr_ffi_type *tft, val obj,
+static void ffi_freeing_in(struct txr_ffi_type *tft, mem_t *src, val obj,
mem_t *rtvec[], val self)
{
mem_t **loc = &rtvec[tft->rtidx];
+ (void) src;
(void) obj;
(void) self;
free(*loc);
@@ -827,7 +827,7 @@ static void ffi_ptr_walk(struct txr_ffi_type *tft, mem_t *ctx,
visit(tgtft, ctx);
}
-static void ffi_ptr_in_in(struct txr_ffi_type *tft, val obj,
+static void ffi_ptr_in_in(struct txr_ffi_type *tft, mem_t *src, val obj,
mem_t *rtvec[], val self)
{
val tgttype = tft->mtypes;
@@ -868,14 +868,14 @@ static void ffi_ptr_in_d_put(struct txr_ffi_type *tft, val s, mem_t *dst,
}
}
-static void ffi_ptr_out_in(struct txr_ffi_type *tft, val obj,
+static void ffi_ptr_out_in(struct txr_ffi_type *tft, mem_t *src, val obj,
mem_t *rtvec[], val self)
{
val tgttype = tft->mtypes;
struct txr_ffi_type *tgtft = ffi_type_struct(tgttype);
mem_t **loc = &rtvec[tft->rtidx];
- if (tgtft->fill != 0)
- tgtft->fill(tgtft, *loc, obj, self);
+ if (tgtft->in != 0)
+ tgtft->in(tgtft, *loc, obj, rtvec, self);
tgtft->free(*loc);
*loc = 0;
}
@@ -941,16 +941,29 @@ static void ffi_struct_walk(struct txr_ffi_type *tft, mem_t *ctx,
}
}
-static void ffi_struct_in(struct txr_ffi_type *tft, val obj,
+static void ffi_struct_in(struct txr_ffi_type *tft, mem_t *src, val strct,
mem_t *rtvec[], val self)
{
+ val slots = tft->mnames;
val types = tft->mtypes;
+ ucnum offs = 0;
- while (types) {
+ while (slots) {
+ val slsym = pop(&slots);
val type = pop(&types);
struct txr_ffi_type *mtft = ffi_type_struct(type);
- if (mtft->in != 0)
- mtft->in(mtft, obj, rtvec, self);
+ ucnum almask = mtft->align - 1;
+ offs = (offs + almask) & ~almask;
+ if (slsym) {
+ if (mtft->in != 0) {
+ val slval = slot(strct, slsym);
+ mtft->in(mtft, src + offs, slval, rtvec, self);
+ } else {
+ val slval = mtft->get(mtft, src + offs, self);
+ slotset(strct, slsym, slval);
+ }
+ }
+ offs += mtft->size;
}
}
@@ -1001,41 +1014,25 @@ static val ffi_struct_get(struct txr_ffi_type *tft, mem_t *src, val self)
return strct;
}
-static void ffi_struct_fill(struct txr_ffi_type *tft, mem_t *src,
- val strct, val self)
-{
- val slots = tft->mnames;
- val types = tft->mtypes;
- ucnum offs = 0;
-
- while (slots) {
- val slsym = pop(&slots);
- val type = pop(&types);
- struct txr_ffi_type *mtft = ffi_type_struct(type);
- ucnum almask = mtft->align - 1;
- val slval;
- offs = (offs + almask) & ~almask;
- if (slsym) {
- slval = mtft->get(mtft, src + offs, self);
- slotset(strct, slsym, slval);
- }
- offs += mtft->size;
- }
-}
-
-static void ffi_array_in(struct txr_ffi_type *tft, val obj,
+static void ffi_array_in(struct txr_ffi_type *tft, mem_t *src, val vec,
mem_t *rtvec[], val self)
{
val eltypes = tft->mtypes;
cnum nelem = tft->nelem, i;
+ ucnum offs = 0;
for (i = 0; i < nelem; i++) {
val eltype = pop(&eltypes);
struct txr_ffi_type *etft = ffi_type_struct(eltype);
- if (i == nelem - 1 && tft->null_term)
- break;
- if (etft->in != 0)
- etft->in(etft, obj, rtvec, self);
+ cnum elsize = etft->size;
+ if (etft->in != 0) {
+ val elval = ref(vec, num_fast(i));
+ etft->in(etft, src + offs, elval, rtvec, self);
+ } else {
+ val elval = etft->get(etft, src + offs, self);
+ refset(vec, num_fast(i), elval);
+ }
+ offs += elsize;
}
}
@@ -1109,23 +1106,6 @@ static val ffi_array_get(struct txr_ffi_type *tft, mem_t *src, val self)
}
}
-static void ffi_array_fill(struct txr_ffi_type *tft, mem_t *src,
- val vec, val self)
-{
- val eltypes = tft->mtypes;
- cnum nelem = tft->nelem, i;
- ucnum offs = 0;
-
- for (i = 0; i < nelem; i++) {
- val eltype = pop(&eltypes);
- struct txr_ffi_type *etft = ffi_type_struct(eltype);
- cnum elsize = etft->size;
- val elval = etft->get(etft, src + offs, self);
- refset(vec, num_fast(i), elval);
- offs += elsize;
- }
-}
-
static val make_ffi_type_builtin(val syntax, val lisp_type,
cnum size, ffi_type *ft,
void (*put)(struct txr_ffi_type *,
@@ -1159,8 +1139,8 @@ static val make_ffi_type_pointer(val syntax, val lisp_type,
val self),
val (*get)(struct txr_ffi_type *,
mem_t *src, val self),
- void (*in)(struct txr_ffi_type *, val obj,
- mem_t *rtvec[], val self),
+ void (*in)(struct txr_ffi_type *, mem_t *src,
+ val obj, mem_t *rtvec[], val self),
val tgtype)
{
struct txr_ffi_type *tft = coerce(struct txr_ffi_type *,
@@ -1198,7 +1178,6 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
val obj = cobj(coerce(mem_t *, tft), ffi_type_s, &ffi_type_struct_ops);
cnum total_size = 0;
cnum most_align = 0;
- int need_in_handler = 0;
ft->type = FFI_TYPE_STRUCT;
ft->size = 0;
@@ -1211,9 +1190,9 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
tft->walk = ffi_struct_walk;
tft->put = ffi_struct_put;
tft->get = ffi_struct_get;
+ tft->in = ffi_struct_in;
tft->alloc = ffi_fixed_alloc;
tft->free = free;
- tft->fill = ffi_struct_fill;
for (i = 0; i < nmemb; i++) {
val type = pop(&types);
@@ -1227,14 +1206,10 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
most_align = align;
total_size = (total_size + align - 1) / align * align + size;
- need_in_handler = need_in_handler || mtft->rtsize != 0 || mtft->in != 0;
}
elements[i] = 0;
- if (need_in_handler)
- tft->in = ffi_struct_in;
-
ft->elements = elements;
total_size = (total_size + most_align - 1) / most_align * most_align;
@@ -1268,9 +1243,9 @@ static val make_ffi_type_array(val syntax, val lisp_type,
tft->walk = ffi_struct_walk;
tft->put = ffi_array_put;
tft->get = ffi_array_get;
+ tft->in = ffi_array_in;
tft->alloc = ffi_fixed_alloc;
tft->free = free;
- tft->fill = ffi_array_fill;
for (i = 0; i < nelem; i++) {
val eltype = pop(&eltypes);
@@ -1279,8 +1254,6 @@ static val make_ffi_type_array(val syntax, val lisp_type,
if (i == 0) {
tft->size = etft->size * nelem;
tft->align = etft->align;
- if (etft->rtsize != 0 || etft->in != 0)
- tft->in = ffi_array_in;
}
}
@@ -1692,7 +1665,7 @@ val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
val arg = pop(&args);
struct txr_ffi_type *mtft = ffi_type_struct(type);
if (mtft->in != 0)
- mtft->in(mtft, arg, rtvec[i], self);
+ mtft->in(mtft, 0, arg, rtvec[i], self);
}
}