- size_t i, c = impl->decl->args->count;
- PSI_LibffiData *data = malloc(sizeof(*data) + c * sizeof(ffi_type *));
-
- data->context = context;
- data->impl = impl;
- data->arginfo = psi_internal_arginfo(impl);
- for (i = 0; i < c; ++i) {
- data->params[i] = psi_ffi_decl_arg_type(impl->decl->args->args[i]);
- }
- data->params[c] = NULL;
-
- rc = ffi_prep_cif(
- &data->signature,
- psi_ffi_abi(data->impl->decl->abi->convention),
- c,
- psi_ffi_decl_arg_type(data->impl->decl->func),
- data->params);
- ZEND_ASSERT(FFI_OK == rc);
- data->closure = ffi_closure_alloc(sizeof(ffi_closure), &data->code);
- rc = ffi_prep_closure_loc(
- data->closure,
- &context->signature,
- handler,
- data,
- data->code);
- ZEND_ASSERT(FFI_OK == rc);
-
- context->data.list = realloc(context->data.list, ++context->data.count * sizeof(*context->data.list));
- context->data.list[context->data.count-1] = data;
-
- return data;
-}
-
-static inline void PSI_LibffiDataFree(PSI_LibffiData *data) {
- free(data->arginfo);
- ffi_closure_free(data->closure);
- free(data);
-}
-
-static inline PSI_LibffiContext *PSI_LibffiContextInit(PSI_LibffiContext *L) {
+
+ 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;
+ }
+}
+
+static inline void psi_ffi_callback_dtor(struct psi_let_exp *let_exp) {
+ struct psi_let_callback *cb;
+ struct psi_let_func *fn = NULL;
+
+ switch (let_exp->kind) {
+ case PSI_LET_CALLBACK:
+ cb = let_exp->data.callback;
+
+ psi_ffi_decl_dtor(cb->decl);
+
+ if (cb->info) {
+ struct psi_ffi_callback_info *info = cb->info;
+
+ if (info->closure) {
+ psi_ffi_closure_free(info->closure);
+ }
+ free(info);
+ cb->info = NULL;
+ }
+ 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 *cb;
+
+ while (psi_plist_get(fn->inner, i++, &cb)) {
+ psi_ffi_callback_dtor(cb);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static inline struct psi_ffi_impl_info *psi_ffi_impl_init(struct psi_impl *impl,
+ struct psi_context *C) {
+ struct psi_ffi_context *context = C->context;
+ struct psi_ffi_impl_info *info = calloc(1, sizeof(*info));
+ struct psi_let_stmt *let;
+ ffi_status rc;
+ size_t l = 0;
+
+ info->context = C;
+
+ rc = psi_ffi_prep_closure(&info->closure, &info->code,
+ &context->signature, psi_ffi_handler, impl);
+
+ if (FFI_OK != rc) {
+ free(info);
+ return NULL;
+ }
+
+ while (psi_plist_get(impl->stmts.let, l++, &let)) {
+ psi_ffi_callback_init(info, let->exp);
+ }
+
+ return impl->info = info;
+}
+
+static inline void psi_ffi_impl_dtor(struct psi_impl *impl) {
+ struct psi_ffi_impl_info *info = impl->info;
+ struct psi_let_stmt *let;
+ size_t j = 0;
+
+ while (psi_plist_get(impl->stmts.let, j++, &let)) {
+ psi_ffi_callback_dtor(let->exp);
+ }
+
+ if (info) {
+ if (info->closure) {
+ psi_ffi_closure_free(info->closure);
+ }
+ free(info);
+ impl->info = NULL;
+ }
+}
+
+
+static inline struct psi_ffi_context *psi_ffi_context_init(struct psi_ffi_context *L) {