cover null default val
[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 static void psi_ffi_extvar_get(ffi_cif *sig, void *result, void **args, void *data) {
541 struct psi_decl_extvar *evar = data;
542
543 psi_decl_extvar_get(evar, result);
544 }
545
546 static void psi_ffi_extvar_set(ffi_cif *sig, void *result, void **args, void *data) {
547 struct psi_decl_extvar *evar = data;
548
549 psi_decl_extvar_set(evar, args[0]);
550 }
551
552 struct psi_ffi_extvar_info {
553 struct {
554 ffi_cif signature;
555 void *code;
556 ffi_closure *closure;
557 } get;
558 struct {
559 ffi_cif signature;
560 ffi_type *params[1];
561 void *code;
562 ffi_closure *closure;
563 } set;
564 };
565
566 static inline ffi_status psi_ffi_extvar_init(struct psi_decl_extvar *evar,
567 ffi_type *type) {
568 struct psi_ffi_extvar_info *info = calloc(1, sizeof(*info));
569 ffi_status rc;
570
571 rc = ffi_prep_cif(&info->get.signature, FFI_DEFAULT_ABI, 0,
572 type, NULL);
573 if (FFI_OK != rc) {
574 return rc;
575 }
576 rc = psi_ffi_prep_closure(&info->get.closure, &info->get.code,
577 &info->get.signature, psi_ffi_extvar_get, evar);
578 if (FFI_OK != rc) {
579 return rc;
580 }
581
582 info->set.params[0] = type;
583 rc = ffi_prep_cif(&info->set.signature, FFI_DEFAULT_ABI, 1,
584 &ffi_type_void, info->set.params);
585 if (FFI_OK != rc) {
586 return rc;
587 }
588 rc = psi_ffi_prep_closure(&info->set.closure, &info->set.code,
589 &info->set.signature, psi_ffi_extvar_set, evar);
590 if (FFI_OK != rc) {
591 return rc;
592 }
593
594 evar->info = info;
595 evar->getter->sym = info->get.code;
596 evar->setter->sym = info->set.code;
597
598 return FFI_OK;
599 }
600
601 static inline void psi_ffi_extvar_dtor(struct psi_decl_extvar *evar) {
602 if (evar->info) {
603 free(evar->info);
604 evar->info = NULL;
605 }
606 }
607
608 static inline struct psi_ffi_context *psi_ffi_context_init(struct psi_ffi_context *L) {
609 ffi_status rc;
610
611 if (!L) {
612 L = malloc(sizeof(*L));
613 }
614 memset(L, 0, sizeof(*L));
615
616 L->params[0] = &ffi_type_pointer;
617 L->params[1] = &ffi_type_pointer;
618 rc = ffi_prep_cif(&L->signature, FFI_DEFAULT_ABI, 2, &ffi_type_void, L->params);
619 assert(rc == FFI_OK);
620
621 return L;
622 }
623
624 static inline void psi_ffi_context_free(struct psi_ffi_context **L) {
625 if (*L) {
626 free(*L);
627 *L = NULL;
628 }
629 }
630
631 static void psi_ffi_init(struct psi_context *C)
632 {
633 C->context = psi_ffi_context_init(NULL);
634 }
635
636 static void psi_ffi_dtor(struct psi_context *C)
637 {
638 if (C->decls) {
639 size_t i = 0;
640 struct psi_decl *decl;
641
642 while (psi_plist_get(C->decls, i++, &decl)) {
643 psi_ffi_decl_dtor(decl);
644 }
645
646 }
647 if (C->vars) {
648 size_t i = 0;
649 struct psi_decl_extvar *evar;
650
651 while (psi_plist_get(C->vars, i++, &evar)) {
652 psi_ffi_extvar_dtor(evar);
653 }
654 }
655 if (C->impls) {
656 size_t i = 0;
657 struct psi_impl *impl;
658
659 while (psi_plist_get(C->impls, i++, &impl)) {
660 psi_ffi_impl_dtor(impl);
661 }
662 }
663 psi_ffi_context_free((void *) &C->context);
664 }
665
666
667 static zend_function_entry *psi_ffi_compile(struct psi_context *C)
668 {
669 size_t i = 0, d = 0, v = 0, nf = 0;
670 struct psi_impl *impl;
671 struct psi_decl *decl;
672 struct psi_decl_extvar *evar;
673 zend_function_entry *zfe = NULL;
674
675 while (psi_plist_get(C->vars, v++, &evar)) {
676 ffi_type *type = psi_ffi_decl_arg_type(evar->arg);
677
678 if (FFI_OK == psi_ffi_extvar_init(evar, type)) {
679 /* */
680 }
681 }
682
683 if (C->impls) {
684 zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
685
686 while (psi_plist_get(C->impls, i++, &impl)) {
687 zend_function_entry *zf = &zfe[nf];
688
689 if (!impl->decl) {
690 continue;
691 }
692 if (!psi_ffi_decl_init(impl->decl)) {
693 continue;
694 }
695 if (!psi_ffi_impl_init(impl, C)) {
696 continue;
697 }
698
699 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
700 zf->handler = ((struct psi_ffi_impl_info *) impl->info)->code;
701 zf->num_args = psi_plist_count(impl->func->args);
702 zf->arg_info = psi_internal_arginfo(impl);
703 ++nf;
704 }
705 }
706
707 while (psi_plist_get(C->decls, d++, &decl)) {
708 if (decl->info) {
709 continue;
710 }
711
712 psi_ffi_decl_init(decl);
713 }
714
715 return zfe;
716 }
717
718 static inline void psi_ffi_call_ex(struct psi_call_frame *frame) {
719 struct psi_decl *decl = psi_call_frame_get_decl(frame);
720 struct psi_impl *impl = psi_call_frame_get_impl(frame);
721 struct psi_ffi_decl_info *decl_info = decl->info;
722 struct psi_ffi_impl_info *impl_info;
723 struct psi_call_frame *prev;
724
725 if (impl) {
726 impl_info = impl->info;
727 prev = impl_info->frame;
728 impl_info->frame = frame;
729 }
730 ffi_call(&decl_info->signature, FFI_FN(decl->sym),
731 psi_call_frame_get_rpointer(frame),
732 psi_call_frame_get_arg_pointers(frame));
733 if (impl) {
734 impl_info->frame = prev;
735 }
736 }
737
738 static inline void psi_ffi_call_va(struct psi_call_frame *frame) {
739 ffi_cif signature;
740 struct psi_call_frame *prev;
741 struct psi_decl *decl = psi_call_frame_get_decl(frame);
742 struct psi_impl *impl = psi_call_frame_get_impl(frame);
743 struct psi_ffi_decl_info *decl_info = decl->info;
744 struct psi_ffi_impl_info *impl_info;
745 size_t i, va_count, argc;
746 ffi_type **param_types;
747
748 argc = psi_plist_count(decl->args);
749 va_count = psi_call_frame_num_var_args(frame);
750 param_types = ecalloc(argc + va_count + 1, sizeof(ffi_type *));
751 memcpy(param_types, decl_info->params, argc * sizeof(ffi_type *));
752 for (i = 0; i < va_count; ++i) {
753 struct psi_call_frame_argument *frame_arg;
754
755 frame_arg = psi_call_frame_get_var_argument(frame, i);
756 param_types[argc + i] = psi_ffi_impl_type(frame_arg->va_type);
757 }
758
759 psi_ffi_prep_va(&decl_info->signature, &signature, argc, va_count, param_types);
760
761 if (impl) {
762 impl_info = impl->info;
763 prev = impl_info->frame;
764 impl_info->frame = frame;
765 }
766 ffi_call(&signature, FFI_FN(decl->sym),
767 psi_call_frame_get_rpointer(frame),
768 psi_call_frame_get_arg_pointers(frame));
769 if (impl) {
770 impl_info->frame = prev;
771 }
772
773 efree(param_types);
774 }
775
776 static void psi_ffi_call(struct psi_call_frame *frame) {
777 if (psi_call_frame_num_var_args(frame)) {
778 psi_ffi_call_va(frame);
779 } else {
780 psi_ffi_call_ex(frame);
781 }
782 }
783
784 static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void *arg) {
785 switch (q) {
786 case PSI_CONTEXT_QUERY_SELF:
787 return "ffi";
788 case PSI_CONTEXT_QUERY_TYPE:
789 return psi_ffi_impl_type(*(token_t *) arg);
790 }
791 return NULL;
792 }
793
794 static ZEND_RESULT_CODE psi_ffi_load()
795 {
796 #if HAVE_INT128
797 ffi_type *i128, *u128;
798
799 i128 = calloc(1, 3*sizeof(ffi_type));
800 i128->type = FFI_TYPE_STRUCT;
801 i128->size = 0;
802 i128->elements = (ffi_type **) (i128 + 1);
803 i128->elements[0] = &ffi_type_sint64;
804 i128->elements[1] = &ffi_type_sint64;
805
806 ffi_type_sint128 = i128;
807
808 u128 = calloc(1, 3*sizeof(ffi_type));
809 u128->type = FFI_TYPE_STRUCT;
810 u128->size = 0;
811 u128->elements = (ffi_type **) (u128 + 1);
812 u128->elements[0] = &ffi_type_uint64;
813 u128->elements[1] = &ffi_type_uint64;
814
815 ffi_type_uint128 = u128;
816 #endif
817 return SUCCESS;
818 }
819
820 static void psi_ffi_free()
821 {
822 #if HAVE_INT128
823 free(ffi_type_sint128);
824 free(ffi_type_uint128);
825 #endif
826 }
827
828 static struct psi_context_ops ops = {
829 psi_ffi_load,
830 psi_ffi_free,
831 psi_ffi_init,
832 psi_ffi_dtor,
833 psi_ffi_compile,
834 psi_ffi_call,
835 psi_ffi_query,
836 };
837
838 struct psi_context_ops *psi_libffi_ops(void)
839 {
840 return &ops;
841 }
842
843 #endif /* HAVE_LIBFFI */