-static inline PSI_LibffiData *PSI_LibffiDataAlloc(PSI_LibffiContext *context, impl *impl) {
- ffi_status rc;
- 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) {
+static inline ffi_abi psi_ffi_abi(zend_string *convention) {
+ if (FFI_LAST_ABI - 2 != FFI_FIRST_ABI) {
+#ifdef HAVE_FFI_STDCALL
+ if (zend_string_equals_literal(convention, "stdcall")) {
+ return FFI_STDCALL;
+ }
+#endif
+#ifdef HAVE_FFI_FASTCALL
+ if (zend_string_equals_literal(convention, "fastcall")) {
+ return FFI_FASTCALL;
+ }
+#endif
+ }
+ return FFI_DEFAULT_ABI;
+}
+
+static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
+{
+ struct psi_impl *impl = data;
+ struct psi_ffi_impl_info *info = impl->info;
+
+ 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 bool psi_ffi_load()
+{
+#if HAVE_INT128
+ ffi_type *i128, *u128;
+
+ i128 = pecalloc(1, 3*sizeof(ffi_type), 1);
+ i128->type = FFI_TYPE_STRUCT;
+ i128->size = 0;
+ i128->elements = (ffi_type **) (i128 + 1);
+ i128->elements[0] = &ffi_type_sint64;
+ i128->elements[1] = &ffi_type_sint64;
+
+ ffi_type_sint128 = i128;
+
+ u128 = pecalloc(1, 3*sizeof(ffi_type), 1);
+ u128->type = FFI_TYPE_STRUCT;
+ u128->size = 0;
+ u128->elements = (ffi_type **) (u128 + 1);
+ u128->elements[0] = &ffi_type_uint64;
+ u128->elements[1] = &ffi_type_uint64;
+
+ ffi_type_uint128 = u128;
+#endif
+ return true;
+}
+
+static void psi_ffi_free()
+{
+#if HAVE_INT128
+ free(ffi_type_sint128);
+ free(ffi_type_uint128);
+#endif
+}
+
+static bool psi_ffi_init(struct psi_context *C)
+{