13 #undef PACKAGE_BUGREPORT
16 #undef PACKAGE_TARNAME
17 #undef PACKAGE_VERSION
21 #ifndef PSI_HAVE_FFI_CLOSURE_ALLOC
26 # include <sys/mman.h>
27 # ifndef MAP_ANONYMOUS
28 # define MAP_ANONYMOUS MAP_ANON
33 static void *psi_ffi_closure_alloc(size_t s
, void **code
)
35 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
36 return ffi_closure_alloc(s
, code
);
38 *code
= mmap(NULL
, s
, PROT_EXEC
|PROT_WRITE
|PROT_READ
,
39 MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
40 if (MAP_FAILED
== *code
) {
49 static void psi_ffi_closure_free(void *c
)
51 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
54 munmap(c
, sizeof(ffi_closure
));
58 static void psi_ffi_handler(ffi_cif
*signature
, void *_result
, void **_args
, void *_data
);
59 static inline ffi_type
*psi_ffi_decl_arg_type(decl_arg
*darg
);
61 static inline ffi_abi
psi_ffi_abi(const char *convention
) {
62 return FFI_DEFAULT_ABI
;
64 static inline ffi_type
*psi_ffi_token_type(token_t t
) {
70 return &ffi_type_void
;
72 return &ffi_type_sint8
;
74 return &ffi_type_uint8
;
76 return &ffi_type_sint16
;
78 return &ffi_type_uint16
;
80 return &ffi_type_sint32
;
82 return &ffi_type_uint32
;
84 return &ffi_type_sint64
;
86 return &ffi_type_uint64
;
88 return &ffi_type_uchar
;
90 return &ffi_type_sint
;
92 return &ffi_type_slong
;
94 return &ffi_type_float
;
96 return &ffi_type_double
;
98 return &ffi_type_pointer
;
101 static inline ffi_type
*psi_ffi_impl_type(token_t impl_type
) {
104 return &ffi_type_sint8
;
106 return &ffi_type_sint64
;
108 return &ffi_type_pointer
;
111 return &ffi_type_double
;
112 EMPTY_SWITCH_DEFAULT_CASE();
116 static void psi_ffi_struct_type_dtor(void *type
) {
117 ffi_type
*strct
= type
;
119 if (strct
->elements
) {
122 for (ptr
= strct
->elements
; *ptr
; ++ptr
) {
125 free(strct
->elements
);
130 static ffi_type
**psi_ffi_struct_type_elements(decl_struct
*strct
) {
131 size_t i
, j
, argc
= strct
->args
->count
<< 2, nels
= 0, offset
= 0, align
, padding
;
132 ffi_type
**els
= calloc(argc
+ 1, sizeof(*els
));
134 for (i
= 0; i
< strct
->args
->count
; ++i
) {
135 decl_arg
*darg
= strct
->args
->args
[i
];
136 ffi_type
*type
= malloc(sizeof(*type
));
138 memcpy(type
, psi_ffi_decl_arg_type(darg
), sizeof(*type
));
140 if (darg
->layout
->pos
> offset
) {
141 padding
= darg
->layout
->pos
- offset
;
142 align
= ((padding
- 1) | (type
->alignment
- 1)) + 1;
143 if (align
>= padding
) {
152 for (j
= 0; j
< padding
; ++j
) {
153 ffi_type
*pad
= malloc(sizeof(*pad
));
155 ZEND_ASSERT(nels
+ 1 < argc
);
156 memcpy(pad
, &ffi_type_schar
, sizeof(*pad
));
161 ZEND_ASSERT(nels
+ 1 < argc
);
164 offset
+= MAX(align
, padding
) + darg
->layout
->len
;
167 ZEND_ASSERT(offset
<= strct
->size
);
168 if (offset
< strct
->size
) {
169 padding
= strct
->size
- offset
;
170 for (j
= 0; j
< padding
; ++j
) {
171 ffi_type
*pad
= malloc(sizeof(*pad
));
173 ZEND_ASSERT(nels
+ 1 < argc
);
174 memcpy(pad
, &ffi_type_schar
, sizeof(*pad
));
181 static inline ffi_type
*psi_ffi_decl_type(decl_type
*type
) {
182 decl_type
*real
= real_decl_type(type
);
184 if (real
->type
== PSI_T_STRUCT
) {
185 if (!real
->strct
->engine
.type
) {
186 ffi_type
*strct
= calloc(1, sizeof(ffi_type
));
188 strct
->type
= FFI_TYPE_STRUCT
;
189 strct
->size
= real
->strct
->size
;
190 strct
->elements
= psi_ffi_struct_type_elements(real
->strct
);
192 real
->strct
->engine
.type
= strct
;
193 real
->strct
->engine
.dtor
= psi_ffi_struct_type_dtor
;
196 return real
->strct
->engine
.type
;
198 return psi_ffi_token_type(real
->type
);
200 static inline ffi_type
*psi_ffi_decl_arg_type(decl_arg
*darg
) {
201 if (darg
->var
->pointer_level
) {
202 return &ffi_type_pointer
;
204 return psi_ffi_decl_type(darg
->type
);
208 typedef struct PSI_LibffiContext
{
213 typedef struct PSI_LibffiCall
{
215 ffi_closure
*closure
;
217 void *params
[1]; /* [type1, type2, NULL, arg1, arg2] ... */
220 static inline PSI_LibffiCall
*PSI_LibffiCallAlloc(PSI_Context
*C
, decl
*decl
) {
222 size_t i
, c
= decl
->args
? decl
->args
->count
: 0;
223 PSI_LibffiCall
*call
= calloc(1, sizeof(*call
) + 2 * c
* sizeof(void *));
225 for (i
= 0; i
< c
; ++i
) {
226 call
->params
[i
] = psi_ffi_decl_arg_type(decl
->args
->args
[i
]);
228 call
->params
[c
] = NULL
;
230 decl
->call
.info
= call
;
231 decl
->call
.rval
= &decl
->func
->ptr
;
233 decl
->call
.args
= (void **) &call
->params
[c
+1];
235 rc
= ffi_prep_cif(&call
->signature
, psi_ffi_abi(decl
->abi
->convention
),
236 c
, psi_ffi_decl_arg_type(decl
->func
), (ffi_type
**) call
->params
);
237 ZEND_ASSERT(FFI_OK
== rc
);
242 static inline void PSI_LibffiCallInitClosure(PSI_Context
*C
, PSI_LibffiCall
*call
, impl
*impl
) {
243 PSI_LibffiContext
*context
= C
->context
;
246 call
->closure
= psi_ffi_closure_alloc(sizeof(ffi_closure
), &call
->code
);
247 ZEND_ASSERT(call
->closure
!= NULL
);
249 #if PSI_HAVE_FFI_PREP_CLOSURE_LOC
250 rc
= ffi_prep_closure_loc(
257 #elif PSI_HAVE_FFI_PREP_CLOSURE
258 rc
= ffi_prep_closure(call
->code
, &context
->signature
, psi_ffi_handler
, impl
);
260 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() available"
262 ZEND_ASSERT(FFI_OK
== rc
);
265 static inline void PSI_LibffiCallFree(PSI_LibffiCall
*call
) {
267 psi_ffi_closure_free(call
->closure
);
272 static inline PSI_LibffiContext
*PSI_LibffiContextInit(PSI_LibffiContext
*L
) {
276 L
= malloc(sizeof(*L
));
278 memset(L
, 0, sizeof(*L
));
280 L
->params
[0] = &ffi_type_pointer
;
281 L
->params
[1] = &ffi_type_pointer
;
282 rc
= ffi_prep_cif(&L
->signature
, FFI_DEFAULT_ABI
, 2, &ffi_type_void
, L
->params
);
283 ZEND_ASSERT(rc
== FFI_OK
);
288 static void psi_ffi_handler(ffi_cif
*_sig
, void *_result
, void **_args
, void *_data
)
290 psi_call(*(zend_execute_data
**)_args
[0], *(zval
**)_args
[1], _data
);
293 static void psi_ffi_init(PSI_Context
*C
)
295 C
->context
= PSI_LibffiContextInit(NULL
);
298 static void psi_ffi_dtor(PSI_Context
*C
)
303 for (i
= 0; i
< C
->decls
->count
; ++i
) {
304 decl
*decl
= C
->decls
->list
[i
];
306 if (decl
->call
.info
) {
307 PSI_LibffiCallFree(decl
->call
.info
);
314 static zend_function_entry
*psi_ffi_compile(PSI_Context
*C
)
317 zend_function_entry
*zfe
;
323 zfe
= calloc(C
->impls
->count
+ 1, sizeof(*zfe
));
324 for (i
= 0; i
< C
->impls
->count
; ++i
) {
325 zend_function_entry
*zf
= &zfe
[j
];
326 PSI_LibffiCall
*call
;
327 impl
*impl
= C
->impls
->list
[i
];
333 call
= PSI_LibffiCallAlloc(C
, impl
->decl
);
334 PSI_LibffiCallInitClosure(C
, call
, impl
);
336 zf
->fname
= impl
->func
->name
+ (impl
->func
->name
[0] == '\\');
337 zf
->num_args
= impl
->func
->args
->count
;
338 zf
->handler
= call
->code
;
339 zf
->arg_info
= psi_internal_arginfo(impl
);
343 for (i
= 0; i
< C
->decls
->count
; ++i
) {
344 decl
*decl
= C
->decls
->list
[i
];
350 PSI_LibffiCallAlloc(C
, decl
);
356 static void psi_ffi_call(PSI_Context
*C
, decl_callinfo
*decl_call
, impl_vararg
*va
) {
357 PSI_LibffiCall
*call
= decl_call
->info
;
362 size_t i
, nfixedargs
= decl_call
->argc
, ntotalargs
= nfixedargs
+ va
->args
->count
;
363 void **params
= calloc(2 * ntotalargs
+ 2, sizeof(void *));
365 for (i
= 0; i
< nfixedargs
; ++i
) {
366 params
[i
] = call
->params
[i
];
367 params
[i
+ ntotalargs
+ 1] = call
->params
[i
+ nfixedargs
+ 1];
369 for (i
= 0; i
< va
->args
->count
; ++i
) {
370 params
[nfixedargs
+ i
] = psi_ffi_impl_type(va
->types
[i
]);
371 params
[nfixedargs
+ i
+ ntotalargs
+ 1] = &va
->values
[i
];
373 #ifdef PSI_HAVE_FFI_PREP_CIF_VAR
374 rc
= ffi_prep_cif_var(&signature
, call
->signature
.abi
,
375 nfixedargs
, ntotalargs
,
376 call
->signature
.rtype
, (ffi_type
**) params
);
378 /* FIXME: test in config.m4; assume we can just call anyway */
379 rc
= ffi_prep_cif(&signature
, call
->signature
.abi
, ntotalargs
,
380 call
->signature
.rtype
, (ffi_type
**) params
);
382 ZEND_ASSERT(FFI_OK
== rc
);
383 ffi_call(&signature
, FFI_FN(decl_call
->sym
), *decl_call
->rval
, ¶ms
[ntotalargs
+ 1]);
386 ffi_call(&call
->signature
, FFI_FN(decl_call
->sym
), *decl_call
->rval
, decl_call
->args
);
390 static PSI_ContextOps ops
= {
397 PSI_ContextOps
*PSI_Libffi(void)
402 #endif /* HAVE_LIBFFI */