+ psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **)args[1], impl);
+}
+
+static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
+{
+ struct psi_ffi_callback_info *cb_info = data;
+ struct psi_call_frame_callback cb_data;
+
+ assert(cb_info->impl_info->frame);
+
+ cb_data.cb = cb_info->let_exp;
+ cb_data.argc = sig->nargs;
+ cb_data.argv = args;
+ cb_data.rval = result;
+
+ psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
+}
+
+static inline void psi_ffi_callback_init(struct psi_ffi_impl_info *impl_info,
+ struct psi_let_exp *let_exp) {
+ struct psi_ffi_callback_info *cb_info;
+ struct psi_ffi_decl_info *decl_info;
+ struct psi_let_callback *cb;
+ struct psi_let_func *fn = NULL;
+ ffi_status rc;
+
+ switch (let_exp->kind) {
+ case PSI_LET_CALLBACK:
+ cb = let_exp->data.callback;
+ if (cb->decl->info) {
+ decl_info = cb->decl->info;
+ } else {
+ decl_info = psi_ffi_decl_init(cb->decl);
+ }
+
+ cb_info = calloc(1, sizeof(*cb_info));
+ cb_info->impl_info = impl_info;
+ cb_info->let_exp = let_exp;
+ rc = psi_ffi_prep_closure(&cb_info->closure, &cb_info->code,
+ &decl_info->signature, psi_ffi_callback, cb_info);
+
+ if (FFI_OK != rc) {
+ free(cb_info);
+ break;
+ }
+ cb->info = cb_info;
+
+ assert(!cb->decl->sym);
+ cb->decl->sym = cb_info->code;
+ fn = cb->func;
+ /* no break */
+
+ case PSI_LET_FUNC:
+ if (!fn) {
+ fn = let_exp->data.func;
+ }
+ if (fn->inner) {
+ size_t i = 0;
+ struct psi_let_exp *inner_let;
+
+ while (psi_plist_get(fn->inner, i++, &inner_let)) {
+ psi_ffi_callback_init(impl_info, inner_let);
+ }
+ }
+ break;
+ default:
+ break;