diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-05-28 05:31:26 +0000 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-05-28 05:31:26 +0000 |
commit | 10507446389cff9b072c25aa86ba35834a786fe5 (patch) | |
tree | 0b01a0f741407278b005952ce1ec4f5a8b9c399e /ffi.c | |
parent | 194297377d00935a4d5df2d162871b0da930f1d5 (diff) | |
download | txr-10507446389cff9b072c25aa86ba35834a786fe5.tar.gz txr-10507446389cff9b072c25aa86ba35834a786fe5.tar.bz2 txr-10507446389cff9b072c25aa86ba35834a786fe5.zip |
ffi: adapt to return value braindamage in libffi.
This change gets TXR FFI working on Power PC 64,
big endian. Many thanks to the GCC Compile Farm.
Turns out, the libffi API has changed some years ago,
with outdated documentation lingering. Return values
for the basic integral types must all be handled with
a buffer of type ffi_arg and casting. This is true in
both ffi_call and closures: in both directions.
For instance, if a foreign function returns char, we
must retrieve a ffi_arg value (which might be as
large as 64 bits). Then we must cast this value to
char. In actual fact, on a big endian system with an
8 byte ffi_arg, the char value may be located in byte
7 of the 8 byte buffer, not in byte 0.
FFI's own test suite got this wrong and had to
be patched back in 2013: it was doing things the way
we are doing them:
https://sourceware.org/ml/libffi-discuss/2013/msg00199.html
The doc was updated at the same time to tell the truth:
https://sourceware.org/ml/libffi-discuss/2013/msg00200.html
Luckily, we can fix TXR's ffi module without damaging its
framework. The object model is flexible enough to absorb the
change. Basically, we add two new methods to the txr_ffi_type
objects: virtual functions rget and rput. We only add these
when targetting big endian. These have the same type
signature as get and put, but are specialized for handling
return values. For all integer types smaller than 64 bits,
these functions are separately implemented with distinct
semanics which handle the FFI API requirements with ffi_arg
and casting and all. For all other types, rget and rput
are identical to get and put.
* ffi.c (pad_retval, ifbe, ifbe2): New macros, conditionally
defined for big and little endian.
(struct txr_ffi_type): New members rput and rget.
(ffi_i8_rput, ffi_i8_rget, ffi_u8_rput, ffi_u8_rget,
ffi_i16_rput, ffi_i16_rget, ffi_u16_rput, ffi_u16_rget,
ffi_i32_rput, ffi_i32_rget, ffi_u32_rput, ffi_u32_rget,
ffi_char_rput, ffi_char_rget, ffi_uchar_rput, ffi_uchar_rget,
ffi_bchar_rget, ffi_short_rput, ffi_short_rget,
ffi_ushort_rput, ffi_ushort_rget, ffi_int_rput, ffi_int_rget,
ffi_uint_rput, ffi_uint_rget, ffi_long_rput, ffi_long_rget,
ffi_ulong_rput, ffi_ulong_rget, ffi_wchar_rput): New
functions.
(make_ffi_type_builtin): Take rput and rget arguments,
regardless of platform. On big endian, store these in the
corresponding members. If they are null, duplicate get and put
instead.
(ffi_type_compile, ffi_init_types): Specify the rput and rget
functions for the basic types, using the ifbe macro which
nullifies the references to functions when they don't exist on
little endian. For all other types, pass the new arguments as
null.
(ffi_call_wrap): Pad the return vaue buffer size to a minimum
size on big endian; it must be at least sizeof (ffi_alloc).
Use the rget method for the return value on big endian.
(ffi_closure_dispatch, ffi_closure_dispatch_safe): Use rput on
big endian for storing return value.
Diffstat (limited to 'ffi.c')
-rw-r--r-- | ffi.c | 342 |
1 files changed, 301 insertions, 41 deletions
@@ -62,6 +62,18 @@ #define alignof(type) offsetof(struct {char x; type y;}, y) +#if HAVE_LITTLE_ENDIAN +#define pad_retval(size) (size) +#define ifbe(expr) (0) +#define ifbe2(expr1, expr2) (expr2) +#else +#define pad_retval(size) ((size) > sizeof (ffi_arg) \ + ? (size) \ + : sizeof (ffi_arg)) +#define ifbe(expr) (expr) +#define ifbe2(expr1, expr2) (expr1) +#endif + val uint8_s, int8_s; val uint16_s, int16_s; val uint32_s, int32_s; @@ -124,6 +136,10 @@ struct txr_ffi_type { void (*release)(struct txr_ffi_type *, val obj, mem_t *dst); mem_t *(*alloc)(struct txr_ffi_type *, val obj, val self); void (*free)(void *); +#if !HAVE_LITTLE_ENDIAN + void (*rput)(struct txr_ffi_type *, val obj, mem_t *dst, val self); + val (*rget)(struct txr_ffi_type *, mem_t *src, val self); +#endif }; static struct txr_ffi_type *ffi_type_struct(val obj) @@ -701,6 +717,199 @@ static val ffi_ubit_get(struct txr_ffi_type *tft, mem_t *src, val self) return unum(uget >> shift); } +#if !HAVE_LITTLE_ENDIAN + +static void ffi_i8_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + i8_t v = c_i8(n, self); + *coerce(i8_t *, dst) = v; +} + +static val ffi_i8_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + return num_fast(*src); +} + +static void ffi_u8_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + u8_t v = c_u8(n, self); + *coerce(u8_t *, dst) = v; +} + +static val ffi_u8_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + return num_fast(*coerce(u8_t *, src)); +} + +#if HAVE_I16 +static void ffi_i16_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + i16_t v = c_i16(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_i16_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + i16_t n = *coerce(ffi_arg *, src); + return num_fast(n); +} + +static void ffi_u16_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + u16_t v = c_u16(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_u16_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + u16_t n = *coerce(ffi_arg *, src); + return num_fast(n); +} +#endif + +#if HAVE_I32 +static void ffi_i32_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + i32_t v = c_i32(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_i32_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + i32_t n = *coerce(ffi_arg *, src); + return num(n); +} +#endif + +static void ffi_u32_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + u32_t v = c_u32(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_u32_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + u32_t n = *coerce(ffi_arg *, src); + return unum(n); +} + +static void ffi_char_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + char v = c_char(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_char_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + return chr((char) *coerce(ffi_arg *, src)); +} + +static void ffi_uchar_rput(struct txr_ffi_type *tft, val n, mem_t *dst, + val self) +{ + unsigned char v = c_uchar(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_uchar_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + return num_fast((unsigned char) *coerce(ffi_arg *, src)); +} + +static val ffi_bchar_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + return chr((unsigned char) *coerce(ffi_arg *, src)); +} + +static void ffi_short_rput(struct txr_ffi_type *tft, val n, mem_t *dst, + val self) +{ + short v = c_short(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_short_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + short n = *coerce(ffi_arg *, src); + return num_fast(n); +} + +static void ffi_ushort_rput(struct txr_ffi_type *tft, val n, mem_t *dst, + val self) +{ + unsigned short v = c_ushort(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_ushort_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + unsigned short n = *coerce(ffi_arg *, src); + return num_fast(n); +} + +static void ffi_int_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + int v = c_int(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_int_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + int n = *coerce(ffi_arg *, src); + return num(n); +} + +static void ffi_uint_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + unsigned v = c_uint(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_uint_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + unsigned n = *coerce(ffi_arg *, src); + return unum(n); +} + +static void ffi_long_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + long v = c_long(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_long_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + long n = *coerce(ffi_arg *, src); + return num(n); +} + +static void ffi_ulong_rput(struct txr_ffi_type *tft, val n, mem_t *dst, val self) +{ + unsigned long v = c_ulong(n, self); + *coerce(ffi_arg *, dst) = v; +} + +static val ffi_ulong_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + unsigned long n = *coerce(ffi_arg *, src); + return unum(n); +} + +static void ffi_wchar_rput(struct txr_ffi_type *tft, val ch, mem_t *dst, + val self) +{ + wchar_t c = c_chr(ch); + *coerce(ffi_arg *, dst) = c; +} + +static val ffi_wchar_rget(struct txr_ffi_type *tft, mem_t *src, val self) +{ + wchar_t c = *coerce(ffi_arg *, src); + return chr(c); +} + +#endif + static void ffi_cptr_put(struct txr_ffi_type *tft, val n, mem_t *dst, val self) { @@ -1546,7 +1755,11 @@ static val make_ffi_type_builtin(val syntax, val lisp_type, void (*put)(struct txr_ffi_type *, val obj, mem_t *dst, val self), val (*get)(struct txr_ffi_type *, - mem_t *src, val self)) + mem_t *src, val self), + void (*rput)(struct txr_ffi_type *, + val obj, mem_t *dst, val self), + val (*rget)(struct txr_ffi_type *, + mem_t *src, val self)) { struct txr_ffi_type *tft = coerce(struct txr_ffi_type *, chk_calloc(1, sizeof *tft)); @@ -1562,6 +1775,10 @@ static val make_ffi_type_builtin(val syntax, val lisp_type, tft->get = get; tft->alloc = ffi_fixed_alloc; tft->free = free; +#if !HAVE_LITTLE_ENDIAN + tft->rput = (rput ? rput : put); + tft->rget = (rget ? rget : get); +#endif return obj; } @@ -1930,7 +2147,8 @@ val ffi_type_compile(val syntax) if3(sym == buf_s, ffi_buf_put, ffi_buf_d_put), if3(sym == buf_s, - ffi_buf_get, ffi_buf_d_get)); + ffi_buf_get, ffi_buf_d_get), + 0, 0); struct txr_ffi_type *tft = ffi_type_struct(type); if (nelem < 0) @@ -1964,7 +2182,8 @@ val ffi_type_compile(val syntax) if3(sym == sbit_s, ffi_sbit_put, ffi_ubit_put), if3(sym == sbit_s, - ffi_sbit_get, ffi_ubit_get)); + ffi_sbit_get, ffi_ubit_get), + 0, 0); struct txr_ffi_type *tft = ffi_type_struct(type); const int bits_int = 8 * sizeof(int); if (nb < 0 || nb > bits_int) @@ -1999,97 +2218,133 @@ static void ffi_init_types(void) #if HAVE_I8 ffi_typedef(uint8_s, make_ffi_type_builtin(uint8_s, integer_s, sizeof (i8_t), alignof (i8_t), &ffi_type_uint8, - ffi_u8_put, ffi_u8_get)); + ffi_u8_put, ffi_u8_get, + ifbe(ffi_u8_rput), + ifbe(ffi_u8_rget))); ffi_typedef(int8_s, make_ffi_type_builtin(int8_s, integer_s, sizeof (i8_t), alignof (i8_t), &ffi_type_sint8, - ffi_i8_put, ffi_i8_get)); + ffi_i8_put, ffi_i8_get, + ifbe(ffi_i8_rput), + ifbe(ffi_i8_rget))); #endif #if HAVE_I16 ffi_typedef(uint16_s, make_ffi_type_builtin(uint16_s, integer_s, sizeof (i16_t), alignof (i16_t), &ffi_type_uint16, - ffi_u16_put, ffi_u16_get)); + ffi_u16_put, ffi_u16_get, + ifbe(ffi_u16_rput), + ifbe(ffi_u16_rget))); ffi_typedef(int16_s, make_ffi_type_builtin(int16_s, integer_s, sizeof (i16_t), alignof (i16_t), &ffi_type_sint16, - ffi_i16_put, ffi_i16_get)); + ffi_i16_put, ffi_i16_get, + ifbe(ffi_i16_rput), + ifbe(ffi_i16_rget))); #endif #if HAVE_I32 ffi_typedef(uint32_s, make_ffi_type_builtin(uint32_s, integer_s, sizeof (i32_t), alignof (i32_t), &ffi_type_uint32, - ffi_u32_put, ffi_u32_get)); + ffi_u32_put, ffi_u32_get, + ifbe(ffi_u32_rput), + ifbe(ffi_u32_rget))); ffi_typedef(int32_s, make_ffi_type_builtin(int32_s, integer_s, sizeof (i32_t), alignof (i32_t), &ffi_type_sint32, - ffi_i32_put, ffi_i32_get)); + ffi_i32_put, ffi_i32_get, + ifbe(ffi_i32_rput), + ifbe(ffi_i32_rget))); #endif #if HAVE_I64 ffi_typedef(uint64_s, make_ffi_type_builtin(uint64_s, integer_s, sizeof (i64_t), alignof (i64_t), &ffi_type_uint64, - ffi_u64_put, ffi_u64_get)); + ffi_u64_put, ffi_u64_get, 0, 0)); ffi_typedef(int64_s, make_ffi_type_builtin(int64_s, integer_s, - sizeof (i64_t), alignof (i64_t), - &ffi_type_sint64, - ffi_i64_put, ffi_i64_get)); + sizeof (i64_t), alignof (i64_t), + &ffi_type_sint64, + ffi_i64_put, ffi_i64_get, 0, 0)); #endif ffi_typedef(uchar_s, make_ffi_type_builtin(uchar_s, integer_s, 1, 1, &ffi_type_uchar, - ffi_uchar_put, ffi_uchar_get)); + ffi_uchar_put, ffi_uchar_get, + ifbe(ffi_uchar_rput), + ifbe(ffi_uchar_rget))); ffi_typedef(char_s, make_ffi_type_builtin(char_s, integer_s, 1, 1, - ffi_char, ffi_char_put, ffi_char_get)); + ffi_char, ffi_char_put, + ffi_char_get, + ifbe(ffi_char_rput), + ifbe(ffi_char_rget))); ffi_typedef(bchar_s, make_ffi_type_builtin(bchar_s, char_s, 1, 1, &ffi_type_uchar, - ffi_uchar_put, ffi_bchar_get)); + ffi_uchar_put, ffi_bchar_get, + ifbe(ffi_uchar_rput), + ifbe(ffi_bchar_rget))); ffi_typedef(wchar_s, make_ffi_type_builtin(wchar_s, char_s, sizeof (wchar_t), alignof (wchar_t), &ffi_type_wchar, - ffi_wchar_put, ffi_wchar_get)); + ffi_wchar_put, ffi_wchar_get, + ifbe(ffi_wchar_rput), + ifbe(ffi_wchar_rget))); ffi_typedef(ushort_s, make_ffi_type_builtin(ushort_s, integer_s, sizeof (short), alignof (short), &ffi_type_ushort, - ffi_ushort_put, ffi_ushort_get)); + ffi_ushort_put, ffi_ushort_get, + ifbe(ffi_ushort_rput), + ifbe(ffi_ushort_rget))); ffi_typedef(short_s, make_ffi_type_builtin(short_s, integer_s, sizeof (short), alignof (short), &ffi_type_sshort, - ffi_short_put, ffi_short_get)); + ffi_short_put, ffi_short_get, + ifbe(ffi_short_rput), + ifbe(ffi_short_rget))); ffi_typedef(int_s, make_ffi_type_builtin(int_s, integer_s, sizeof (int), alignof (int), &ffi_type_sint, - ffi_int_put, ffi_int_get)); + ffi_int_put, ffi_int_get, + ifbe(ffi_int_rput), + ifbe(ffi_int_rget))); ffi_typedef(uint_s, make_ffi_type_builtin(uint_s, integer_s, sizeof (int), alignof (int), &ffi_type_uint, - ffi_uint_put, ffi_uint_get)); + ffi_uint_put, ffi_uint_get, + ifbe(ffi_uint_rput), + ifbe(ffi_uint_rget))); ffi_typedef(ulong_s, make_ffi_type_builtin(ulong_s, integer_s, sizeof (long), alignof (long), &ffi_type_ulong, - ffi_ulong_put, ffi_ulong_get)); + ffi_ulong_put, ffi_ulong_get, + ifbe(ffi_ulong_rput), + ifbe(ffi_ulong_rget))); ffi_typedef(long_s, make_ffi_type_builtin(long_s, integer_s, sizeof (long), alignof (long), &ffi_type_slong, - ffi_long_put, ffi_long_get)); + ffi_long_put, ffi_long_get, + ifbe(ffi_long_rput), + ifbe(ffi_long_rget))); ffi_typedef(float_s, make_ffi_type_builtin(float_s, float_s, sizeof (float), alignof (float), &ffi_type_float, - ffi_float_put, ffi_float_get)); + ffi_float_put, ffi_float_get, + 0, 0)); ffi_typedef(double_s, make_ffi_type_builtin(double_s, float_s, sizeof (double), alignof (double), &ffi_type_double, - ffi_double_put, ffi_double_get)); + ffi_double_put, ffi_double_get, + 0, 0)); ffi_typedef(val_s, make_ffi_type_builtin(val_s, t, sizeof (val), alignof (val), &ffi_type_pointer, - ffi_val_put, ffi_val_get)); + ffi_val_put, ffi_val_get, + 0, 0)); { val type = make_ffi_type_builtin(cptr_s, cptr_s, sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, - ffi_cptr_put, ffi_cptr_get); + ffi_cptr_put, ffi_cptr_get, 0, 0); struct txr_ffi_type *tft = ffi_type_struct(type); tft->alloc = ffi_cptr_alloc; tft->free = ffi_noop_free; @@ -2100,7 +2355,7 @@ static void ffi_init_types(void) val type = make_ffi_type_builtin(str_s, str_s, sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, - ffi_str_put, ffi_str_get); + ffi_str_put, ffi_str_get, 0, 0); struct txr_ffi_type *tft = ffi_type_struct(type); tft->in = ffi_str_in; tft->release = ffi_simple_release; @@ -2111,7 +2366,7 @@ static void ffi_init_types(void) val type = make_ffi_type_builtin(bstr_s, str_s, sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, - ffi_bstr_put, ffi_bstr_get); + ffi_bstr_put, ffi_bstr_get, 0, 0); struct txr_ffi_type *tft = ffi_type_struct(type); tft->in = ffi_bstr_in; tft->release = ffi_simple_release; @@ -2121,14 +2376,14 @@ static void ffi_init_types(void) ffi_typedef(str_d_s, make_ffi_type_builtin(str_d_s, str_s, sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, - ffi_str_put, ffi_str_d_get)); + ffi_str_put, ffi_str_d_get, 0, 0)); { val type = ffi_typedef(wstr_s, make_ffi_type_builtin(wstr_s, str_s, sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, ffi_wstr_put, - ffi_wstr_get)); + ffi_wstr_get, 0, 0)); struct txr_ffi_type *tft = ffi_type_struct(type); tft->in = ffi_wstr_in; tft->release = ffi_simple_release; @@ -2138,11 +2393,13 @@ static void ffi_init_types(void) ffi_typedef(wstr_d_s, make_ffi_type_builtin(wstr_d_s, str_s, sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, - ffi_wstr_put, ffi_wstr_d_get)); + ffi_wstr_put, ffi_wstr_d_get, + 0, 0)); ffi_typedef(bstr_d_s, make_ffi_type_builtin(bstr_d_s, str_s, sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, - ffi_bstr_put, ffi_bstr_d_get)); + ffi_bstr_put, ffi_bstr_d_get, + 0, 0)); { val iter; @@ -2154,7 +2411,7 @@ static void ffi_init_types(void) &ffi_type_pointer, if3(sym == buf_s, ffi_buf_put, ffi_buf_d_put), - ffi_void_get)); + ffi_void_get, 0, 0)); } } @@ -2162,10 +2419,12 @@ static void ffi_init_types(void) sizeof (mem_t *), alignof (mem_t *), &ffi_type_pointer, - ffi_closure_put, ffi_cptr_get)); + ffi_closure_put, ffi_cptr_get, + 0, 0)); ffi_typedef(void_s, make_ffi_type_builtin(void_s, null_s, 0, 0, &ffi_type_void, - ffi_void_put, ffi_void_get)); + ffi_void_put, ffi_void_get, + 0, 0)); } static val ffi_type_lookup(val sym) @@ -2372,7 +2631,7 @@ val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args) val types = tfcd->argtypes; val rtype = tfcd->rettype; struct txr_ffi_type *rtft = ffi_type_struct(rtype); - void *rc = alloca(rtft->size); + void *rc = alloca(pad_retval(rtft->size)); int in_pass_needed = 0; volatile int cleanup_needed = 1; volatile cnum i; @@ -2422,7 +2681,7 @@ val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args) ffi_call(&tfcd->cif, coerce(void (*)(void), fp), rc, values); - ret = rtft->get(rtft, convert(mem_t *, rc), self); + ret = ifbe2(rtft->rget, rtft->get)(rtft, convert(mem_t *, rc), self); if (in_pass_needed) { for (i = 0; i < n; i++) { @@ -2480,7 +2739,7 @@ static void ffi_closure_dispatch(ffi_cif *cif, void *cret, } } - rtft->put(rtft, retval, convert(mem_t *, cret), self); + ifbe2(rtft->rput, rtft->put)(rtft, retval, convert(mem_t *, cret), self); } static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, @@ -2532,7 +2791,7 @@ static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, } } - rtft->put(rtft, retval, convert(mem_t *, cret), self); + ifbe2(rtft->rput, rtft->put)(rtft, retval, convert(mem_t *, cret), self); } uw_unwind { @@ -2543,7 +2802,8 @@ static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, if (!tfcl->abort_retval) memset(cret, 0, rtft->size); else - rtft->put(rtft, tfcl->abort_retval, convert(mem_t *, cret), self); + ifbe2(rtft->rput, rtft->put)(rtft, tfcl->abort_retval, + convert(mem_t *, cret), self); } uw_curr_exit_point = 0; /* stops unwinding */ } |