validate: fix type stack and leaks
[m6w6/ext-psi] / src / libffi.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
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.
13
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 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27 #include "context.h"
28 #include "call.h"
29 #include "php.h"
30
31 #ifdef HAVE_LIBFFI
32
33 #undef PACKAGE
34 #undef PACKAGE_BUGREPORT
35 #undef PACKAGE_NAME
36 #undef PACKAGE_STRING
37 #undef PACKAGE_TARNAME
38 #undef PACKAGE_VERSION
39
40 #include <ffi.h>
41
42 #ifndef PSI_HAVE_FFI_CLOSURE_ALLOC
43 # if HAVE_UNISTD_H
44 # include <unistd.h>
45 # endif
46 # if HAVE_SYS_MMAN_H
47 # include <sys/mman.h>
48 # ifndef MAP_ANONYMOUS
49 # define MAP_ANONYMOUS MAP_ANON
50 # endif
51 # endif
52 #endif
53
54 static void *psi_ffi_closure_alloc(size_t s, void **code)
55 {
56 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
57 return ffi_closure_alloc(s, code);
58 #elif HAVE_MMAP
59 *code = mmap(NULL, s, PROT_EXEC|PROT_WRITE|PROT_READ,
60 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
61 if (MAP_FAILED == *code) {
62 return NULL;
63 }
64 return *code;
65 #else
66 # error "Neither ffi_closure_alloc() nor mmap() available"
67 #endif
68 }
69
70 static ffi_status psi_ffi_prep_closure(ffi_closure **closure, void **code, ffi_cif *sig, void (*handler)(ffi_cif*,void*,void**,void*), void *data) {
71 *closure = psi_ffi_closure_alloc(sizeof(ffi_closure), code);
72 assert(*closure != NULL);
73
74 #if PSI_HAVE_FFI_PREP_CLOSURE_LOC
75 return ffi_prep_closure_loc(*closure, sig, handler, data, *code);
76
77 #elif PSI_HAVE_FFI_PREP_CLOSURE
78 return ffi_prep_closure(*code, sig, handler, data);
79 #else
80 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() is available"
81 #endif
82 }
83
84 static void psi_ffi_closure_free(void *c)
85 {
86 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
87 ffi_closure_free(c);
88 #elif HAVE_MMAP
89 munmap(c, sizeof(ffi_closure));
90 #endif
91 }
92
93 static void psi_ffi_prep_va(ffi_cif *base, ffi_cif *signature, size_t argc, size_t va_count,
94 ffi_type **param_types) {
95 ffi_status rc;
96
97 #ifdef PSI_HAVE_FFI_PREP_CIF_VAR
98 rc = ffi_prep_cif_var(signature, base->abi, argc, argc + va_count,
99 base->rtype, param_types);
100 #else
101 /* FIXME: test in config.m4; assume we can just call anyway */
102 rc = ffi_prep_cif(signature, base->abi, argc + va_count, base->rtype, param_types);
103 #endif
104
105 assert(FFI_OK == rc);
106 }
107
108 #if HAVE_INT128
109 static ffi_type *ffi_type_sint128;
110 static ffi_type *ffi_type_uint128;
111 #endif
112
113 static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg);
114
115 static inline ffi_type *psi_ffi_token_type(token_t t) {
116 switch (t) {
117 default:
118 assert(0);
119 /* no break */
120 case PSI_T_VOID:
121 return &ffi_type_void;
122 case PSI_T_INT8:
123 return &ffi_type_sint8;
124 case PSI_T_UINT8:
125 return &ffi_type_uint8;
126 case PSI_T_INT16:
127 return &ffi_type_sint16;
128 case PSI_T_UINT16:
129 return &ffi_type_uint16;
130 case PSI_T_INT32:
131 return &ffi_type_sint32;
132 case PSI_T_UINT32:
133 return &ffi_type_uint32;
134 case PSI_T_INT64:
135 return &ffi_type_sint64;
136 case PSI_T_UINT64:
137 return &ffi_type_uint64;
138 #if HAVE_INT128
139 case PSI_T_INT128:
140 return ffi_type_sint128;
141 case PSI_T_UINT128:
142 return ffi_type_uint128;
143 #endif
144 case PSI_T_BOOL:
145 return &ffi_type_uchar;
146 case PSI_T_ENUM:
147 return &ffi_type_sint;
148 case PSI_T_FLOAT:
149 return &ffi_type_float;
150 case PSI_T_DOUBLE:
151 return &ffi_type_double;
152 #ifdef HAVE_LONG_DOUBLE
153 case PSI_T_LONG_DOUBLE:
154 return &ffi_type_longdouble;
155 #endif
156 case PSI_T_POINTER:
157 case PSI_T_FUNCTION:
158 return &ffi_type_pointer;
159 }
160 }
161 static inline ffi_type *psi_ffi_impl_type(token_t impl_type) {
162 switch (impl_type) {
163 case PSI_T_BOOL:
164 return &ffi_type_sint8;
165 case PSI_T_INT:
166 return &ffi_type_sint64;
167 case PSI_T_STRING:
168 return &ffi_type_pointer;
169 case PSI_T_FLOAT:
170 case PSI_T_DOUBLE:
171 return &ffi_type_double;
172 EMPTY_SWITCH_DEFAULT_CASE();
173 }
174 return NULL;
175 }
176 static void psi_ffi_struct_type_dtor(void *type) {
177 ffi_type *strct = type;
178
179 if (strct->elements) {
180 ffi_type **ptr;
181
182 for (ptr = strct->elements; *ptr; ++ptr) {
183 free(*ptr);
184 }
185 free(strct->elements);
186 }
187 free(strct);
188 }
189
190 static size_t psi_ffi_struct_type_pad(ffi_type **els, size_t padding) {
191 size_t i;
192
193 for (i = 0; i < padding; ++i) {
194 ffi_type *pad = malloc(sizeof(*pad));
195
196 memcpy(pad, &ffi_type_schar, sizeof(*pad));
197 *els++ = pad;
198 }
199
200 return padding;
201 }
202
203 static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) {
204 size_t i = 0, argc, nels = 0, offset = 0, maxalign = 0, last_arg_pos = -1;
205 ffi_type **tmp, **els;
206 struct psi_decl_arg *darg;
207
208 argc = psi_plist_count(strct->args);
209 els = calloc(argc + 1, sizeof(*els));
210
211 while (psi_plist_get(strct->args, i++, &darg)) {
212 ffi_type *type;
213 size_t padding;
214
215 if (darg->layout->pos == last_arg_pos) {
216 /* skip bit fields */
217 continue;
218 }
219 last_arg_pos = darg->layout->pos;
220
221 type = malloc(sizeof(*type));
222 *type = *psi_ffi_decl_arg_type(darg);
223
224 if (type->alignment > maxalign) {
225 maxalign = type->alignment;
226 }
227
228 assert(type->size <= darg->layout->len);
229 if ((padding = psi_offset_padding(darg->layout->pos - offset, type->alignment))) {
230 if (nels + padding + 1 > argc) {
231 argc += padding;
232 tmp = realloc(els, (argc + 1) * sizeof(*els));
233 if (tmp) {
234 els = tmp;
235 } else {
236 free(els);
237 return NULL;
238 }
239 els[argc] = NULL;
240 }
241 psi_ffi_struct_type_pad(&els[nels], padding);
242 nels += padding;
243 offset += padding;
244 }
245 assert(offset == darg->layout->pos);
246
247 offset = (offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1);
248 els[nels++] = type;
249 }
250
251 /* apply struct alignment padding */
252 offset = (offset + maxalign - 1) & ~(maxalign - 1);
253
254 assert(offset <= strct->size);
255 if (offset < strct->size) {
256 size_t padding = strct->size - offset;
257
258 tmp = realloc(els, (padding + argc + 1) * sizeof(*els));
259 if (tmp) {
260 els = tmp;
261 } else {
262 free(els);
263 return NULL;
264 }
265 psi_ffi_struct_type_pad(&els[nels], padding);
266 els[argc + padding] = NULL;
267 }
268
269 return els;
270 }
271 static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) {
272 struct psi_decl_type *real = psi_decl_type_get_real(type);
273
274 switch (real->type) {
275 case PSI_T_STRUCT:
276 if (!real->real.strct->engine.type) {
277 ffi_type *strct = calloc(1, sizeof(ffi_type));
278
279 strct->type = FFI_TYPE_STRUCT;
280 strct->size = 0;
281 strct->elements = psi_ffi_struct_type_elements(real->real.strct);
282
283 real->real.strct->engine.type = strct;
284 real->real.strct->engine.dtor = psi_ffi_struct_type_dtor;
285 }
286
287 return real->real.strct->engine.type;
288
289 case PSI_T_UNION:
290 {
291 struct psi_decl_arg *arg;
292 psi_plist_get(real->real.unn->args, 0, &arg);
293 return psi_ffi_decl_arg_type(arg);
294 }
295
296 default:
297 return psi_ffi_token_type(real->type);
298 }
299 }
300 static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg) {
301 if (darg->var->pointer_level) {
302 return &ffi_type_pointer;
303 } else {
304 return psi_ffi_decl_type(darg->type);
305 }
306 }
307
308 static inline ffi_abi psi_ffi_abi(const char *convention) {
309 if (FFI_LAST_ABI - 2 != FFI_FIRST_ABI) {
310 #ifdef HAVE_FFI_STDCALL
311 if (!strcasecmp(convention, "stdcall")) {
312 return FFI_STDCALL;
313 }
314 #endif
315 #ifdef HAVE_FFI_FASTCALL
316 if (!strcasecmp(convention, "fastcall")) {
317 return FFI_FASTCALL;
318 }
319 #endif
320 }
321 return FFI_DEFAULT_ABI;
322 }
323
324 struct psi_ffi_context {
325 ffi_cif signature;
326 ffi_type *params[2];
327 };
328
329 struct psi_ffi_impl_info {
330 struct psi_context *context;
331 struct psi_call_frame *frame;
332
333 void *code;
334 ffi_closure *closure;
335 };
336
337 struct psi_ffi_callback_info {
338 struct psi_ffi_impl_info *impl_info;
339 struct psi_let_exp *let_exp;
340
341 void *code;
342 ffi_closure *closure;
343 };
344
345 struct psi_ffi_decl_info {
346 ffi_cif signature;
347 ffi_type *params[1];
348 };
349
350 static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) {
351 if (!decl->info) {
352 int rc;
353 size_t i, c = psi_plist_count(decl->args);
354 struct psi_decl_arg *arg;
355 struct psi_ffi_decl_info *info = calloc(1, sizeof(*info) + 2 * c * sizeof(void *));
356
357 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
358 info->params[i] = psi_ffi_decl_arg_type(arg);
359 }
360 info->params[c] = NULL;
361
362 rc = ffi_prep_cif(&info->signature, psi_ffi_abi(decl->abi->convention),
363 c, psi_ffi_decl_arg_type(decl->func), info->params);
364
365 if (FFI_OK != rc) {
366 free(info);
367 } else {
368 decl->info = info;
369 }
370 }
371
372 return decl->info;
373 }
374
375 static inline void psi_ffi_decl_dtor(struct psi_decl *decl) {
376 if (decl->info) {
377 free(decl->info);
378 decl->info = NULL;
379 }
380 }
381
382 static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
383 {
384 struct psi_impl *impl = data;
385 struct psi_ffi_impl_info *info = impl->info;
386
387 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **)args[1], impl);
388 }
389
390 static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
391 {
392 struct psi_ffi_callback_info *cb_info = data;
393 struct psi_call_frame_callback cb_data;
394
395 assert(cb_info->impl_info->frame);
396
397 cb_data.cb = cb_info->let_exp;
398 cb_data.argc = sig->nargs;
399 cb_data.argv = args;
400 cb_data.rval = result;
401
402 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
403 }
404
405 static inline void psi_ffi_callback_init(struct psi_ffi_impl_info *impl_info,
406 struct psi_let_exp *let_exp) {
407 struct psi_ffi_callback_info *cb_info;
408 struct psi_ffi_decl_info *decl_info;
409 struct psi_let_callback *cb;
410 struct psi_let_func *fn = NULL;
411 ffi_status rc;
412
413 switch (let_exp->kind) {
414 case PSI_LET_CALLBACK:
415 cb = let_exp->data.callback;
416 if (cb->decl->info) {
417 decl_info = cb->decl->info;
418 } else {
419 decl_info = psi_ffi_decl_init(cb->decl);
420 }
421
422 cb_info = calloc(1, sizeof(*cb_info));
423 cb_info->impl_info = impl_info;
424 cb_info->let_exp = let_exp;
425 rc = psi_ffi_prep_closure(&cb_info->closure, &cb_info->code,
426 &decl_info->signature, psi_ffi_callback, cb_info);
427
428 if (FFI_OK != rc) {
429 free(cb_info);
430 break;
431 }
432 cb->info = cb_info;
433
434 assert(!cb->decl->sym);
435 cb->decl->sym = cb_info->code;
436 fn = cb->func;
437 /* no break */
438
439 case PSI_LET_FUNC:
440 if (!fn) {
441 fn = let_exp->data.func;
442 }
443 if (fn->inner) {
444 size_t i = 0;
445 struct psi_let_exp *inner_let;
446
447 while (psi_plist_get(fn->inner, i++, &inner_let)) {
448 psi_ffi_callback_init(impl_info, inner_let);
449 }
450 }
451 break;
452 default:
453 break;
454 }
455 }
456
457 static inline void psi_ffi_callback_dtor(struct psi_let_exp *let_exp) {
458 struct psi_let_callback *cb;
459 struct psi_let_func *fn = NULL;
460
461 switch (let_exp->kind) {
462 case PSI_LET_CALLBACK:
463 cb = let_exp->data.callback;
464
465 psi_ffi_decl_dtor(cb->decl);
466
467 if (cb->info) {
468 struct psi_ffi_callback_info *info = cb->info;
469
470 if (info->closure) {
471 psi_ffi_closure_free(info->closure);
472 }
473 free(info);
474 cb->info = NULL;
475 }
476 fn = cb->func;
477 /* no break */
478 case PSI_LET_FUNC:
479 if (!fn) {
480 fn = let_exp->data.func;
481 }
482
483 if (fn->inner) {
484 size_t i = 0;
485 struct psi_let_exp *cb;
486
487 while (psi_plist_get(fn->inner, i++, &cb)) {
488 psi_ffi_callback_dtor(cb);
489 }
490 }
491 break;
492 default:
493 break;
494 }
495 }
496
497 static inline struct psi_ffi_impl_info *psi_ffi_impl_init(struct psi_impl *impl,
498 struct psi_context *C) {
499 struct psi_ffi_context *context = C->context;
500 struct psi_ffi_impl_info *info = calloc(1, sizeof(*info));
501 struct psi_let_stmt *let;
502 ffi_status rc;
503 size_t l = 0;
504
505 info->context = C;
506
507 rc = psi_ffi_prep_closure(&info->closure, &info->code,
508 &context->signature, psi_ffi_handler, impl);
509
510 if (FFI_OK != rc) {
511 free(info);
512 return NULL;
513 }
514
515 while (psi_plist_get(impl->stmts.let, l++, &let)) {
516 psi_ffi_callback_init(info, let->exp);
517 }
518
519 return impl->info = info;
520 }
521
522 static inline void psi_ffi_impl_dtor(struct psi_impl *impl) {
523 struct psi_ffi_impl_info *info = impl->info;
524 struct psi_let_stmt *let;
525 size_t j = 0;
526
527 while (psi_plist_get(impl->stmts.let, j++, &let)) {
528 psi_ffi_callback_dtor(let->exp);
529 }
530
531 if (info) {
532 if (info->closure) {
533 psi_ffi_closure_free(info->closure);
534 }
535 free(info);
536 impl->info = NULL;
537 }
538 }
539
540
541 static inline struct psi_ffi_context *psi_ffi_context_init(struct psi_ffi_context *L) {
542 ffi_status rc;
543
544 if (!L) {
545 L = malloc(sizeof(*L));
546 }
547 memset(L, 0, sizeof(*L));
548
549 L->params[0] = &ffi_type_pointer;
550 L->params[1] = &ffi_type_pointer;
551 rc = ffi_prep_cif(&L->signature, FFI_DEFAULT_ABI, 2, &ffi_type_void, L->params);
552 assert(rc == FFI_OK);
553
554 return L;
555 }
556
557 static inline void psi_ffi_context_free(struct psi_ffi_context **L) {
558 if (*L) {
559 free(*L);
560 *L = NULL;
561 }
562 }
563
564 static void psi_ffi_init(struct psi_context *C)
565 {
566 C->context = psi_ffi_context_init(NULL);
567 }
568
569 static void psi_ffi_dtor(struct psi_context *C)
570 {
571 if (C->decls) {
572 size_t i = 0;
573 struct psi_decl *decl;
574
575 while (psi_plist_get(C->decls, i++, &decl)) {
576 psi_ffi_decl_dtor(decl);
577 }
578
579 }
580 if (C->impls) {
581 size_t i = 0;
582 struct psi_impl *impl;
583
584 while (psi_plist_get(C->impls, i++, &impl)) {
585 psi_ffi_impl_dtor(impl);
586 }
587 }
588 psi_ffi_context_free((void *) &C->context);
589 }
590
591
592 static zend_function_entry *psi_ffi_compile(struct psi_context *C)
593 {
594 size_t i = 0, d = 0, nf = 0;
595 struct psi_impl *impl;
596 struct psi_decl *decl;
597 zend_function_entry *zfe;
598
599 if (!C->impls) {
600 return NULL;
601 }
602
603 zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
604
605 while (psi_plist_get(C->impls, i++, &impl)) {
606 zend_function_entry *zf = &zfe[nf];
607
608 if (!impl->decl) {
609 continue;
610 }
611 if (!psi_ffi_decl_init(impl->decl)) {
612 continue;
613 }
614 if (!psi_ffi_impl_init(impl, C)) {
615 continue;
616 }
617
618 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
619 zf->handler = ((struct psi_ffi_impl_info *) impl->info)->code;
620 zf->num_args = psi_plist_count(impl->func->args);
621 zf->arg_info = psi_internal_arginfo(impl);
622 ++nf;
623 }
624
625 while (psi_plist_get(C->decls, d++, &decl)) {
626 if (decl->info) {
627 continue;
628 }
629
630 psi_ffi_decl_init(decl);
631 }
632
633 return zfe;
634 }
635
636 static inline void psi_ffi_call_ex(struct psi_call_frame *frame) {
637 struct psi_decl *decl = psi_call_frame_get_decl(frame);
638 struct psi_impl *impl = psi_call_frame_get_impl(frame);
639 struct psi_ffi_decl_info *decl_info = decl->info;
640 struct psi_ffi_impl_info *impl_info;
641 struct psi_call_frame *prev;
642
643 if (impl) {
644 impl_info = impl->info;
645 prev = impl_info->frame;
646 impl_info->frame = frame;
647 }
648 ffi_call(&decl_info->signature, FFI_FN(decl->sym),
649 psi_call_frame_get_rpointer(frame),
650 psi_call_frame_get_arg_pointers(frame));
651 if (impl) {
652 impl_info->frame = prev;
653 }
654 }
655
656 static inline void psi_ffi_call_va(struct psi_call_frame *frame) {
657 ffi_cif signature;
658 struct psi_call_frame *prev;
659 struct psi_decl *decl = psi_call_frame_get_decl(frame);
660 struct psi_impl *impl = psi_call_frame_get_impl(frame);
661 struct psi_ffi_decl_info *decl_info = decl->info;
662 struct psi_ffi_impl_info *impl_info;
663 size_t i, va_count, argc;
664 ffi_type **param_types;
665
666 argc = psi_plist_count(decl->args);
667 va_count = psi_call_frame_num_var_args(frame);
668 param_types = ecalloc(argc + va_count + 1, sizeof(ffi_type *));
669 memcpy(param_types, decl_info->params, argc * sizeof(ffi_type *));
670 for (i = 0; i < va_count; ++i) {
671 struct psi_call_frame_argument *frame_arg;
672
673 frame_arg = psi_call_frame_get_var_argument(frame, i);
674 param_types[argc + i] = psi_ffi_impl_type(frame_arg->va_type);
675 }
676
677 psi_ffi_prep_va(&decl_info->signature, &signature, argc, va_count, param_types);
678
679 if (impl) {
680 impl_info = impl->info;
681 prev = impl_info->frame;
682 impl_info->frame = frame;
683 }
684 ffi_call(&signature, FFI_FN(decl->sym),
685 psi_call_frame_get_rpointer(frame),
686 psi_call_frame_get_arg_pointers(frame));
687 if (impl) {
688 impl_info->frame = prev;
689 }
690
691 efree(param_types);
692 }
693
694 static void psi_ffi_call(struct psi_call_frame *frame) {
695 if (psi_call_frame_num_var_args(frame)) {
696 psi_ffi_call_va(frame);
697 } else {
698 psi_ffi_call_ex(frame);
699 }
700 }
701
702 static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void *arg) {
703 switch (q) {
704 case PSI_CONTEXT_QUERY_SELF:
705 return "ffi";
706 case PSI_CONTEXT_QUERY_TYPE:
707 return psi_ffi_impl_type(*(token_t *) arg);
708 }
709 return NULL;
710 }
711
712 static ZEND_RESULT_CODE psi_ffi_load()
713 {
714 #if HAVE_INT128
715 ffi_type *i128, *u128;
716
717 i128 = calloc(1, 3*sizeof(ffi_type));
718 i128->type = FFI_TYPE_STRUCT;
719 i128->size = 0;
720 i128->elements = (ffi_type **) (i128 + 1);
721 i128->elements[0] = &ffi_type_sint64;
722 i128->elements[1] = &ffi_type_sint64;
723
724 ffi_type_sint128 = i128;
725
726 u128 = calloc(1, 3*sizeof(ffi_type));
727 u128->type = FFI_TYPE_STRUCT;
728 u128->size = 0;
729 u128->elements = (ffi_type **) (u128 + 1);
730 u128->elements[0] = &ffi_type_uint64;
731 u128->elements[1] = &ffi_type_uint64;
732
733 ffi_type_uint128 = u128;
734 #endif
735 return SUCCESS;
736 }
737
738 static void psi_ffi_free()
739 {
740 #if HAVE_INT128
741 free(ffi_type_sint128);
742 free(ffi_type_uint128);
743 #endif
744 }
745
746 static struct psi_context_ops ops = {
747 psi_ffi_load,
748 psi_ffi_free,
749 psi_ffi_init,
750 psi_ffi_dtor,
751 psi_ffi_compile,
752 psi_ffi_call,
753 psi_ffi_query,
754 };
755
756 struct psi_context_ops *psi_libffi_ops(void)
757 {
758 return &ops;
759 }
760
761 #endif /* HAVE_LIBFFI */