+}
+
+static ffi_status psi_ffi_prep_closure(ffi_closure **closure, void **code, ffi_cif *sig, void (*handler)(ffi_cif*,void*,void**,void*), void *data) {
+ *closure = psi_ffi_closure_alloc(sizeof(ffi_closure), code);
+ assert(*closure != NULL);
+
+#if PSI_HAVE_FFI_PREP_CLOSURE_LOC
+ return ffi_prep_closure_loc(*closure, sig, handler, data, *code);
+
+#elif PSI_HAVE_FFI_PREP_CLOSURE
+ return ffi_prep_closure(*code, sig, handler, data);
+#else
+# error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() is available"
+#endif
+}
+
+static void psi_ffi_closure_free(void *c)
+{
+#ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
+ ffi_closure_free(c);
+#elif HAVE_MMAP
+ munmap(c, sizeof(ffi_closure));
+#endif
+}
+
+static void psi_ffi_prep_va(ffi_cif *base, ffi_cif *signature, size_t argc, size_t va_count,
+ ffi_type **param_types) {
+ ffi_status rc;
+
+#ifdef PSI_HAVE_FFI_PREP_CIF_VAR
+ rc = ffi_prep_cif_var(signature, base->abi, argc, argc + va_count,
+ base->rtype, param_types);
+#else
+ /* FIXME: test in config.m4; assume we can just call anyway */
+ rc = ffi_prep_cif(signature, base->abi, argc + va_count, base->rtype, param_types);
+#endif
+
+ assert(FFI_OK == rc);
+}
+
+static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg);
+
+struct psi_ffi_context {
+ ffi_cif signature;
+ ffi_type *params[2];
+};
+
+struct psi_ffi_call {
+ struct psi_context *context;
+ union {
+ struct {
+ struct psi_impl *impl;
+ struct psi_call_frame *frame;
+ } fn;
+ struct {
+ struct psi_let_exp *let_exp;
+ struct psi_ffi_call *impl_call;
+ } cb;
+ } impl;
+ void *code;
+ ffi_closure *closure;
+ ffi_cif signature;
+ ffi_type *params[1]; /* [type1, type2, ... ] */
+};
+
+static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
+{
+ struct psi_ffi_call *call = data;
+
+ psi_context_call(call->context, *(zend_execute_data **)args[0], *(zval **)args[1], call->impl.fn.impl);
+}
+
+static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
+{
+ struct psi_ffi_call *call = data, *impl_call = call->impl.cb.impl_call;
+
+ if (impl_call->impl.fn.frame) {
+ struct psi_call_frame_callback cbdata;
+
+ cbdata.cb = call->impl.cb.let_exp;
+ cbdata.argc = sig->nargs;
+ cbdata.argv = args;
+ cbdata.rval = result;