7 #ifndef PSI_HAVE_FFI_CLOSURE_ALLOC
12 static void handler(ffi_cif
*signature
, void *_result
, void **_args
, void *_data
);
14 static inline ffi_abi
psi_ffi_abi(const char *convention
) {
15 return FFI_DEFAULT_ABI
;
17 static inline ffi_type
*psi_ffi_type(token_t t
) {
23 return &ffi_type_void
;
25 return &ffi_type_sint8
;
27 return &ffi_type_uint8
;
29 return &ffi_type_sint16
;
31 return &ffi_type_uint16
;
33 return &ffi_type_sint32
;
35 return &ffi_type_uint32
;
37 return &ffi_type_sint64
;
39 return &ffi_type_uint64
;
41 return &ffi_type_uchar
;
43 return &ffi_type_schar
;
45 return &ffi_type_sshort
;
47 return &ffi_type_sint
;
49 return &ffi_type_slong
;
51 return &ffi_type_float
;
53 return &ffi_type_double
;
56 static inline ffi_type
*psi_ffi_decl_type(decl_type
*type
) {
57 return psi_ffi_type(real_decl_type(type
)->type
);
59 static inline ffi_type
*psi_ffi_decl_arg_type(decl_arg
*darg
) {
60 if (darg
->var
->pointer_level
) {
61 return &ffi_type_pointer
;
63 return psi_ffi_decl_type(darg
->type
);
67 typedef struct PSI_LibffiContext
{
71 struct PSI_LibffiData
**list
;
76 typedef struct PSI_LibffiData
{
77 PSI_LibffiContext
*context
;
79 zend_internal_arg_info
*arginfo
;
86 static inline PSI_LibffiData
*PSI_LibffiDataAlloc(PSI_LibffiContext
*context
, impl
*impl
) {
88 size_t i
, c
= impl
->decl
->args
->count
;
89 PSI_LibffiData
*data
= malloc(sizeof(*data
) + c
* sizeof(ffi_type
*));
91 data
->context
= context
;
93 data
->arginfo
= psi_internal_arginfo(impl
);
94 for (i
= 0; i
< c
; ++i
) {
95 data
->params
[i
] = psi_ffi_decl_arg_type(impl
->decl
->args
->args
[i
]);
97 data
->params
[c
] = NULL
;
101 psi_ffi_abi(data
->impl
->decl
->abi
->convention
),
103 psi_ffi_decl_arg_type(data
->impl
->decl
->func
),
105 ZEND_ASSERT(FFI_OK
== rc
);
107 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
108 data
->closure
= ffi_closure_alloc(sizeof(ffi_closure
), &data
->code
);
109 rc
= ffi_prep_closure_loc(
115 ZEND_ASSERT(FFI_OK
== rc
);
118 data
->closure
= malloc(sizeof(ffi_closure
) + i
);
119 data
->code
= (void *) (((intptr_t) data
->closure
+ i
- 1) & ~((intptr_t) i
- 1));
120 rc
= mprotect(data
->code
, sizeof(ffi_closure
), PROT_EXEC
|PROT_WRITE
);
121 ZEND_ASSERT(rc
== 0);
122 rc
= ffi_prep_closure(data
->code
, &context
->signature
, handler
, data
);
123 ZEND_ASSERT(FFI_OK
== rc
);
126 context
->data
.list
= realloc(context
->data
.list
, ++context
->data
.count
* sizeof(*context
->data
.list
));
127 context
->data
.list
[context
->data
.count
-1] = data
;
132 static inline void PSI_LibffiDataFree(PSI_LibffiData
*data
) {
134 #ifdef PSI_HAVE_FFI_CLOSURE_FREE
135 ffi_closure_free(data
->closure
);
142 static inline PSI_LibffiContext
*PSI_LibffiContextInit(PSI_LibffiContext
*L
) {
146 L
= malloc(sizeof(*L
));
148 memset(L
, 0, sizeof(*L
));
150 L
->params
[0] = &ffi_type_pointer
;
151 L
->params
[1] = &ffi_type_pointer
;
152 rc
= ffi_prep_cif(&L
->signature
, FFI_DEFAULT_ABI
, 2, &ffi_type_void
, L
->params
);
153 ZEND_ASSERT(rc
== FFI_OK
);
158 static inline void PSI_LibffiContextDtor(PSI_LibffiContext
*L
) {
161 for (i
= 0; i
< L
->data
.count
; ++i
) {
162 PSI_LibffiDataFree(L
->data
.list
[i
]);
169 static inline void PSI_LibffiContextFree(PSI_LibffiContext
**L
) {
171 PSI_LibffiContextDtor(*L
);
177 static void handler(ffi_cif
*_sig
, void *_result
, void **_args
, void *_data
)
179 PSI_LibffiData
*data
= _data
;
181 void **arg_ptr
= NULL
, **arg_prm
= NULL
;
184 if (SUCCESS
!= psi_parse_args(*(zend_execute_data
**)_args
[0], data
->impl
)) {
188 if (data
->impl
->decl
->args
->count
) {
189 arg_ptr
= malloc(data
->impl
->decl
->args
->count
* sizeof(*arg_ptr
));
190 arg_prm
= malloc(data
->impl
->decl
->args
->count
* sizeof(*arg_prm
));
192 for (i
= 0; i
< data
->impl
->decl
->args
->count
; ++i
) {
193 decl_arg
*darg
= data
->impl
->decl
->args
->args
[i
];
195 arg_ptr
[i
] = psi_do_let(darg
);
196 arg_prm
[i
] = darg
->let
->val
->is_reference
? &arg_ptr
[i
] : arg_ptr
[i
];
198 darg
->let
->ptr
= arg_ptr
[i
];
202 ffi_call(&data
->signature
, FFI_FN(data
->impl
->decl
->dlptr
), &ret_val
, arg_prm
);
204 psi_do_return(data
->impl
, &ret_val
, *(zval
**)_args
[1]);
206 for (i
= 0; i
< data
->impl
->stmts
->set
.count
; ++i
) {
207 set_stmt
*set
= data
->impl
->stmts
->set
.list
[i
];
209 psi_do_set(set
->arg
->_zv
, set
->val
->func
, set
->val
->vars
);
212 for (i
= 0; i
< data
->impl
->stmts
->fre
.count
; ++i
) {
213 free_stmt
*fre
= data
->impl
->stmts
->fre
.list
[i
];
218 psi_do_clean(data
->impl
);
228 static void init(PSI_Context
*C
)
230 C
->context
= PSI_LibffiContextInit(NULL
);
233 static void dtor(PSI_Context
*C
)
235 PSI_LibffiContextFree((void *) &C
->context
);
238 static zend_function_entry
*compile(PSI_Context
*C
, PSI_Data
*D
)
241 zend_function_entry
*zfe
= calloc(D
->impls
->count
+ 1, sizeof(*zfe
));
242 PSI_LibffiContext
*ctx
= C
->context
;
244 for (i
= 0; i
< D
->impls
->count
; ++i
) {
245 zend_function_entry
*zf
= &zfe
[j
];
246 PSI_LibffiData
*data
;
248 if (!D
->impls
->list
[i
]->decl
) {
252 data
= PSI_LibffiDataAlloc(ctx
, D
->impls
->list
[i
]);
253 zf
->fname
= D
->impls
->list
[i
]->func
->name
+ (D
->impls
->list
[i
]->func
->name
[0] == '\\');
254 zf
->num_args
= D
->impls
->list
[i
]->func
->args
->count
;
255 zf
->handler
= data
->code
;
256 zf
->arg_info
= data
->arginfo
;
263 static PSI_ContextOps ops
= {
269 PSI_ContextOps
*PSI_Libffi(void)