summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-04-28 21:59:06 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-04-28 21:59:06 -0700
commitce6d4ca76af3c5f10cd90b9c2a974f63fa1187e2 (patch)
treefcd17a65177e091d3326cd6f60d6a84e9bcd1a73
parent0f77a3213364452bcf63f0bb09a4049f9f5a4214 (diff)
downloadtxr-ce6d4ca76af3c5f10cd90b9c2a974f63fa1187e2.tar.gz
txr-ce6d4ca76af3c5f10cd90b9c2a974f63fa1187e2.tar.bz2
txr-ce6d4ca76af3c5f10cd90b9c2a974f63fa1187e2.zip
ffi: move run-time state out of txr_ffi_type.
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.
-rw-r--r--ffi.c312
1 files changed, 200 insertions, 112 deletions
diff --git a/ffi.c b/ffi.c
index b760bfb2..2d2aa476 100644
--- a/ffi.c
+++ b/ffi.c
@@ -84,13 +84,17 @@ struct txr_ffi_type {
val mtypes;
cnum size, align;
cnum nelem;
- void (*put)(struct txr_ffi_type *, val obj, mem_t *dst, val self);
+ int rtidx, rtsize;
+ void (*walk)(struct txr_ffi_type *, mem_t *ctx,
+ void (*visit)(struct txr_ffi_type *, mem_t *ctx));
+ 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, val self);
+ void (*in)(struct txr_ffi_type *, 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);
- mem_t *buf;
};
static struct txr_ffi_type *ffi_type_struct(val obj)
@@ -117,16 +121,6 @@ static void ffi_type_print_op(val obj, val out, val pretty, struct strm_ctx *ctx
format(out, lit(" ~!~s>"), tft->syntax, nao);
}
-static void ffi_builtin_type_struct_destroy_op(val obj)
-{
- struct txr_ffi_type *tft = ffi_type_struct(obj);
-
- if (tft->in)
- (void) tft->in(tft, nil, nil);
-
- free(obj->co.handle);
-}
-
static void ffi_type_struct_destroy_op(val obj)
{
struct txr_ffi_type *tft = ffi_type_struct(obj);
@@ -145,10 +139,6 @@ static void ffi_type_struct_destroy_op(val obj)
free(ft);
tft->ft = 0;
-
- if (tft->in)
- (void) tft->in(tft, nil, nil);
-
free(tft);
}
@@ -172,7 +162,7 @@ static void ffi_ptr_type_mark(val obj)
static struct cobj_ops ffi_type_builtin_ops =
cobj_ops_init(eq,
ffi_type_print_op,
- ffi_builtin_type_struct_destroy_op,
+ cobj_destroy_free_op,
cobj_mark_op,
cobj_hash_op);
@@ -186,17 +176,18 @@ static struct cobj_ops ffi_type_struct_ops =
static struct cobj_ops ffi_type_ptr_ops =
cobj_ops_init(eq,
ffi_type_print_op,
- ffi_builtin_type_struct_destroy_op,
+ cobj_destroy_free_op,
ffi_ptr_type_mark,
cobj_hash_op);
-static void ffi_void_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_void_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
(void) tft;
(void) n;
(void) dst;
(void) self;
+ (void) rtvec;
}
static mem_t *ffi_fixed_alloc(struct txr_ffi_type *tft, val obj, val self)
@@ -220,10 +211,11 @@ static val ffi_void_get(struct txr_ffi_type *tft, mem_t *src, val self)
}
#if HAVE_I8
-static void ffi_i8_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_i8_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
(void) tft;
+ (void) rtvec;
i8_t v = c_i8(n, self);
memcpy(dst, &v, sizeof v);
}
@@ -235,10 +227,11 @@ static val ffi_i8_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num_fast(*src);
}
-static void ffi_u8_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_u8_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
(void) tft;
+ (void) rtvec;
u8_t v = c_u8(n, self);
memcpy(dst, &v, sizeof v);
}
@@ -253,10 +246,11 @@ static val ffi_u8_get(struct txr_ffi_type *tft, mem_t *src, val self)
#endif
#if HAVE_I16
-static void ffi_i16_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_i16_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
(void) tft;
+ (void) rtvec;
i16_t v = c_i16(n, self);
memcpy(dst, &v, sizeof v);
}
@@ -270,10 +264,11 @@ static val ffi_i16_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num_fast(n);
}
-static void ffi_u16_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_u16_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
(void) tft;
+ (void) rtvec;
u16_t v = c_u16(n, self);
memcpy(dst, &v, sizeof v);
}
@@ -289,10 +284,11 @@ static val ffi_u16_get(struct txr_ffi_type *tft, mem_t *src, val self)
#endif
#if HAVE_I32
-static void ffi_i32_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_i32_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
(void) tft;
+ (void) rtvec;
i32_t v = c_i32(n, self);
memcpy(dst, &v, sizeof v);
}
@@ -306,10 +302,11 @@ static val ffi_i32_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num(n);
}
-static void ffi_u32_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_u32_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
(void) tft;
+ (void) rtvec;
u32_t v = c_u32(n, self);
memcpy(dst, &v, sizeof v);
}
@@ -325,11 +322,12 @@ static val ffi_u32_get(struct txr_ffi_type *tft, mem_t *src, val self)
#endif
#if HAVE_I64
-static void ffi_i64_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_i64_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
i64_t v = c_i64(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -349,9 +347,11 @@ static val ffi_i64_get(struct txr_ffi_type *tft, mem_t *src, val self)
}
}
-static void ffi_u64_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_u64_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
+ (void) tft;
+ (void) rtvec;
u64_t v = c_u64(n, self);
memcpy(dst, &v, sizeof v);
}
@@ -374,11 +374,12 @@ static val ffi_u64_get(struct txr_ffi_type *tft, mem_t *src, val self)
#endif
-static void ffi_char_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_char_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
char v = c_char(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -389,11 +390,12 @@ static val ffi_char_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num_fast(*coerce(char *, src));
}
-static void ffi_uchar_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_uchar_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
unsigned char v = c_uchar(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -404,11 +406,12 @@ static val ffi_uchar_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num_fast(*src);
}
-static void ffi_short_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_short_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
short v = c_short(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -421,11 +424,12 @@ static val ffi_short_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num_fast(n);
}
-static void ffi_ushort_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_ushort_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
unsigned short v = c_ushort(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -438,11 +442,12 @@ static val ffi_ushort_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num_fast(n);
}
-static void ffi_int_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_int_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
int v = c_int(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -455,11 +460,12 @@ static val ffi_int_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num(n);
}
-static void ffi_uint_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_uint_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
unsigned v = c_uint(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -472,11 +478,12 @@ static val ffi_uint_get(struct txr_ffi_type *tft, mem_t *src, val self)
return unum(n);
}
-static void ffi_long_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_long_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
long v = c_long(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -489,11 +496,12 @@ static val ffi_long_get(struct txr_ffi_type *tft, mem_t *src, val self)
return num(n);
}
-static void ffi_ulong_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_ulong_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
unsigned long v = c_ulong(n, self);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -506,12 +514,13 @@ static val ffi_ulong_get(struct txr_ffi_type *tft, mem_t *src, val self)
return unum(n);
}
-static void ffi_float_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_float_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
double f = c_flo(n);
double v;
(void) tft;
+ (void) rtvec;
if (f > FLT_MAX || f < FLT_MIN)
uw_throwf(error_s, lit("~a: ~s is out of float range"), self, num, nao);
v = f;
@@ -527,11 +536,12 @@ static val ffi_float_get(struct txr_ffi_type *tft, mem_t *src, val self)
return flo(n);
}
-static void ffi_double_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_double_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
double v = c_flo(n);
(void) tft;
+ (void) rtvec;
memcpy(dst, &v, sizeof v);
}
@@ -544,11 +554,12 @@ static val ffi_double_get(struct txr_ffi_type *tft, mem_t *src, val self)
return flo(n);
}
-static void ffi_cptr_put(struct txr_ffi_type *tft,
- val n, mem_t *dst, val self)
+static void ffi_cptr_put(struct txr_ffi_type *tft, val n, mem_t *dst,
+ mem_t *rtvec[], val self)
{
mem_t *p = cptr_get(n);
(void) tft;
+ (void) rtvec;
memcpy(dst, &p, sizeof p);
}
@@ -567,21 +578,22 @@ 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, val self)
+static void ffi_freeing_in(struct txr_ffi_type *tft, val obj,
+ mem_t *rtvec[], val self)
{
+ mem_t **loc = &rtvec[tft->rtidx];
(void) obj;
(void) self;
- free(tft->buf);
- tft->buf = 0;
+ free(*loc);
+ *loc = 0;
}
-static void ffi_str_put(struct txr_ffi_type *tft,
- val s, mem_t *dst, val self)
+static void ffi_str_put(struct txr_ffi_type *tft, val s, mem_t *dst,
+ mem_t *rtvec[], val self)
{
const wchar_t *ws = c_str(s);
char *u8s = utf8_dup_to(ws);
- free(tft->buf);
- tft->buf = coerce(mem_t *, u8s);
+ rtvec[tft->rtidx] = coerce(mem_t *, u8s);
*coerce(const char **, dst) = u8s;
}
@@ -594,9 +606,11 @@ static val ffi_str_get(struct txr_ffi_type *tft, mem_t *src, val self)
return string_utf8(p);
}
-static void ffi_wstr_put(struct txr_ffi_type *tft,
- val s, mem_t *dst, val self)
+static void ffi_wstr_put(struct txr_ffi_type *tft, val s, mem_t *dst,
+ mem_t *rtvec[], val self)
{
+ (void) tft;
+ (void) rtvec;
const wchar_t *ws = c_str(s);
*coerce(const wchar_t **, dst) = ws;
}
@@ -609,9 +623,10 @@ static val ffi_wstr_get(struct txr_ffi_type *tft, mem_t *src, val self)
return string(p);
}
-static void ffi_buf_put(struct txr_ffi_type *tft,
- val buf, mem_t *dst, val self)
+static void ffi_buf_put(struct txr_ffi_type *tft, val buf, mem_t *dst,
+ mem_t *rtvec[], val self)
{
+ (void) rtvec;
mem_t *b = buf_get(buf, self);
*coerce(const mem_t **, dst) = b;
}
@@ -630,41 +645,55 @@ static mem_t *ffi_buf_alloc(struct txr_ffi_type *tft, val buf, val self)
return buf_get(buf, self);
}
-static void ffi_ptr_in_in(struct txr_ffi_type *tft, val obj, val self)
+static void ffi_ptr_walk(struct txr_ffi_type *tft, mem_t *ctx,
+ void (*visit)(struct txr_ffi_type *, mem_t *ctx))
{
val tgttype = tft->mtypes;
struct txr_ffi_type *tgtft = ffi_type_struct(tgttype);
- tgtft->free(tft->buf);
- tft->buf = 0;
+ if (tgtft->walk)
+ tgtft->walk(tgtft, ctx, visit);
+ visit(tgtft, ctx);
}
-static void ffi_ptr_in_put(struct txr_ffi_type *tft,
- val s, mem_t *dst, val self)
+static void ffi_ptr_in_in(struct txr_ffi_type *tft, 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];
+ tgtft->free(*loc);
+ *loc = 0;
+}
+
+static void ffi_ptr_in_put(struct txr_ffi_type *tft, val s, mem_t *dst,
+ mem_t *rtvec[], val self)
{
val tgttype = tft->mtypes;
struct txr_ffi_type *tgtft = ffi_type_struct(tgttype);
mem_t *buf = tgtft->alloc(tgtft, s, self);
- tgtft->put(tgtft, s, buf, self);
- tft->buf = buf;
+ tgtft->put(tgtft, s, buf, rtvec, self);
+ rtvec[tft->rtidx] = buf;
}
-static void ffi_ptr_out_in(struct txr_ffi_type *tft, val obj, val self)
+static void ffi_ptr_out_in(struct txr_ffi_type *tft, 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, tft->buf, obj, self);
- tgtft->free(tft->buf);
- tft->buf = 0;
+ tgtft->fill(tgtft, *loc, obj, self);
+ tgtft->free(*loc);
+ *loc = 0;
}
-static void ffi_ptr_out_put(struct txr_ffi_type *tft,
- val s, mem_t *dst, val self)
+static void ffi_ptr_out_put(struct txr_ffi_type *tft, val s, mem_t *dst,
+ mem_t *rtvec[], val self)
{
val tgttype = tft->mtypes;
struct txr_ffi_type *tgtft = ffi_type_struct(tgttype);
mem_t *buf = tgtft->alloc(tgtft, s, self);
- tft->buf = buf;
+ rtvec[tft->rtidx] = buf;
*coerce(mem_t **, dst) = buf;
}
@@ -676,18 +705,33 @@ static val ffi_ptr_out_get(struct txr_ffi_type *tft, mem_t *src, val self)
return tgtft->get(tgtft, ptr, self);
}
-static void ffi_ptr_in_out_put(struct txr_ffi_type *tft,
- val s, mem_t *dst, val self)
+static void ffi_ptr_in_out_put(struct txr_ffi_type *tft, val s, mem_t *dst,
+ mem_t *rtvec[], val self)
{
val tgttype = tft->mtypes;
struct txr_ffi_type *tgtft = ffi_type_struct(tgttype);
mem_t *buf = tgtft->alloc(tgtft, s, self);
- tgtft->put(tgtft, s, buf, self);
- tft->buf = buf;
+ tgtft->put(tgtft, s, buf, rtvec, self);
+ rtvec[tft->rtidx] = buf;
*coerce(mem_t **, dst) = buf;
}
-static void ffi_struct_in(struct txr_ffi_type *tft, val obj, val self)
+static void ffi_struct_walk(struct txr_ffi_type *tft, mem_t *ctx,
+ void (*visit)(struct txr_ffi_type *, mem_t *ctx))
+{
+ val types = tft->mtypes;
+
+ while (types) {
+ val type = pop(&types);
+ struct txr_ffi_type *mtft = ffi_type_struct(type);
+ if (mtft->walk != 0)
+ mtft->walk(mtft, ctx, visit);
+ visit(mtft, ctx);
+ }
+}
+
+static void ffi_struct_in(struct txr_ffi_type *tft, val obj,
+ mem_t *rtvec[], val self)
{
val types = tft->mtypes;
@@ -695,12 +739,12 @@ static void ffi_struct_in(struct txr_ffi_type *tft, val obj, val self)
val type = pop(&types);
struct txr_ffi_type *mtft = ffi_type_struct(type);
if (mtft->in != 0)
- mtft->in(mtft, obj, self);
+ mtft->in(mtft, obj, rtvec, self);
}
}
-static void ffi_struct_put(struct txr_ffi_type *tft,
- val strct, mem_t *dst, val self)
+static void ffi_struct_put(struct txr_ffi_type *tft, val strct, mem_t *dst,
+ mem_t *rtvec[], val self)
{
val slots = tft->mnames;
val types = tft->mtypes;
@@ -713,7 +757,7 @@ static void ffi_struct_put(struct txr_ffi_type *tft,
struct txr_ffi_type *mtft = ffi_type_struct(type);
ucnum almask = mtft->align - 1;
offs = (offs + almask) & ~almask;
- mtft->put(mtft, slval, dst + offs, self);
+ mtft->put(mtft, slval, dst + offs, rtvec, self);
offs += mtft->size;
}
}
@@ -761,7 +805,8 @@ static void ffi_struct_fill(struct txr_ffi_type *tft, mem_t *src,
}
}
-static void ffi_array_in(struct txr_ffi_type *tft, val obj, val self)
+static void ffi_array_in(struct txr_ffi_type *tft, val obj,
+ mem_t *rtvec[], val self)
{
val eltypes = tft->mtypes;
cnum nelem = tft->nelem, i;
@@ -770,12 +815,12 @@ static void ffi_array_in(struct txr_ffi_type *tft, val obj, val self)
val eltype = pop(&eltypes);
struct txr_ffi_type *etft = ffi_type_struct(eltype);
if (etft->in != 0)
- etft->in(etft, obj, self);
+ etft->in(etft, obj, rtvec, self);
}
}
-static void ffi_array_put(struct txr_ffi_type *tft,
- val vec, mem_t *dst, val self)
+static void ffi_array_put(struct txr_ffi_type *tft, val vec, mem_t *dst,
+ mem_t *rtvec[], val self)
{
val eltypes = tft->mtypes;
cnum nelem = tft->nelem, i;
@@ -786,7 +831,7 @@ static void ffi_array_put(struct txr_ffi_type *tft,
struct txr_ffi_type *etft = ffi_type_struct(eltype);
cnum elsize = etft->size;
val elval = ref(vec, num_fast(i));
- etft->put(etft, elval, dst + offs, self);
+ etft->put(etft, elval, dst + offs, rtvec, self);
offs += elsize;
}
}
@@ -830,7 +875,8 @@ static void ffi_array_fill(struct txr_ffi_type *tft, mem_t *src,
static val make_ffi_type_builtin(val syntax, val lisp_type,
cnum size, ffi_type *ft,
void (*put)(struct txr_ffi_type *,
- val obj, mem_t *dst, val self),
+ val obj, mem_t *dst,
+ mem_t *rtvec[], val self),
val (*get)(struct txr_ffi_type *,
mem_t *src, val self))
{
@@ -854,12 +900,13 @@ static val make_ffi_type_builtin(val syntax, val lisp_type,
static val make_ffi_type_pointer(val syntax, val lisp_type,
cnum size, ffi_type *ft,
- void (*put)(struct txr_ffi_type *,
- val obj, mem_t *dst, val self),
+ 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, val self),
+ void (*in)(struct txr_ffi_type *, val obj,
+ mem_t *rtvec[], val self),
val tgtype)
{
struct txr_ffi_type *tft = coerce(struct txr_ffi_type *,
@@ -872,6 +919,8 @@ static val make_ffi_type_pointer(val syntax, val lisp_type,
tft->lt = lisp_type;
tft->mnames = tft->mtypes = nil;
tft->size = tft->align = size;
+ tft->rtsize = 1;
+ tft->walk = ffi_ptr_walk;
tft->put = put;
tft->get = get;
tft->mtypes = tgtype;
@@ -882,7 +931,6 @@ static val make_ffi_type_pointer(val syntax, val lisp_type,
return obj;
}
-
static val make_ffi_type_struct(val syntax, val lisp_type,
val slots, val types)
{
@@ -896,7 +944,7 @@ 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 in_handler_needed = 0;
+ int rtsize = 0;
ft->type = FFI_TYPE_STRUCT;
ft->size = 0;
@@ -906,6 +954,7 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
tft->lt = lisp_type;
tft->mnames = slots;
tft->mtypes = types;
+ tft->walk = ffi_struct_walk;
tft->put = ffi_struct_put;
tft->get = ffi_struct_get;
tft->alloc = ffi_fixed_alloc;
@@ -924,13 +973,15 @@ static val make_ffi_type_struct(val syntax, val lisp_type,
most_align = align;
total_size = (total_size + align - 1) / align * align + size;
- in_handler_needed = in_handler_needed || mtft->in != 0;
+ rtsize += mtft->rtsize;
}
elements[i] = 0;
- if (in_handler_needed)
+ if (rtsize != 0) {
+ tft->rtsize = rtsize;
tft->in = ffi_struct_in;
+ }
ft->elements = elements;
@@ -962,6 +1013,7 @@ static val make_ffi_type_array(val syntax, val lisp_type,
tft->lt = lisp_type;
tft->mnames = nil;
tft->mtypes = eltypes;
+ tft->walk = ffi_struct_walk;
tft->put = ffi_array_put;
tft->get = ffi_array_get;
tft->alloc = ffi_fixed_alloc;
@@ -975,9 +1027,11 @@ 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) {
+ tft->rtsize = etft->rtsize * nelem;
+ tft->in = ffi_array_in;
+ }
}
- if (i == 0 && etft->in != 0)
- tft->in = ffi_array_in;
}
elements[i] = 0;
@@ -989,6 +1043,15 @@ static val make_ffi_type_array(val syntax, val lisp_type,
return obj;
}
+static void ffi_type_walk(val type, mem_t *ctx,
+ void (*visit)(struct txr_ffi_type *, mem_t *ctx))
+{
+ struct txr_ffi_type *tft = ffi_type_struct(type);
+ if (tft->walk != 0)
+ tft->walk(tft, ctx, visit);
+ visit(tft, ctx);
+}
+
static val ffi_struct_compile(val membs, val *ptypes, val self)
{
list_collect_decl (slots, pstail);
@@ -1174,6 +1237,7 @@ val ffi_type_compile(val syntax)
ffi_str_put, ffi_str_get);
struct txr_ffi_type *tft = ffi_type_struct(type);
tft->in = ffi_freeing_in;
+ tft->rtsize = 1;
return type;
} else if (syntax == wstr_s) {
return make_ffi_type_builtin(syntax, cptr_s, sizeof (mem_t *),
@@ -1196,6 +1260,26 @@ val ffi_type_compile(val syntax)
}
}
+static void assign_rtindices_visit(struct txr_ffi_type *tft, mem_t *ctx)
+{
+ int *counter = coerce(int *, ctx);
+ if (tft->in != 0)
+ tft->rtidx = (*counter)++;
+}
+
+static void ffi_type_assign_rtindices(val type)
+{
+ int counter = 0;
+ ffi_type_walk(type, coerce(mem_t *, &counter), assign_rtindices_visit);
+}
+
+val ffi_type_compile_toplevel(val syntax)
+{
+ val type = ffi_type_compile(syntax);
+ ffi_type_assign_rtindices(type);
+ return type;
+}
+
struct txr_ffi_call_desc {
ffi_cif cif;
ffi_type **args;
@@ -1291,6 +1375,7 @@ val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
val types = tfcd->argtypes;
val rtype = tfcd->rettype;
struct txr_ffi_type *rtft = ffi_type_struct(rtype);
+ mem_t ***rtvec = coerce(mem_t ***, alloca(sizeof *rtvec * tfcd->ntotal));
void *rc = alloca(rtft->size);
int in_pass_needed = 0;
@@ -1298,8 +1383,11 @@ val ffi_call_wrap(val ffi_call_desc, val fptr, val args_in)
val type = pop(&types);
val arg = pop(&args);
struct txr_ffi_type *mtft = ffi_type_struct(type);
+ rtvec[i] = mtft->rtsize
+ ? coerce(mem_t **, alloca(mtft->rtsize * sizeof *rtvec[0]))
+ : 0;
values[i] = alloca(mtft->size);
- mtft->put(mtft, arg, convert(mem_t *, values[i]), self);
+ mtft->put(mtft, arg, convert(mem_t *, values[i]), rtvec[i], self);
in_pass_needed = in_pass_needed || mtft->in != 0;
}
@@ -1313,7 +1401,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, self);
+ mtft->in(mtft, arg, rtvec[i], self);
}
}
@@ -1354,7 +1442,7 @@ void ffi_init(void)
ptr_in_out_s = intern(lit("ptr-in-out"), user_package);
ffi_type_s = intern(lit("ffi-type"), user_package);
ffi_call_desc_s = intern(lit("ffi-call-desc"), user_package);
- reg_fun(intern(lit("ffi-type-compile"), user_package), func_n1(ffi_type_compile));
+ reg_fun(intern(lit("ffi-type-compile"), user_package), func_n1(ffi_type_compile_toplevel));
reg_fun(intern(lit("ffi-make-call-desc"), user_package), func_n4(ffi_make_call_desc));
reg_fun(intern(lit("ffi-call"), user_package), func_n3(ffi_call_wrap));
reg_fun(intern(lit("cptr"), user_package), func_n1o(cptr_make, 0));