From d2728e196d67557805e28d85509da61f1754c160 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 22 Oct 2022 20:58:49 +0100 Subject: [PATCH] Handle FFI calls that return unconstrained arrays --- src/jit/jit-core.c | 8 ++++---- src/jit/jit-ffi.c | 39 ++++++++++++++++++++++++++++----------- src/jit/jit-ffi.h | 2 +- src/jit/jit-interp.c | 2 +- src/jit/jit-irgen.c | 6 +++++- 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/jit/jit-core.c b/src/jit/jit-core.c index 5b8abfe2..ec68881a 100644 --- a/src/jit/jit-core.c +++ b/src/jit/jit-core.c @@ -488,12 +488,12 @@ static bool jit_try_vcall(jit_t *j, jit_func_t *f, jit_scalar_t *result, if (ff == NULL) ff = jit_ffi_bind(f->name, f->spec, f->symbol); - *result = jit_ffi_call(ff, args); + jit_ffi_call(ff, args); } - else { + else failed = !jit_interp(f, args); - *result = args[0]; - } + + *result = args[0]; } else { jit_set_exit_status(j, rc - 1); diff --git a/src/jit/jit-ffi.c b/src/jit/jit-ffi.c index d408a457..a1188dde 100644 --- a/src/jit/jit-ffi.c +++ b/src/jit/jit-ffi.c @@ -39,6 +39,7 @@ typedef struct _jit_foreign { ffi_cif cif; void *ptr; ident_t sym; + ffi_spec_t spec; int nargs; ffi_type *args[0]; } jit_foreign_t; @@ -75,8 +76,8 @@ static ffi_type *libffi_type_for(ffi_type_t type) case FFI_INT32: return &ffi_type_sint32; case FFI_INT64: return &ffi_type_sint64; case FFI_FLOAT: return &ffi_type_double; - case FFI_UARRAY: case FFI_POINTER: return &ffi_type_pointer; + case FFI_UARRAY: case FFI_VOID: default: return &ffi_type_void; } @@ -96,11 +97,16 @@ jit_foreign_t *jit_ffi_bind(ident_t sym, ffi_spec_t spec, void *ptr) fatal("sorry, cannot call foreign function %s with more than " "15 arguments", istr(sym)); - jit_foreign_t *ff = - xcalloc_flex(sizeof(jit_foreign_t), nargs, sizeof(ffi_type *)); + int adj_nargs = nargs; + if ((spec & 0xf) == FFI_UARRAY) + adj_nargs++; + + jit_foreign_t *ff = xcalloc_flex(sizeof(jit_foreign_t), + adj_nargs, sizeof(ffi_type *)); ff->ptr = ptr; ff->sym = sym; ff->nargs = nargs; + ff->spec = spec; int wptr = 0; for (ffi_spec_t s = spec >> 4; (s & 0xf) != FFI_VOID; s >>= 4) { @@ -112,37 +118,48 @@ jit_foreign_t *jit_ffi_bind(ident_t sym, ffi_spec_t spec, void *ptr) else ff->args[wptr++] = libffi_type_for(s & 0xf); } - assert(wptr == nargs); + if ((spec & 0xf) == FFI_UARRAY) + ff->args[wptr++] = &ffi_type_pointer; + assert(wptr == adj_nargs); ffi_type *ret = libffi_type_for(spec & 0xf); - if (ffi_prep_cif(&ff->cif, FFI_DEFAULT_ABI, nargs, ret, ff->args) != FFI_OK) + if (ffi_prep_cif(&ff->cif, FFI_DEFAULT_ABI, adj_nargs, + ret, ff->args) != FFI_OK) fatal("ffi_prep_cif failed for %s", istr(sym)); hash_put(cache, sym, ff); return ff; } -jit_scalar_t jit_ffi_call(jit_foreign_t *ff, jit_scalar_t *args) +void jit_ffi_call(jit_foreign_t *ff, jit_scalar_t *args) { - void *aptrs[ff->nargs]; + void *aptrs[ff->nargs + 1]; for (int i = 0; i < ff->nargs; i++) aptrs[i] = &(args[i].integer); + ffi_uarray_t u, *up = &u; + if ((ff->spec & 0xf) == FFI_UARRAY) + aptrs[ff->nargs] = &up; + if (ff->ptr == NULL) { LOCAL_TEXT_BUF tb = tb_new(); tb_istr(tb, ff->sym); - if ((ff->ptr = ffi_find_symbol(NULL, tb_get(tb))) == NULL) { + if ((ff->ptr = ffi_find_symbol(NULL, tb_get(tb))) == NULL) jit_msg(NULL, DIAG_FATAL, "foreign function %s not found", tb_get(tb)); - return (jit_scalar_t){ .integer = 0 }; // TODO: should not reach here - } } jit_scalar_t result; ffi_call(&ff->cif, ff->ptr, &result, aptrs); - return result; + if ((ff->spec & 0xf) == FFI_UARRAY) { + args[0].pointer = u.ptr; + args[1].integer = u.dims[0].left; + args[2].integer = u.dims[0].length; + } + else + args[0] = result; } int ffi_count_args(ffi_spec_t spec) diff --git a/src/jit/jit-ffi.h b/src/jit/jit-ffi.h index 489f848d..547c3f7d 100644 --- a/src/jit/jit-ffi.h +++ b/src/jit/jit-ffi.h @@ -59,7 +59,7 @@ typedef struct _ffi_closure { jit_foreign_t *jit_ffi_bind(ident_t sym, ffi_spec_t spec, void *ptr); jit_foreign_t *jit_ffi_get(ident_t sym); -jit_scalar_t jit_ffi_call(jit_foreign_t *ff, jit_scalar_t *args); +void jit_ffi_call(jit_foreign_t *ff, jit_scalar_t *args); int ffi_count_args(ffi_spec_t spec); ffi_uarray_t ffi_wrap_str(char *buf, size_t len); diff --git a/src/jit/jit-interp.c b/src/jit/jit-interp.c index 14ccf834..6c79b603 100644 --- a/src/jit/jit-interp.c +++ b/src/jit/jit-interp.c @@ -1216,7 +1216,7 @@ static void interp_exit(jit_interp_t *state, jit_ir_t *ir) static void interp_fficall(jit_interp_t *state, jit_ir_t *ir) { jit_foreign_t *ff = interp_get_value(state, ir->arg1).pointer; - state->args[0] = jit_ffi_call(ff, state->args); + jit_ffi_call(ff, state->args); } static void interp_getpriv(jit_interp_t *state, jit_ir_t *ir) diff --git a/src/jit/jit-irgen.c b/src/jit/jit-irgen.c index 2e2ed7ad..be42c3be 100644 --- a/src/jit/jit-irgen.c +++ b/src/jit/jit-irgen.c @@ -1984,8 +1984,12 @@ static void irgen_op_fcall(jit_irgen_t *g, int op) macro_fficall(g, addr); vcode_reg_t result = vcode_get_result(op); - if (result != VCODE_INVALID_REG) + if (result != VCODE_INVALID_REG) { + const int slots = irgen_slots_for_type(vcode_reg_type(result)); g->map[result] = j_recv(g, 0); + for (int i = 1; i < slots; i++) + j_recv(g, i); + } } else { vcode_reg_t result = vcode_get_result(op); -- 2.39.2