897affbd56d28dded713f8029159b7ec0fa70884
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 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_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_schar
;
84 return &ffi_type_sshort
;
86 return &ffi_type_sint
;
88 return &ffi_type_slong
;
90 return &ffi_type_float
;
92 return &ffi_type_double
;
95 static inline ffi_type
*psi_ffi_decl_type(decl_type
*type
) {
96 return psi_ffi_type(real_decl_type(type
)->type
);
98 static inline ffi_type
*psi_ffi_decl_arg_type(decl_arg
*darg
) {
99 if (darg
->var
->pointer_level
) {
100 return &ffi_type_pointer
;
102 return psi_ffi_decl_type(darg
->type
);
106 typedef struct PSI_LibffiContext
{
110 struct PSI_LibffiData
**list
;
115 typedef struct PSI_LibffiData
{
116 PSI_LibffiContext
*context
;
118 zend_internal_arg_info
*arginfo
;
120 ffi_closure
*closure
;
125 static inline PSI_LibffiData
*PSI_LibffiDataAlloc(PSI_LibffiContext
*context
, impl
*impl
) {
127 size_t i
, c
= impl
->decl
->args
? impl
->decl
->args
->count
: 0;
128 PSI_LibffiData
*data
= malloc(sizeof(*data
) + c
* sizeof(ffi_type
*));
130 data
->context
= context
;
132 data
->arginfo
= psi_internal_arginfo(impl
);
133 for (i
= 0; i
< c
; ++i
) {
134 data
->params
[i
] = psi_ffi_decl_arg_type(impl
->decl
->args
->args
[i
]);
136 data
->params
[c
] = NULL
;
140 psi_ffi_abi(data
->impl
->decl
->abi
->convention
),
142 psi_ffi_decl_arg_type(data
->impl
->decl
->func
),
144 ZEND_ASSERT(FFI_OK
== rc
);
146 data
->closure
= psi_ffi_closure_alloc(sizeof(ffi_closure
), &data
->code
);
147 ZEND_ASSERT(data
->closure
!= NULL
);
148 #if PSI_HAVE_FFI_PREP_CLOSURE_LOC
149 rc
= ffi_prep_closure_loc(
155 ZEND_ASSERT(FFI_OK
== rc
);
156 #elif PSI_HAVE_FFI_PREP_CLOSURE
157 rc
= ffi_prep_closure(data
->code
, &context
->signature
, handler
, data
);
158 ZEND_ASSERT(FFI_OK
== rc
);
160 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() available"
163 context
->data
.list
= realloc(context
->data
.list
, ++context
->data
.count
* sizeof(*context
->data
.list
));
164 context
->data
.list
[context
->data
.count
-1] = data
;
169 static inline void PSI_LibffiDataFree(PSI_LibffiData
*data
) {
170 psi_ffi_closure_free(data
->closure
);
175 static inline PSI_LibffiContext
*PSI_LibffiContextInit(PSI_LibffiContext
*L
) {
179 L
= malloc(sizeof(*L
));
181 memset(L
, 0, sizeof(*L
));
183 L
->params
[0] = &ffi_type_pointer
;
184 L
->params
[1] = &ffi_type_pointer
;
185 rc
= ffi_prep_cif(&L
->signature
, FFI_DEFAULT_ABI
, 2, &ffi_type_void
, L
->params
);
186 ZEND_ASSERT(rc
== FFI_OK
);
191 static inline void PSI_LibffiContextDtor(PSI_LibffiContext
*L
) {
194 for (i
= 0; i
< L
->data
.count
; ++i
) {
195 PSI_LibffiDataFree(L
->data
.list
[i
]);
202 static inline void PSI_LibffiContextFree(PSI_LibffiContext
**L
) {
204 PSI_LibffiContextDtor(*L
);
210 static void handler(ffi_cif
*_sig
, void *_result
, void **_args
, void *_data
)
212 PSI_LibffiData
*data
= _data
;
214 void **arg_ptr
= NULL
, **arg_prm
= NULL
;
217 if (SUCCESS
!= psi_parse_args(*(zend_execute_data
**)_args
[0], data
->impl
)) {
221 if (data
->impl
->decl
->args
) {
222 arg_ptr
= malloc(data
->impl
->decl
->args
->count
* sizeof(*arg_ptr
));
223 arg_prm
= malloc(data
->impl
->decl
->args
->count
* sizeof(*arg_prm
));
225 for (i
= 0; i
< data
->impl
->decl
->args
->count
; ++i
) {
226 decl_arg
*darg
= data
->impl
->decl
->args
->args
[i
];
228 arg_ptr
[i
] = psi_do_let(darg
);
229 arg_prm
[i
] = (darg
->let
->val
&& darg
->let
->val
->is_reference
)
230 ? &arg_ptr
[i
] : arg_ptr
[i
];
232 darg
->let
->ptr
= arg_ptr
[i
];
236 ffi_call(&data
->signature
, FFI_FN(data
->impl
->decl
->dlptr
), &ret_val
, arg_prm
);
238 psi_do_return(data
->impl
, &ret_val
, *(zval
**)_args
[1]);
240 for (i
= 0; i
< data
->impl
->stmts
->set
.count
; ++i
) {
241 set_stmt
*set
= data
->impl
->stmts
->set
.list
[i
];
244 psi_do_set(set
->arg
->_zv
, set
->val
->func
, set
->val
->vars
);
248 for (i
= 0; i
< data
->impl
->stmts
->fre
.count
; ++i
) {
249 free_stmt
*fre
= data
->impl
->stmts
->fre
.list
[i
];
254 psi_do_clean(data
->impl
);
264 static void init(PSI_Context
*C
)
266 C
->context
= PSI_LibffiContextInit(NULL
);
269 static void dtor(PSI_Context
*C
)
271 PSI_LibffiContextFree((void *) &C
->context
);
274 static zend_function_entry
*compile(PSI_Context
*C
, PSI_Data
*D
)
277 zend_function_entry
*zfe
= calloc(D
->impls
->count
+ 1, sizeof(*zfe
));
278 PSI_LibffiContext
*ctx
= C
->context
;
280 for (i
= 0; i
< D
->impls
->count
; ++i
) {
281 zend_function_entry
*zf
= &zfe
[j
];
282 PSI_LibffiData
*data
;
284 if (!D
->impls
->list
[i
]->decl
) {
288 data
= PSI_LibffiDataAlloc(ctx
, D
->impls
->list
[i
]);
289 zf
->fname
= D
->impls
->list
[i
]->func
->name
+ (D
->impls
->list
[i
]->func
->name
[0] == '\\');
290 zf
->num_args
= D
->impls
->list
[i
]->func
->args
->count
;
291 zf
->handler
= data
->code
;
292 zf
->arg_info
= data
->arginfo
;
299 static PSI_ContextOps ops
= {
305 PSI_ContextOps
*PSI_Libffi(void)