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
,
141 struct psi_decl
*fn
);
143 static inline ffi_type
*psi_ffi_token_type(token_t t
) {
149 return &ffi_type_void
;
151 return &ffi_type_sint8
;
153 return &ffi_type_uint8
;
155 return &ffi_type_sint16
;
157 return &ffi_type_uint16
;
159 return &ffi_type_sint32
;
161 return &ffi_type_uint32
;
163 return &ffi_type_sint64
;
165 return &ffi_type_uint64
;
168 return ffi_type_sint128
;
170 return ffi_type_uint128
;
173 return &ffi_type_uchar
;
175 return &ffi_type_sint
;
177 return &ffi_type_float
;
179 return &ffi_type_double
;
180 #ifdef HAVE_LONG_DOUBLE
181 case PSI_T_LONG_DOUBLE
:
182 return &ffi_type_longdouble
;
186 return &ffi_type_pointer
;
189 static inline ffi_type
*psi_ffi_impl_type(token_t impl_type
) {
192 return &ffi_type_sint8
;
194 return &ffi_type_sint64
;
196 return &ffi_type_pointer
;
199 return &ffi_type_double
;
200 EMPTY_SWITCH_DEFAULT_CASE();
204 static void psi_ffi_type_dtor(void *type
) {
205 ffi_type
*strct
= type
;
207 if (strct
->elements
) {
210 for (ptr
= strct
->elements
; *ptr
; ++ptr
) {
213 free(strct
->elements
);
218 static size_t psi_ffi_struct_type_pad(ffi_type
**els
, size_t padding
) {
221 for (i
= 0; i
< padding
; ++i
) {
222 ffi_type
*pad
= malloc(sizeof(*pad
));
224 memcpy(pad
, &ffi_type_schar
, sizeof(*pad
));
231 struct psi_ffi_struct_element_storage
{
240 static inline void psi_ffi_struct_type_element(
241 struct psi_ffi_struct_element_storage
*s
, struct psi_decl_arg
*darg
) {
243 ffi_type
*type
, **tmp
;
246 if (darg
->layout
->pos
== s
->last_arg_pos
) {
247 /* skip bit fields */
250 s
->last_arg_pos
= darg
->layout
->pos
;
252 type
= malloc(sizeof(*type
));
253 *type
= *psi_ffi_decl_arg_type(darg
, NULL
);
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 tmp
= realloc(s
->els
, (s
->argc
+ 1) * sizeof(*s
->els
));
270 s
->els
[s
->argc
] = NULL
;
272 psi_ffi_struct_type_pad(&s
->els
[s
->nels
], padding
);
274 s
->offset
+= padding
;
276 assert(s
->offset
== darg
->layout
->pos
);
278 s
->offset
= (s
->offset
+ darg
->layout
->len
+ type
->alignment
- 1) & ~(type
->alignment
- 1);
279 s
->els
[s
->nels
++] = type
;
282 static ffi_type
**psi_ffi_struct_type_elements(struct psi_decl_struct
*strct
) {
285 struct psi_decl_arg
*darg
;
286 struct psi_ffi_struct_element_storage s
= {0};
289 s
.argc
= psi_plist_count(strct
->args
);
290 s
.els
= calloc(s
.argc
+ 1, sizeof(*s
.els
));
292 while (psi_plist_get(strct
->args
, i
++, &darg
)) {
293 psi_ffi_struct_type_element(&s
, darg
);
296 /* apply struct alignment padding */
297 s
.offset
= (s
.offset
+ s
.max_align
- 1) & ~(s
.max_align
- 1);
299 assert(s
.offset
<= strct
->size
);
300 if (s
.offset
< strct
->size
) { /* WTF? */
301 size_t padding
= strct
->size
- s
.offset
;
303 tmp
= realloc(s
.els
, (padding
+ s
.argc
+ 1) * sizeof(*s
.els
));
310 psi_ffi_struct_type_pad(&s
.els
[s
.nels
], padding
);
311 s
.els
[s
.argc
+ padding
] = NULL
;
317 static inline ffi_type
*psi_ffi_decl_type(struct psi_decl_type
*type
) {
318 struct psi_decl_type
*real
= psi_decl_type_get_real(type
);
320 if (real
!= type
&& type
->real
.def
->var
->pointer_level
) {
321 return &ffi_type_pointer
;
324 switch (real
->type
) {
326 if (!real
->real
.strct
->engine
.type
) {
327 ffi_type
*strct
= calloc(1, sizeof(ffi_type
));
329 strct
->type
= FFI_TYPE_STRUCT
;
331 strct
->elements
= psi_ffi_struct_type_elements(real
->real
.strct
);
333 real
->real
.strct
->engine
.type
= strct
;
334 real
->real
.strct
->engine
.dtor
= psi_ffi_type_dtor
;
337 return real
->real
.strct
->engine
.type
;
341 struct psi_decl_arg
*arg
;
342 psi_plist_get(real
->real
.unn
->args
, 0, &arg
);
343 return psi_ffi_decl_arg_type(arg
, NULL
);
350 return psi_ffi_token_type(real
->type
);
353 static inline ffi_type
*psi_ffi_decl_func_array_type(struct psi_decl
*fn
) {
354 struct psi_ffi_decl_info
*info
= fn
->info
;
355 struct psi_ffi_struct_element_storage s
= {0};
360 s
.argc
= fn
->func
->var
->array_size
;
361 s
.els
= calloc(s
.argc
+ 1, sizeof(*s
.els
));
363 assert(!fn
->func
->layout
);
365 l
.len
= psi_decl_arg_get_size(fn
->func
);
367 fn
->func
->layout
= &l
;
368 psi_ffi_struct_type_element(&s
, fn
->func
);
369 fn
->func
->layout
= NULL
;
371 info
->rv_array
= calloc(1, sizeof(ffi_type
));
372 info
->rv_array
->type
= FFI_TYPE_STRUCT
;
373 info
->rv_array
->size
= 0;
374 info
->rv_array
->elements
= s
.els
;
376 return info
->rv_array
;
379 static inline ffi_type
*psi_ffi_decl_arg_type(struct psi_decl_arg
*darg
,
380 struct psi_decl
*fn
) {
381 if (darg
->var
->pointer_level
) {
382 if (darg
->var
->array_size
&& fn
) {
383 /* mimic a struct resembling the array return type of fn */
384 return psi_ffi_decl_func_array_type(fn
);
386 return &ffi_type_pointer
;
388 return psi_ffi_decl_type(darg
->type
);
392 static inline ffi_abi
psi_ffi_abi(const char *convention
) {
393 if (FFI_LAST_ABI
- 2 != FFI_FIRST_ABI
) {
394 #ifdef HAVE_FFI_STDCALL
395 if (!strcasecmp(convention
, "stdcall")) {
399 #ifdef HAVE_FFI_FASTCALL
400 if (!strcasecmp(convention
, "fastcall")) {
405 return FFI_DEFAULT_ABI
;
408 static inline struct psi_ffi_decl_info
*psi_ffi_decl_init(struct psi_decl
*decl
) {
411 size_t i
, c
= psi_plist_count(decl
->args
);
412 struct psi_decl_arg
*arg
;
413 struct psi_ffi_decl_info
*info
= calloc(1, sizeof(*info
) + 2 * c
* sizeof(void *));
417 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
418 info
->params
[i
] = psi_ffi_decl_arg_type(arg
, NULL
);
420 info
->params
[c
] = NULL
;
422 rc
= ffi_prep_cif(&info
->signature
, psi_ffi_abi(decl
->abi
->convention
),
423 c
, psi_ffi_decl_arg_type(decl
->func
, decl
), info
->params
);
434 static inline void psi_ffi_decl_dtor(struct psi_decl
*decl
) {
436 struct psi_ffi_decl_info
*info
= decl
->info
;
438 if (info
->rv_array
) {
439 psi_ffi_type_dtor(info
->rv_array
);
446 static void psi_ffi_handler(ffi_cif
*sig
, void *result
, void **args
, void *data
)
448 struct psi_impl
*impl
= data
;
449 struct psi_ffi_impl_info
*info
= impl
->info
;
451 psi_context_call(info
->context
, *(zend_execute_data
**)args
[0], *(zval
**)args
[1], impl
);
454 static void psi_ffi_callback(ffi_cif
*sig
, void *result
, void **args
, void *data
)
456 struct psi_ffi_callback_info
*cb_info
= data
;
457 struct psi_call_frame_callback cb_data
;
459 assert(cb_info
->impl_info
->frame
);
461 cb_data
.cb
= cb_info
->let_exp
;
462 cb_data
.argc
= sig
->nargs
;
464 cb_data
.rval
= result
;
466 psi_call_frame_do_callback(cb_info
->impl_info
->frame
, &cb_data
);
469 static inline void psi_ffi_callback_init(struct psi_ffi_impl_info
*impl_info
,
470 struct psi_let_exp
*let_exp
) {
471 struct psi_ffi_callback_info
*cb_info
;
472 struct psi_ffi_decl_info
*decl_info
;
473 struct psi_let_callback
*cb
;
474 struct psi_let_func
*fn
= NULL
;
477 switch (let_exp
->kind
) {
478 case PSI_LET_CALLBACK
:
479 cb
= let_exp
->data
.callback
;
480 if (cb
->decl
->info
) {
481 decl_info
= cb
->decl
->info
;
483 decl_info
= psi_ffi_decl_init(cb
->decl
);
486 cb_info
= calloc(1, sizeof(*cb_info
));
487 cb_info
->impl_info
= impl_info
;
488 cb_info
->let_exp
= let_exp
;
489 rc
= psi_ffi_prep_closure(&cb_info
->closure
, &cb_info
->code
,
490 &decl_info
->signature
, psi_ffi_callback
, cb_info
);
498 assert(!cb
->decl
->sym
);
499 cb
->decl
->sym
= cb_info
->code
;
505 fn
= let_exp
->data
.func
;
509 struct psi_let_exp
*inner_let
;
511 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
512 psi_ffi_callback_init(impl_info
, inner_let
);
521 static inline void psi_ffi_callback_dtor(struct psi_let_exp
*let_exp
) {
522 struct psi_let_callback
*cb
;
523 struct psi_let_func
*fn
= NULL
;
525 switch (let_exp
->kind
) {
526 case PSI_LET_CALLBACK
:
527 cb
= let_exp
->data
.callback
;
529 psi_ffi_decl_dtor(cb
->decl
);
532 struct psi_ffi_callback_info
*info
= cb
->info
;
535 psi_ffi_closure_free(info
->closure
);
544 fn
= let_exp
->data
.func
;
549 struct psi_let_exp
*cb
;
551 while (psi_plist_get(fn
->inner
, i
++, &cb
)) {
552 psi_ffi_callback_dtor(cb
);
561 static inline struct psi_ffi_impl_info
*psi_ffi_impl_init(struct psi_impl
*impl
,
562 struct psi_context
*C
) {
563 struct psi_ffi_context
*context
= C
->context
;
564 struct psi_ffi_impl_info
*info
= calloc(1, sizeof(*info
));
565 struct psi_let_stmt
*let
;
571 rc
= psi_ffi_prep_closure(&info
->closure
, &info
->code
,
572 &context
->signature
, psi_ffi_handler
, impl
);
579 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
580 psi_ffi_callback_init(info
, let
->exp
);
583 return impl
->info
= info
;
586 static inline void psi_ffi_impl_dtor(struct psi_impl
*impl
) {
587 struct psi_ffi_impl_info
*info
= impl
->info
;
588 struct psi_let_stmt
*let
;
591 while (psi_plist_get(impl
->stmts
.let
, j
++, &let
)) {
592 psi_ffi_callback_dtor(let
->exp
);
597 psi_ffi_closure_free(info
->closure
);
604 static void psi_ffi_extvar_get(ffi_cif
*sig
, void *result
, void **args
, void *data
) {
605 struct psi_decl_extvar
*evar
= data
;
607 psi_decl_extvar_get(evar
, result
);
610 static void psi_ffi_extvar_set(ffi_cif
*sig
, void *result
, void **args
, void *data
) {
611 struct psi_decl_extvar
*evar
= data
;
613 psi_decl_extvar_set(evar
, args
[0]);
616 struct psi_ffi_extvar_info
{
620 ffi_closure
*closure
;
626 ffi_closure
*closure
;
630 static inline ffi_status
psi_ffi_extvar_init(struct psi_decl_extvar
*evar
) {
631 struct psi_ffi_extvar_info
*info
= calloc(1, sizeof(*info
));
637 psi_ffi_decl_init(evar
->getter
);
638 psi_ffi_decl_init(evar
->setter
);
640 type
= psi_ffi_decl_arg_type(evar
->arg
, evar
->getter
);
642 rc
= ffi_prep_cif(&info
->get
.signature
, FFI_DEFAULT_ABI
, 0,
647 rc
= psi_ffi_prep_closure(&info
->get
.closure
, &info
->get
.code
,
648 &info
->get
.signature
, psi_ffi_extvar_get
, evar
);
653 info
->set
.params
[0] = type
;
654 rc
= ffi_prep_cif(&info
->set
.signature
, FFI_DEFAULT_ABI
, 1,
655 &ffi_type_void
, info
->set
.params
);
659 rc
= psi_ffi_prep_closure(&info
->set
.closure
, &info
->set
.code
,
660 &info
->set
.signature
, psi_ffi_extvar_set
, evar
);
665 evar
->getter
->sym
= info
->get
.code
;
666 evar
->setter
->sym
= info
->set
.code
;
671 static inline void psi_ffi_extvar_dtor(struct psi_decl_extvar
*evar
) {
678 static inline struct psi_ffi_context
*psi_ffi_context_init(struct psi_ffi_context
*L
) {
682 L
= malloc(sizeof(*L
));
684 memset(L
, 0, sizeof(*L
));
686 L
->params
[0] = &ffi_type_pointer
;
687 L
->params
[1] = &ffi_type_pointer
;
688 rc
= ffi_prep_cif(&L
->signature
, FFI_DEFAULT_ABI
, 2, &ffi_type_void
, L
->params
);
689 assert(rc
== FFI_OK
);
694 static inline void psi_ffi_context_free(struct psi_ffi_context
**L
) {
701 static void psi_ffi_init(struct psi_context
*C
)
703 C
->context
= psi_ffi_context_init(NULL
);
706 static void psi_ffi_dtor(struct psi_context
*C
)
710 struct psi_decl
*decl
;
712 while (psi_plist_get(C
->decls
, i
++, &decl
)) {
713 psi_ffi_decl_dtor(decl
);
719 struct psi_decl_extvar
*evar
;
721 while (psi_plist_get(C
->vars
, i
++, &evar
)) {
722 psi_ffi_extvar_dtor(evar
);
727 struct psi_impl
*impl
;
729 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
730 psi_ffi_impl_dtor(impl
);
733 psi_ffi_context_free((void *) &C
->context
);
737 static zend_function_entry
*psi_ffi_compile(struct psi_context
*C
)
739 size_t i
= 0, d
= 0, v
= 0, nf
= 0;
740 struct psi_impl
*impl
;
741 struct psi_decl
*decl
;
742 struct psi_decl_extvar
*evar
;
743 zend_function_entry
*zfe
= NULL
;
745 while (psi_plist_get(C
->vars
, v
++, &evar
)) {
746 if (FFI_OK
== psi_ffi_extvar_init(evar
)) {
752 zfe
= calloc(psi_plist_count(C
->impls
) + 1, sizeof(*zfe
));
754 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
755 zend_function_entry
*zf
= &zfe
[nf
];
760 if (!psi_ffi_decl_init(impl
->decl
)) {
763 if (!psi_ffi_impl_init(impl
, C
)) {
767 zf
->fname
= impl
->func
->name
+ (impl
->func
->name
[0] == '\\');
768 zf
->handler
= ((struct psi_ffi_impl_info
*) impl
->info
)->code
;
769 zf
->num_args
= psi_plist_count(impl
->func
->args
);
770 zf
->arg_info
= psi_internal_arginfo(impl
);
775 while (psi_plist_get(C
->decls
, d
++, &decl
)) {
780 psi_ffi_decl_init(decl
);
786 static inline void psi_ffi_call_ex(struct psi_call_frame
*frame
) {
787 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
788 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
789 struct psi_ffi_decl_info
*decl_info
= decl
->info
;
790 struct psi_ffi_impl_info
*impl_info
;
791 struct psi_call_frame
*prev
;
794 impl_info
= impl
->info
;
795 prev
= impl_info
->frame
;
796 impl_info
->frame
= frame
;
798 ffi_call(&decl_info
->signature
, FFI_FN(decl
->sym
),
799 psi_call_frame_get_rpointer(frame
),
800 psi_call_frame_get_arg_pointers(frame
));
802 impl_info
->frame
= prev
;
806 static inline void psi_ffi_call_va(struct psi_call_frame
*frame
) {
808 struct psi_call_frame
*prev
;
809 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
810 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
811 struct psi_ffi_decl_info
*decl_info
= decl
->info
;
812 struct psi_ffi_impl_info
*impl_info
;
813 size_t i
, va_count
, argc
;
814 ffi_type
**param_types
;
816 argc
= psi_plist_count(decl
->args
);
817 va_count
= psi_call_frame_num_var_args(frame
);
818 param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(ffi_type
*));
819 memcpy(param_types
, decl_info
->params
, argc
* sizeof(ffi_type
*));
820 for (i
= 0; i
< va_count
; ++i
) {
821 struct psi_call_frame_argument
*frame_arg
;
823 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
824 param_types
[argc
+ i
] = psi_ffi_impl_type(frame_arg
->va_type
);
827 psi_ffi_prep_va(&decl_info
->signature
, &signature
, argc
, va_count
, param_types
);
830 impl_info
= impl
->info
;
831 prev
= impl_info
->frame
;
832 impl_info
->frame
= frame
;
834 ffi_call(&signature
, FFI_FN(decl
->sym
),
835 psi_call_frame_get_rpointer(frame
),
836 psi_call_frame_get_arg_pointers(frame
));
838 impl_info
->frame
= prev
;
844 static void psi_ffi_call(struct psi_call_frame
*frame
) {
845 if (psi_call_frame_num_var_args(frame
)) {
846 psi_ffi_call_va(frame
);
848 psi_ffi_call_ex(frame
);
852 static void *psi_ffi_query(struct psi_context
*C
, enum psi_context_query q
, void *arg
) {
854 case PSI_CONTEXT_QUERY_SELF
:
856 case PSI_CONTEXT_QUERY_TYPE
:
857 return psi_ffi_impl_type(*(token_t
*) arg
);
862 static ZEND_RESULT_CODE
psi_ffi_load()
865 ffi_type
*i128
, *u128
;
867 i128
= calloc(1, 3*sizeof(ffi_type
));
868 i128
->type
= FFI_TYPE_STRUCT
;
870 i128
->elements
= (ffi_type
**) (i128
+ 1);
871 i128
->elements
[0] = &ffi_type_sint64
;
872 i128
->elements
[1] = &ffi_type_sint64
;
874 ffi_type_sint128
= i128
;
876 u128
= calloc(1, 3*sizeof(ffi_type
));
877 u128
->type
= FFI_TYPE_STRUCT
;
879 u128
->elements
= (ffi_type
**) (u128
+ 1);
880 u128
->elements
[0] = &ffi_type_uint64
;
881 u128
->elements
[1] = &ffi_type_uint64
;
883 ffi_type_uint128
= u128
;
888 static void psi_ffi_free()
891 free(ffi_type_sint128
);
892 free(ffi_type_uint128
);
896 static struct psi_context_ops ops
= {
906 struct psi_context_ops
*psi_libffi_ops(void)
911 #endif /* HAVE_LIBFFI */