1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
26 #include "php_psi_stdinc.h"
34 #undef PACKAGE_BUGREPORT
37 #undef PACKAGE_TARNAME
38 #undef PACKAGE_VERSION
42 #ifndef PSI_HAVE_FFI_CLOSURE_ALLOC
47 # include <sys/mman.h>
48 # ifndef MAP_ANONYMOUS
49 # define MAP_ANONYMOUS MAP_ANON
54 struct psi_ffi_context
{
59 struct psi_ffi_impl_info
{
60 struct psi_context
*context
;
61 struct psi_call_frame
*frame
;
67 struct psi_ffi_callback_info
{
68 struct psi_ffi_impl_info
*impl_info
;
69 struct psi_let_exp
*let_exp
;
75 struct psi_ffi_decl_info
{
81 static void *psi_ffi_closure_alloc(size_t s
, void **code
)
83 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
84 return ffi_closure_alloc(s
, code
);
86 *code
= mmap(NULL
, s
, PROT_EXEC
|PROT_WRITE
|PROT_READ
,
87 MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
88 if (MAP_FAILED
== *code
) {
93 # error "Neither ffi_closure_alloc() nor mmap() available"
97 static ffi_status
psi_ffi_prep_closure(ffi_closure
**closure
, void **code
, ffi_cif
*sig
, void (*handler
)(ffi_cif
*,void*,void**,void*), void *data
) {
98 *closure
= psi_ffi_closure_alloc(sizeof(ffi_closure
), code
);
99 assert(*closure
!= NULL
);
101 #if PSI_HAVE_FFI_PREP_CLOSURE_LOC
102 return ffi_prep_closure_loc(*closure
, sig
, handler
, data
, *code
);
104 #elif PSI_HAVE_FFI_PREP_CLOSURE
105 return ffi_prep_closure(*code
, sig
, handler
, data
);
107 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() is available"
111 static void psi_ffi_closure_free(void *c
)
113 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
116 munmap(c
, sizeof(ffi_closure
));
120 static void psi_ffi_prep_va(ffi_cif
*base
, ffi_cif
*signature
, size_t argc
, size_t va_count
,
121 ffi_type
**param_types
) {
124 #ifdef PSI_HAVE_FFI_PREP_CIF_VAR
125 rc
= ffi_prep_cif_var(signature
, base
->abi
, argc
, argc
+ va_count
,
126 base
->rtype
, param_types
);
128 /* FIXME: test in config.m4; assume we can just call anyway */
129 rc
= ffi_prep_cif(signature
, base
->abi
, argc
+ va_count
, base
->rtype
, param_types
);
132 assert(FFI_OK
== rc
);
136 static ffi_type
*ffi_type_sint128
;
137 static ffi_type
*ffi_type_uint128
;
140 static inline ffi_type
*psi_ffi_decl_arg_type(struct psi_decl_arg
*darg
);
142 static inline ffi_type
*psi_ffi_token_type(token_t t
) {
148 return &ffi_type_void
;
150 return &ffi_type_sint8
;
152 return &ffi_type_uint8
;
154 return &ffi_type_sint16
;
156 return &ffi_type_uint16
;
158 return &ffi_type_sint32
;
160 return &ffi_type_uint32
;
162 return &ffi_type_sint64
;
164 return &ffi_type_uint64
;
167 return ffi_type_sint128
;
169 return ffi_type_uint128
;
172 return &ffi_type_uchar
;
174 return &ffi_type_sint
;
176 return &ffi_type_float
;
178 return &ffi_type_double
;
179 #ifdef HAVE_LONG_DOUBLE
180 case PSI_T_LONG_DOUBLE
:
181 return &ffi_type_longdouble
;
185 return &ffi_type_pointer
;
188 static inline ffi_type
*psi_ffi_impl_type(token_t impl_type
) {
191 return &ffi_type_sint8
;
193 return &ffi_type_sint64
;
195 return &ffi_type_pointer
;
198 return &ffi_type_double
;
199 EMPTY_SWITCH_DEFAULT_CASE();
203 static void psi_ffi_type_dtor(void *type
) {
204 ffi_type
*strct
= type
;
206 if (strct
->elements
) {
209 for (ptr
= strct
->elements
; *ptr
; ++ptr
) {
212 free(strct
->elements
);
217 static size_t psi_ffi_struct_type_pad(ffi_type
**els
, size_t padding
) {
220 for (i
= 0; i
< padding
; ++i
) {
221 ffi_type
*pad
= pemalloc(sizeof(*pad
), 1);
223 memcpy(pad
, &ffi_type_schar
, sizeof(*pad
));
230 struct psi_ffi_struct_element_storage
{
239 static inline void psi_ffi_struct_type_element(
240 struct psi_ffi_struct_element_storage
*s
, struct psi_decl_arg
*darg
,
241 ffi_type
*darg_type
) {
246 if (darg
->layout
->pos
== s
->last_arg_pos
) {
247 /* skip bit fields */
250 s
->last_arg_pos
= darg
->layout
->pos
;
252 type
= pemalloc(sizeof(*type
), 1);
255 if (type
->alignment
> s
->max_align
) {
256 s
->max_align
= type
->alignment
;
259 assert(type
->size
<= darg
->layout
->len
);
260 if ((padding
= psi_offset_padding(darg
->layout
->pos
- s
->offset
, type
->alignment
))) {
261 if (s
->nels
+ padding
+ 1 > s
->argc
) {
263 s
->els
= safe_perealloc(s
->els
, (s
->argc
+ 1), sizeof(*s
->els
), 0, 1);
264 s
->els
[s
->argc
] = NULL
;
266 psi_ffi_struct_type_pad(&s
->els
[s
->nels
], padding
);
268 s
->offset
+= padding
;
270 assert(s
->offset
== darg
->layout
->pos
);
272 s
->offset
= (s
->offset
+ darg
->layout
->len
+ type
->alignment
- 1) & ~(type
->alignment
- 1);
273 s
->els
[s
->nels
++] = type
;
276 static ffi_type
**psi_ffi_struct_type_elements(struct psi_decl_struct
*strct
) {
278 struct psi_decl_arg
*darg
;
279 struct psi_ffi_struct_element_storage s
= {0};
282 s
.argc
= psi_plist_count(strct
->args
);
283 s
.els
= pecalloc(s
.argc
+ 1, sizeof(*s
.els
), 1);
285 while (psi_plist_get(strct
->args
, i
++, &darg
)) {
286 psi_ffi_struct_type_element(&s
, darg
, psi_ffi_decl_arg_type(darg
));
289 /* apply struct alignment padding */
290 s
.offset
= (s
.offset
+ s
.max_align
- 1) & ~(s
.max_align
- 1);
292 assert(s
.offset
<= strct
->size
);
293 if (s
.offset
< strct
->size
) { /* WTF? */
294 size_t padding
= strct
->size
- s
.offset
;
296 s
.els
= safe_perealloc(s
.els
, (padding
+ s
.argc
+ 1), sizeof(*s
.els
), 0, 1);
297 psi_ffi_struct_type_pad(&s
.els
[s
.nels
], padding
);
298 s
.els
[s
.argc
+ padding
] = NULL
;
304 static inline ffi_type
*psi_ffi_decl_type(struct psi_decl_type
*type
) {
305 struct psi_decl_type
*real
= psi_decl_type_get_real(type
);
307 if (real
!= type
&& type
->real
.def
->var
->pointer_level
) {
308 return &ffi_type_pointer
;
311 switch (real
->type
) {
313 if (!real
->real
.strct
->engine
.type
) {
314 ffi_type
*strct
= pecalloc(1, sizeof(ffi_type
), 1);
316 strct
->type
= FFI_TYPE_STRUCT
;
318 strct
->elements
= psi_ffi_struct_type_elements(real
->real
.strct
);
320 real
->real
.strct
->engine
.type
= strct
;
321 real
->real
.strct
->engine
.dtor
= psi_ffi_type_dtor
;
324 return real
->real
.strct
->engine
.type
;
328 struct psi_decl_arg
*arg
;
329 psi_plist_get(real
->real
.unn
->args
, 0, &arg
);
330 return psi_ffi_decl_arg_type(arg
);
337 return psi_ffi_token_type(real
->type
);
340 static inline ffi_type
*psi_ffi_decl_func_array_type(struct psi_decl
*fn
) {
341 struct psi_ffi_decl_info
*info
= fn
->info
;
342 struct psi_ffi_struct_element_storage s
= {0};
347 if (info
->rv_array
) {
348 return info
->rv_array
;
352 s
.argc
= fn
->func
->var
->array_size
;
353 s
.els
= pecalloc(s
.argc
+ 1, sizeof(*s
.els
), 1);
355 info
->rv_array
= pecalloc(1, sizeof(ffi_type
), 1);
356 info
->rv_array
->type
= FFI_TYPE_STRUCT
;
357 info
->rv_array
->size
= 0;
358 info
->rv_array
->elements
= s
.els
;
361 if (fn
->func
->var
->pointer_level
> 1) {
362 l
.len
= SIZEOF_VOID_P
;
363 type
= &ffi_type_pointer
;
365 l
.len
= psi_decl_type_get_size(fn
->func
->type
, NULL
);
366 type
= psi_ffi_decl_type(fn
->func
->type
);
369 assert(!fn
->func
->layout
);
370 fn
->func
->layout
= &l
;
371 for (i
= 0; i
< fn
->func
->var
->array_size
; ++i
) {
372 psi_ffi_struct_type_element(&s
, fn
->func
, type
);
373 info
->rv_array
->elements
= s
.els
;
376 fn
->func
->layout
= NULL
;
378 return info
->rv_array
;
381 static inline ffi_type
*psi_ffi_decl_arg_type(struct psi_decl_arg
*darg
) {
382 if (darg
->var
->pointer_level
) {
383 return &ffi_type_pointer
;
385 return psi_ffi_decl_type(darg
->type
);
389 static inline ffi_type
*psi_ffi_decl_func_type(struct psi_decl
*fn
) {
390 struct psi_decl_arg
*darg
= fn
->func
;
392 if (darg
->var
->pointer_level
) {
393 if (darg
->var
->array_size
) {
394 /* mimic a struct resembling the array return type of fn */
395 return psi_ffi_decl_func_array_type(fn
);
397 return &ffi_type_pointer
;
399 return psi_ffi_decl_type(darg
->type
);
403 static inline ffi_abi
psi_ffi_abi(zend_string
*convention
) {
404 if (FFI_LAST_ABI
- 2 != FFI_FIRST_ABI
) {
405 #ifdef HAVE_FFI_STDCALL
406 if (zend_string_equals_literal(convention
, "stdcall")) {
410 #ifdef HAVE_FFI_FASTCALL
411 if (zend_string_equals_literal(convention
, "fastcall")) {
416 return FFI_DEFAULT_ABI
;
419 static inline struct psi_ffi_decl_info
*psi_ffi_decl_init(struct psi_decl
*decl
) {
422 size_t i
, c
= psi_plist_count(decl
->args
);
423 struct psi_decl_arg
*arg
;
424 struct psi_ffi_decl_info
*info
= pecalloc(1, sizeof(*info
) + 2 * c
* sizeof(void *), 1);
428 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
429 info
->params
[i
] = psi_ffi_decl_arg_type(arg
);
431 info
->params
[c
] = NULL
;
433 rc
= ffi_prep_cif(&info
->signature
, psi_ffi_abi(decl
->abi
->convention
),
434 c
, psi_ffi_decl_func_type(decl
), info
->params
);
445 static inline void psi_ffi_decl_dtor(struct psi_decl
*decl
) {
447 struct psi_ffi_decl_info
*info
= decl
->info
;
449 if (info
->rv_array
) {
450 psi_ffi_type_dtor(info
->rv_array
);
457 static void psi_ffi_handler(ffi_cif
*sig
, void *result
, void **args
, void *data
)
459 struct psi_impl
*impl
= data
;
460 struct psi_ffi_impl_info
*info
= impl
->info
;
462 psi_context_call(info
->context
, *(zend_execute_data
**)args
[0], *(zval
**)args
[1], impl
);
465 static void psi_ffi_callback(ffi_cif
*sig
, void *result
, void **args
, void *data
)
467 struct psi_ffi_callback_info
*cb_info
= data
;
468 struct psi_call_frame_callback cb_data
;
470 assert(cb_info
->impl_info
->frame
);
472 cb_data
.cb
= cb_info
->let_exp
;
473 cb_data
.argc
= sig
->nargs
;
475 cb_data
.rval
= result
;
477 psi_call_frame_do_callback(cb_info
->impl_info
->frame
, &cb_data
);
480 static inline void psi_ffi_callback_init(struct psi_ffi_impl_info
*impl_info
,
481 struct psi_let_exp
*let_exp
) {
482 struct psi_ffi_callback_info
*cb_info
;
483 struct psi_ffi_decl_info
*decl_info
;
484 struct psi_let_callback
*cb
;
485 struct psi_let_func
*fn
= NULL
;
488 switch (let_exp
->kind
) {
489 case PSI_LET_CALLBACK
:
490 cb
= let_exp
->data
.callback
;
491 if (cb
->decl
->info
) {
492 decl_info
= cb
->decl
->info
;
494 decl_info
= psi_ffi_decl_init(cb
->decl
);
497 cb_info
= pecalloc(1, sizeof(*cb_info
), 1);
498 cb_info
->impl_info
= impl_info
;
499 cb_info
->let_exp
= let_exp
;
500 rc
= psi_ffi_prep_closure(&cb_info
->closure
, &cb_info
->code
,
501 &decl_info
->signature
, psi_ffi_callback
, cb_info
);
509 assert(!cb
->decl
->sym
);
510 cb
->decl
->sym
= cb_info
->code
;
516 fn
= let_exp
->data
.func
;
520 struct psi_let_exp
*inner_let
;
522 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
523 psi_ffi_callback_init(impl_info
, inner_let
);
532 static inline void psi_ffi_callback_dtor(struct psi_let_exp
*let_exp
) {
533 struct psi_let_callback
*cb
;
534 struct psi_let_func
*fn
= NULL
;
536 switch (let_exp
->kind
) {
537 case PSI_LET_CALLBACK
:
538 cb
= let_exp
->data
.callback
;
540 psi_ffi_decl_dtor(cb
->decl
);
543 struct psi_ffi_callback_info
*info
= cb
->info
;
546 psi_ffi_closure_free(info
->closure
);
555 fn
= let_exp
->data
.func
;
560 struct psi_let_exp
*cb
;
562 while (psi_plist_get(fn
->inner
, i
++, &cb
)) {
563 psi_ffi_callback_dtor(cb
);
572 static inline struct psi_ffi_impl_info
*psi_ffi_impl_init(struct psi_impl
*impl
,
573 struct psi_context
*C
) {
574 struct psi_ffi_context
*context
= C
->context
;
575 struct psi_ffi_impl_info
*info
= pecalloc(1, sizeof(*info
), 1);
576 struct psi_let_stmt
*let
;
582 rc
= psi_ffi_prep_closure(&info
->closure
, &info
->code
,
583 &context
->signature
, psi_ffi_handler
, impl
);
590 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
591 psi_ffi_callback_init(info
, let
->exp
);
594 return impl
->info
= info
;
597 static inline void psi_ffi_impl_dtor(struct psi_impl
*impl
) {
598 struct psi_ffi_impl_info
*info
= impl
->info
;
599 struct psi_let_stmt
*let
;
602 while (psi_plist_get(impl
->stmts
.let
, j
++, &let
)) {
603 psi_ffi_callback_dtor(let
->exp
);
608 psi_ffi_closure_free(info
->closure
);
615 static void psi_ffi_extvar_get(ffi_cif
*sig
, void *result
, void **args
, void *data
) {
616 struct psi_decl_extvar
*evar
= data
;
618 psi_decl_extvar_get(evar
, result
);
621 static void psi_ffi_extvar_set(ffi_cif
*sig
, void *result
, void **args
, void *data
) {
622 struct psi_decl_extvar
*evar
= data
;
624 psi_decl_extvar_set(evar
, args
[0]);
627 struct psi_ffi_extvar_info
{
631 ffi_closure
*closure
;
637 ffi_closure
*closure
;
641 static inline ffi_status
psi_ffi_extvar_init(struct psi_decl_extvar
*evar
) {
642 struct psi_ffi_extvar_info
*info
= pecalloc(1, sizeof(*info
), 1);
647 psi_ffi_decl_init(evar
->getter
);
648 psi_ffi_decl_init(evar
->setter
);
650 rc
= ffi_prep_cif(&info
->get
.signature
, FFI_DEFAULT_ABI
, 0,
651 psi_ffi_decl_func_type(evar
->getter
), NULL
);
655 rc
= psi_ffi_prep_closure(&info
->get
.closure
, &info
->get
.code
,
656 &info
->get
.signature
, psi_ffi_extvar_get
, evar
);
661 info
->set
.params
[0] = psi_ffi_decl_arg_type(evar
->arg
);
662 rc
= ffi_prep_cif(&info
->set
.signature
, FFI_DEFAULT_ABI
, 1,
663 &ffi_type_void
, info
->set
.params
);
667 rc
= psi_ffi_prep_closure(&info
->set
.closure
, &info
->set
.code
,
668 &info
->set
.signature
, psi_ffi_extvar_set
, evar
);
673 evar
->getter
->sym
= info
->get
.code
;
674 evar
->setter
->sym
= info
->set
.code
;
679 static inline void psi_ffi_extvar_dtor(struct psi_decl_extvar
*evar
) {
686 static inline struct psi_ffi_context
*psi_ffi_context_init(struct psi_ffi_context
*L
) {
690 L
= pemalloc(sizeof(*L
), 1);
692 memset(L
, 0, sizeof(*L
));
694 L
->params
[0] = &ffi_type_pointer
;
695 L
->params
[1] = &ffi_type_pointer
;
696 rc
= ffi_prep_cif(&L
->signature
, FFI_DEFAULT_ABI
, 2, &ffi_type_void
, L
->params
);
697 assert(rc
== FFI_OK
);
702 static inline void psi_ffi_context_free(struct psi_ffi_context
**L
) {
709 static void psi_ffi_init(struct psi_context
*C
)
711 C
->context
= psi_ffi_context_init(NULL
);
714 static void psi_ffi_dtor(struct psi_context
*C
)
718 struct psi_decl
*decl
;
720 while (psi_plist_get(C
->decls
, i
++, &decl
)) {
721 psi_ffi_decl_dtor(decl
);
727 struct psi_decl_extvar
*evar
;
729 while (psi_plist_get(C
->vars
, i
++, &evar
)) {
730 psi_ffi_extvar_dtor(evar
);
735 struct psi_impl
*impl
;
737 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
738 psi_ffi_impl_dtor(impl
);
741 psi_ffi_context_free((void *) &C
->context
);
745 static zend_function_entry
*psi_ffi_compile(struct psi_context
*C
)
747 size_t i
= 0, d
= 0, v
= 0, nf
= 0;
748 struct psi_impl
*impl
;
749 struct psi_decl
*decl
;
750 struct psi_decl_extvar
*evar
;
751 zend_function_entry
*zfe
= NULL
;
753 while (psi_plist_get(C
->vars
, v
++, &evar
)) {
754 if (FFI_OK
== psi_ffi_extvar_init(evar
)) {
760 zfe
= pecalloc(psi_plist_count(C
->impls
) + 1, sizeof(*zfe
), 1);
762 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
763 zend_function_entry
*zf
= &zfe
[nf
];
768 if (!psi_ffi_decl_init(impl
->decl
)) {
771 if (!psi_ffi_impl_init(impl
, C
)) {
775 zf
->fname
= impl
->func
->name
->val
+ (impl
->func
->name
->val
[0] == '\\');
776 zf
->handler
= ((struct psi_ffi_impl_info
*) impl
->info
)->code
;
777 zf
->num_args
= psi_plist_count(impl
->func
->args
);
778 zf
->arg_info
= psi_internal_arginfo(impl
);
783 while (psi_plist_get(C
->decls
, d
++, &decl
)) {
788 psi_ffi_decl_init(decl
);
794 static inline void psi_ffi_call_ex(struct psi_call_frame
*frame
) {
795 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
796 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
797 struct psi_ffi_decl_info
*decl_info
= decl
->info
;
798 struct psi_ffi_impl_info
*impl_info
;
799 struct psi_call_frame
*prev
;
802 impl_info
= impl
->info
;
803 prev
= impl_info
->frame
;
804 impl_info
->frame
= frame
;
806 ffi_call(&decl_info
->signature
, FFI_FN(decl
->sym
),
807 psi_call_frame_get_rpointer(frame
),
808 psi_call_frame_get_arg_pointers(frame
));
810 impl_info
->frame
= prev
;
814 static inline void psi_ffi_call_va(struct psi_call_frame
*frame
) {
816 struct psi_call_frame
*prev
;
817 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
818 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
819 struct psi_ffi_decl_info
*decl_info
= decl
->info
;
820 struct psi_ffi_impl_info
*impl_info
;
821 size_t i
, va_count
, argc
;
822 ffi_type
**param_types
;
824 argc
= psi_plist_count(decl
->args
);
825 va_count
= psi_call_frame_num_var_args(frame
);
826 param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(ffi_type
*));
827 memcpy(param_types
, decl_info
->params
, argc
* sizeof(ffi_type
*));
828 for (i
= 0; i
< va_count
; ++i
) {
829 struct psi_call_frame_argument
*frame_arg
;
831 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
832 param_types
[argc
+ i
] = psi_ffi_impl_type(frame_arg
->va_type
);
835 psi_ffi_prep_va(&decl_info
->signature
, &signature
, argc
, va_count
, param_types
);
838 impl_info
= impl
->info
;
839 prev
= impl_info
->frame
;
840 impl_info
->frame
= frame
;
842 ffi_call(&signature
, FFI_FN(decl
->sym
),
843 psi_call_frame_get_rpointer(frame
),
844 psi_call_frame_get_arg_pointers(frame
));
846 impl_info
->frame
= prev
;
852 static void psi_ffi_call(struct psi_call_frame
*frame
) {
853 if (psi_call_frame_num_var_args(frame
)) {
854 psi_ffi_call_va(frame
);
856 psi_ffi_call_ex(frame
);
860 static void *psi_ffi_query(struct psi_context
*C
, enum psi_context_query q
, void *arg
) {
862 case PSI_CONTEXT_QUERY_SELF
:
864 case PSI_CONTEXT_QUERY_TYPE
:
865 return psi_ffi_impl_type(*(token_t
*) arg
);
870 static ZEND_RESULT_CODE
psi_ffi_load()
873 ffi_type
*i128
, *u128
;
875 i128
= pecalloc(1, 3*sizeof(ffi_type
), 1);
876 i128
->type
= FFI_TYPE_STRUCT
;
878 i128
->elements
= (ffi_type
**) (i128
+ 1);
879 i128
->elements
[0] = &ffi_type_sint64
;
880 i128
->elements
[1] = &ffi_type_sint64
;
882 ffi_type_sint128
= i128
;
884 u128
= pecalloc(1, 3*sizeof(ffi_type
), 1);
885 u128
->type
= FFI_TYPE_STRUCT
;
887 u128
->elements
= (ffi_type
**) (u128
+ 1);
888 u128
->elements
[0] = &ffi_type_uint64
;
889 u128
->elements
[1] = &ffi_type_uint64
;
891 ffi_type_uint128
= u128
;
896 static void psi_ffi_free()
899 free(ffi_type_sint128
);
900 free(ffi_type_uint128
);
904 static struct psi_context_ops ops
= {
914 struct psi_context_ops
*psi_libffi_ops(void)
919 #endif /* HAVE_LIBFFI */