6 #undef PACKAGE_BUGREPORT
10 #undef PACKAGE_VERSION
14 #ifndef PSI_HAVE_FFI_CLOSURE_ALLOC
19 # include <sys/mman.h>
20 # ifndef MAP_ANONYMOUS
21 # define MAP_ANONYMOUS MAP_ANON
26 static void *psi_ffi_closure_alloc(size_t s
, void **code
)
28 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
29 return ffi_closure_alloc(s
, code
);
31 *code
= mmap(NULL
, s
, PROT_EXEC
|PROT_WRITE
|PROT_READ
,
32 MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
33 if (MAP_FAILED
== *code
) {
42 static void psi_ffi_closure_free(void *c
)
44 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
47 munmap(c
, sizeof(ffi_closure
));
51 static void psi_ffi_handler(ffi_cif
*signature
, void *_result
, void **_args
, void *_data
);
53 static inline ffi_abi
psi_ffi_abi(const char *convention
) {
54 return FFI_DEFAULT_ABI
;
56 static inline ffi_type
*psi_ffi_token_type(token_t t
) {
62 return &ffi_type_void
;
64 return &ffi_type_sint8
;
66 return &ffi_type_uint8
;
68 return &ffi_type_sint16
;
70 return &ffi_type_uint16
;
72 return &ffi_type_sint32
;
74 return &ffi_type_uint32
;
76 return &ffi_type_sint64
;
78 return &ffi_type_uint64
;
80 return &ffi_type_uchar
;
82 return &ffi_type_sint
;
84 return &ffi_type_float
;
86 return &ffi_type_double
;
89 static inline ffi_type
*psi_ffi_decl_type(decl_type
*type
) {
90 return psi_ffi_token_type(real_decl_type(type
)->type
);
92 static inline ffi_type
*psi_ffi_decl_arg_type(decl_arg
*darg
) {
93 if (darg
->var
->pointer_level
) {
94 return &ffi_type_pointer
;
96 return psi_ffi_decl_type(darg
->type
);
100 typedef struct PSI_LibffiContext
{
105 typedef struct PSI_LibffiCall
{
107 ffi_closure
*closure
;
109 void *params
[1]; /* [type1, type2, NULL, arg1, arg2] ... */
112 static inline PSI_LibffiCall
*PSI_LibffiCallAlloc(PSI_Context
*C
, decl
*decl
) {
114 size_t i
, c
= decl
->args
? decl
->args
->count
: 0;
115 PSI_LibffiCall
*call
= calloc(1, sizeof(*call
) + 2 * c
* sizeof(void *));
117 for (i
= 0; i
< c
; ++i
) {
118 call
->params
[i
] = psi_ffi_decl_arg_type(decl
->args
->args
[i
]);
120 call
->params
[c
] = NULL
;
122 decl
->call
.info
= call
;
123 decl
->call
.args
= (void **) &call
->params
[c
+1];
125 rc
= ffi_prep_cif(&call
->signature
, psi_ffi_abi(decl
->abi
->convention
),
126 c
, psi_ffi_decl_arg_type(decl
->func
), (ffi_type
**) call
->params
);
127 ZEND_ASSERT(FFI_OK
== rc
);
132 static inline void PSI_LibffiCallInitClosure(PSI_Context
*C
, PSI_LibffiCall
*call
, impl
*impl
) {
133 PSI_LibffiContext
*context
= C
->context
;
136 call
->closure
= psi_ffi_closure_alloc(sizeof(ffi_closure
), &call
->code
);
137 ZEND_ASSERT(call
->closure
!= NULL
);
139 #if PSI_HAVE_FFI_PREP_CLOSURE_LOC
140 rc
= ffi_prep_closure_loc(
147 #elif PSI_HAVE_FFI_PREP_CLOSURE
148 rc
= ffi_prep_closure(data
->code
, &context
->signature
, psi_ffi_handler
, data
);
150 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() available"
152 ZEND_ASSERT(FFI_OK
== rc
);
155 static inline void PSI_LibffiCallFree(PSI_LibffiCall
*call
) {
157 psi_ffi_closure_free(call
->closure
);
162 static inline PSI_LibffiContext
*PSI_LibffiContextInit(PSI_LibffiContext
*L
) {
166 L
= malloc(sizeof(*L
));
168 memset(L
, 0, sizeof(*L
));
170 L
->params
[0] = &ffi_type_pointer
;
171 L
->params
[1] = &ffi_type_pointer
;
172 rc
= ffi_prep_cif(&L
->signature
, FFI_DEFAULT_ABI
, 2, &ffi_type_void
, L
->params
);
173 ZEND_ASSERT(rc
== FFI_OK
);
178 static void psi_ffi_handler(ffi_cif
*_sig
, void *_result
, void **_args
, void *_data
)
180 psi_call(*(zend_execute_data
**)_args
[0], *(zval
**)_args
[1], _data
);
183 static void psi_ffi_init(PSI_Context
*C
)
185 C
->context
= PSI_LibffiContextInit(NULL
);
188 static void psi_ffi_dtor(PSI_Context
*C
) {
191 for (i
= 0; i
< C
->decls
->count
; ++i
) {
192 decl
*decl
= C
->decls
->list
[i
];
194 if (decl
->call
.info
) {
195 PSI_LibffiCallFree(decl
->call
.info
);
201 static zend_function_entry
*psi_ffi_compile(PSI_Context
*C
)
204 zend_function_entry
*zfe
;
210 zfe
= calloc(C
->impls
->count
+ 1, sizeof(*zfe
));
211 for (i
= 0; i
< C
->impls
->count
; ++i
) {
212 zend_function_entry
*zf
= &zfe
[j
];
213 PSI_LibffiCall
*call
;
214 impl
*impl
= C
->impls
->list
[i
];
220 call
= PSI_LibffiCallAlloc(C
, impl
->decl
);
221 PSI_LibffiCallInitClosure(C
, call
, impl
);
223 zf
->fname
= impl
->func
->name
+ (impl
->func
->name
[0] == '\\');
224 zf
->num_args
= impl
->func
->args
->count
;
225 zf
->handler
= call
->code
;
226 zf
->arg_info
= psi_internal_arginfo(impl
);
230 for (i
= 0; i
< C
->decls
->count
; ++i
) {
231 decl
*decl
= C
->decls
->list
[i
];
237 PSI_LibffiCallAlloc(C
, decl
);
243 static void psi_ffi_call(PSI_Context
*C
, impl_val
*ret_val
, decl
*decl
) {
244 PSI_LibffiCall
*call
= decl
->call
.info
;
246 ffi_call(&call
->signature
, FFI_FN(decl
->call
.sym
), ret_val
, decl
->call
.args
);
249 static PSI_ContextOps ops
= {
256 PSI_ContextOps
*PSI_Libffi(void)