- void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
-} PSI_LibjitCall;
-
-typedef struct PSI_LibjitData {
- PSI_LibjitContext *context;
- impl *impl;
- zend_internal_arg_info *arginfo;
-} PSI_LibjitData;
-
-static inline PSI_LibjitCall *PSI_LibjitCallAlloc(PSI_Context *C, decl *decl) {
- size_t i, c = decl->args ? decl->args->count : 0;
- PSI_LibjitCall *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
-
- for (i = 0; i < c; ++i) {
- call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
- }
- call->params[c] = NULL;
-
- decl->call.info = call;
- decl->call.rval = &decl->func->ptr;
- decl->call.argc = c;
- decl->call.args = (void **) &call->params[c+1];
-
- call->signature = jit_type_create_signature(
- psi_jit_abi(decl->abi->convention),
- psi_jit_decl_arg_type(decl->func),
- (jit_type_t *) call->params, c, 1);
- return call;
+ void *params[1];
+};
+
+static inline struct psi_jit_decl_info *psi_jit_decl_init(struct psi_decl *decl) {
+ if (!decl->info) {
+ size_t i, c = psi_plist_count(decl->args);
+ struct psi_decl_arg *arg;
+ struct psi_jit_decl_info *info = calloc(1, sizeof(*info) + 2 * c * sizeof(void *));
+
+ for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
+ info->params[i] = psi_jit_decl_arg_type(arg);
+ }
+ info->params[c] = NULL;
+
+ info->signature = jit_type_create_signature(
+ psi_jit_abi(decl->abi->convention),
+ psi_jit_decl_arg_type(decl->func),
+ (jit_type_t *) info->params,
+ c, 1);
+
+ if (!info->signature) {
+ free(info);
+ } else {
+ decl->info = info;
+ }
+ }
+
+ return decl->info;
+}
+
+static inline void psi_jit_decl_dtor(struct psi_decl *decl) {
+ if (decl->info) {
+ struct psi_jit_decl_info *info = decl->info;
+
+ jit_type_free(info->signature);
+ free(info);
+ decl->info = NULL;
+ }
+}
+
+static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
+{
+ struct psi_impl *impl = data;
+ struct psi_jit_impl_info *info = impl->info;
+
+ psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **) args[1], impl);
+}
+
+static void psi_jit_callback(jit_type_t sig, void *result, void **args, void *data)
+{
+ struct psi_jit_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 = jit_type_num_params(sig);
+ cb_data.argv = args;
+ cb_data.rval = result;
+
+ psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
+}
+
+static inline void psi_jit_callback_init(struct psi_jit_impl_info *impl_info,
+ struct psi_let_exp *let_exp)
+{
+ struct psi_jit_context *context = impl_info->context->context;
+ struct psi_jit_callback_info *cb_info;
+ struct psi_jit_decl_info *decl_info;
+ struct psi_let_callback *cb;
+ struct psi_let_func *fn = NULL;
+
+ 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_jit_decl_init(cb->decl);
+ }
+
+ cb_info = calloc(1, sizeof(*cb_info));
+ cb_info->impl_info = impl_info;
+ cb_info->let_exp = let_exp;
+ cb_info->closure = jit_closure_create(context->jit, decl_info->signature,
+ &psi_jit_callback, cb_info);
+
+ if (!cb_info->closure) {
+ free(cb_info);
+ break;
+ }
+ cb->info = cb_info;
+
+ assert(!cb->decl->sym);
+ cb->decl->sym = cb_info->closure;
+ 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_jit_callback_init(impl_info, inner_let);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static inline void psi_jit_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_jit_decl_dtor(cb->decl);
+
+ if (cb->info) {
+ struct psi_jit_callback_info *info = cb->info;
+
+ if (info->closure) {
+ /* The memory for the closure will be reclaimed when the context is destroyed.
+ 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_jit_callback_dtor(cb);
+ }
+ }
+ break;
+ default:
+ break;
+ }