marshal: array return values
[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 struct psi_ffi_context {
55 ffi_cif signature;
56 ffi_type *params[2];
57 };
58
59 struct psi_ffi_impl_info {
60 struct psi_context *context;
61 struct psi_call_frame *frame;
62
63 void *code;
64 ffi_closure *closure;
65 };
66
67 struct psi_ffi_callback_info {
68 struct psi_ffi_impl_info *impl_info;
69 struct psi_let_exp *let_exp;
70
71 void *code;
72 ffi_closure *closure;
73 };
74
75 struct psi_ffi_decl_info {
76 ffi_cif signature;
77 ffi_type *rv_array;
78 ffi_type *params[1];
79 };
80
81 static void *psi_ffi_closure_alloc(size_t s, void **code)
82 {
83 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
84 return ffi_closure_alloc(s, code);
85 #elif HAVE_MMAP
86 *code = mmap(NULL, s, PROT_EXEC|PROT_WRITE|PROT_READ,
87 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
88 if (MAP_FAILED == *code) {
89 return NULL;
90 }
91 return *code;
92 #else
93 # error "Neither ffi_closure_alloc() nor mmap() available"
94 #endif
95 }
96
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);
100
101 #if PSI_HAVE_FFI_PREP_CLOSURE_LOC
102 return ffi_prep_closure_loc(*closure, sig, handler, data, *code);
103
104 #elif PSI_HAVE_FFI_PREP_CLOSURE
105 return ffi_prep_closure(*code, sig, handler, data);
106 #else
107 # error "Neither ffi_prep_closure() nor ffi_prep_closure_loc() is available"
108 #endif
109 }
110
111 static void psi_ffi_closure_free(void *c)
112 {
113 #ifdef PSI_HAVE_FFI_CLOSURE_ALLOC
114 ffi_closure_free(c);
115 #elif HAVE_MMAP
116 munmap(c, sizeof(ffi_closure));
117 #endif
118 }
119
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) {
122 ffi_status rc;
123
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);
127 #else
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);
130 #endif
131
132 assert(FFI_OK == rc);
133 }
134
135 #if HAVE_INT128
136 static ffi_type *ffi_type_sint128;
137 static ffi_type *ffi_type_uint128;
138 #endif
139
140 static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg,
141 struct psi_decl *fn);
142
143 static inline ffi_type *psi_ffi_token_type(token_t t) {
144 switch (t) {
145 default:
146 assert(0);
147 /* no break */
148 case PSI_T_VOID:
149 return &ffi_type_void;
150 case PSI_T_INT8:
151 return &ffi_type_sint8;
152 case PSI_T_UINT8:
153 return &ffi_type_uint8;
154 case PSI_T_INT16:
155 return &ffi_type_sint16;
156 case PSI_T_UINT16:
157 return &ffi_type_uint16;
158 case PSI_T_INT32:
159 return &ffi_type_sint32;
160 case PSI_T_UINT32:
161 return &ffi_type_uint32;
162 case PSI_T_INT64:
163 return &ffi_type_sint64;
164 case PSI_T_UINT64:
165 return &ffi_type_uint64;
166 #if HAVE_INT128
167 case PSI_T_INT128:
168 return ffi_type_sint128;
169 case PSI_T_UINT128:
170 return ffi_type_uint128;
171 #endif
172 case PSI_T_BOOL:
173 return &ffi_type_uchar;
174 case PSI_T_ENUM:
175 return &ffi_type_sint;
176 case PSI_T_FLOAT:
177 return &ffi_type_float;
178 case PSI_T_DOUBLE:
179 return &ffi_type_double;
180 #ifdef HAVE_LONG_DOUBLE
181 case PSI_T_LONG_DOUBLE:
182 return &ffi_type_longdouble;
183 #endif
184 case PSI_T_POINTER:
185 case PSI_T_FUNCTION:
186 return &ffi_type_pointer;
187 }
188 }
189 static inline ffi_type *psi_ffi_impl_type(token_t impl_type) {
190 switch (impl_type) {
191 case PSI_T_BOOL:
192 return &ffi_type_sint8;
193 case PSI_T_INT:
194 return &ffi_type_sint64;
195 case PSI_T_STRING:
196 return &ffi_type_pointer;
197 case PSI_T_FLOAT:
198 case PSI_T_DOUBLE:
199 return &ffi_type_double;
200 EMPTY_SWITCH_DEFAULT_CASE();
201 }
202 return NULL;
203 }
204 static void psi_ffi_type_dtor(void *type) {
205 ffi_type *strct = type;
206
207 if (strct->elements) {
208 ffi_type **ptr;
209
210 for (ptr = strct->elements; *ptr; ++ptr) {
211 free(*ptr);
212 }
213 free(strct->elements);
214 }
215 free(strct);
216 }
217
218 static size_t psi_ffi_struct_type_pad(ffi_type **els, size_t padding) {
219 size_t i;
220
221 for (i = 0; i < padding; ++i) {
222 ffi_type *pad = malloc(sizeof(*pad));
223
224 memcpy(pad, &ffi_type_schar, sizeof(*pad));
225 *els++ = pad;
226 }
227
228 return padding;
229 }
230
231 struct psi_ffi_struct_element_storage {
232 ffi_type **els;
233 size_t nels;
234 size_t argc;
235 size_t offset;
236 size_t max_align;
237 size_t last_arg_pos;
238 };
239
240 static inline void psi_ffi_struct_type_element(
241 struct psi_ffi_struct_element_storage *s, struct psi_decl_arg *darg) {
242
243 ffi_type *type, **tmp;
244 size_t padding;
245
246 if (darg->layout->pos == s->last_arg_pos) {
247 /* skip bit fields */
248 return;
249 }
250 s->last_arg_pos = darg->layout->pos;
251
252 type = malloc(sizeof(*type));
253 *type = *psi_ffi_decl_arg_type(darg, NULL);
254
255 if (type->alignment > s->max_align) {
256 s->max_align = type->alignment;
257 }
258
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) {
262 s->argc += padding;
263 tmp = realloc(s->els, (s->argc + 1) * sizeof(*s->els));
264 if (tmp) {
265 s->els = tmp;
266 } else {
267 free(s->els);
268 abort();
269 }
270 s->els[s->argc] = NULL;
271 }
272 psi_ffi_struct_type_pad(&s->els[s->nels], padding);
273 s->nels += padding;
274 s->offset += padding;
275 }
276 assert(s->offset == darg->layout->pos);
277
278 s->offset = (s->offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1);
279 s->els[s->nels++] = type;
280 }
281
282 static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) {
283 size_t i = 0;
284 ffi_type **tmp;
285 struct psi_decl_arg *darg;
286 struct psi_ffi_struct_element_storage s = {0};
287
288 s.last_arg_pos = -1;
289 s.argc = psi_plist_count(strct->args);
290 s.els = calloc(s.argc + 1, sizeof(*s.els));
291
292 while (psi_plist_get(strct->args, i++, &darg)) {
293 psi_ffi_struct_type_element(&s, darg);
294 }
295
296 /* apply struct alignment padding */
297 s.offset = (s.offset + s.max_align - 1) & ~(s.max_align - 1);
298
299 assert(s.offset <= strct->size);
300 if (s.offset < strct->size) { /* WTF? */
301 size_t padding = strct->size - s.offset;
302
303 tmp = realloc(s.els, (padding + s.argc + 1) * sizeof(*s.els));
304 if (tmp) {
305 s.els = tmp;
306 } else {
307 free(s.els);
308 return NULL;
309 }
310 psi_ffi_struct_type_pad(&s.els[s.nels], padding);
311 s.els[s.argc + padding] = NULL;
312 }
313
314 return s.els;
315 }
316
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);
319
320 if (real != type && type->real.def->var->pointer_level) {
321 return &ffi_type_pointer;
322 }
323
324 switch (real->type) {
325 case PSI_T_STRUCT:
326 if (!real->real.strct->engine.type) {
327 ffi_type *strct = calloc(1, sizeof(ffi_type));
328
329 strct->type = FFI_TYPE_STRUCT;
330 strct->size = 0;
331 strct->elements = psi_ffi_struct_type_elements(real->real.strct);
332
333 real->real.strct->engine.type = strct;
334 real->real.strct->engine.dtor = psi_ffi_type_dtor;
335 }
336
337 return real->real.strct->engine.type;
338
339 case PSI_T_UNION:
340 {
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);
344 }
345
346 default:
347 break;
348 }
349
350 return psi_ffi_token_type(real->type);
351 }
352
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};
356 struct psi_layout l;
357 size_t i;
358
359 s.last_arg_pos = -1;
360 s.argc = fn->func->var->array_size;
361 s.els = calloc(s.argc + 1, sizeof(*s.els));
362
363 assert(!fn->func->layout);
364 l.pos = 0;
365 l.len = psi_decl_arg_get_size(fn->func);
366
367 fn->func->layout = &l;
368 psi_ffi_struct_type_element(&s, fn->func);
369 fn->func->layout = NULL;
370
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;
375
376 return info->rv_array;
377 }
378
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);
385 }
386 return &ffi_type_pointer;
387 } else {
388 return psi_ffi_decl_type(darg->type);
389 }
390 }
391
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")) {
396 return FFI_STDCALL;
397 }
398 #endif
399 #ifdef HAVE_FFI_FASTCALL
400 if (!strcasecmp(convention, "fastcall")) {
401 return FFI_FASTCALL;
402 }
403 #endif
404 }
405 return FFI_DEFAULT_ABI;
406 }
407
408 static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) {
409 if (!decl->info) {
410 int rc;
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 *));
414
415 decl->info = info;
416
417 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
418 info->params[i] = psi_ffi_decl_arg_type(arg, NULL);
419 }
420 info->params[c] = NULL;
421
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);
424
425 if (FFI_OK != rc) {
426 free(info);
427 decl->info = NULL;
428 }
429 }
430
431 return decl->info;
432 }
433
434 static inline void psi_ffi_decl_dtor(struct psi_decl *decl) {
435 if (decl->info) {
436 struct psi_ffi_decl_info *info = decl->info;
437
438 if (info->rv_array) {
439 psi_ffi_type_dtor(info->rv_array);
440 }
441 free(decl->info);
442 decl->info = NULL;
443 }
444 }
445
446 static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
447 {
448 struct psi_impl *impl = data;
449 struct psi_ffi_impl_info *info = impl->info;
450
451 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **)args[1], impl);
452 }
453
454 static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
455 {
456 struct psi_ffi_callback_info *cb_info = data;
457 struct psi_call_frame_callback cb_data;
458
459 assert(cb_info->impl_info->frame);
460
461 cb_data.cb = cb_info->let_exp;
462 cb_data.argc = sig->nargs;
463 cb_data.argv = args;
464 cb_data.rval = result;
465
466 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
467 }
468
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;
475 ffi_status rc;
476
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;
482 } else {
483 decl_info = psi_ffi_decl_init(cb->decl);
484 }
485
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);
491
492 if (FFI_OK != rc) {
493 free(cb_info);
494 break;
495 }
496 cb->info = cb_info;
497
498 assert(!cb->decl->sym);
499 cb->decl->sym = cb_info->code;
500 fn = cb->func;
501 /* no break */
502
503 case PSI_LET_FUNC:
504 if (!fn) {
505 fn = let_exp->data.func;
506 }
507 if (fn->inner) {
508 size_t i = 0;
509 struct psi_let_exp *inner_let;
510
511 while (psi_plist_get(fn->inner, i++, &inner_let)) {
512 psi_ffi_callback_init(impl_info, inner_let);
513 }
514 }
515 break;
516 default:
517 break;
518 }
519 }
520
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;
524
525 switch (let_exp->kind) {
526 case PSI_LET_CALLBACK:
527 cb = let_exp->data.callback;
528
529 psi_ffi_decl_dtor(cb->decl);
530
531 if (cb->info) {
532 struct psi_ffi_callback_info *info = cb->info;
533
534 if (info->closure) {
535 psi_ffi_closure_free(info->closure);
536 }
537 free(info);
538 cb->info = NULL;
539 }
540 fn = cb->func;
541 /* no break */
542 case PSI_LET_FUNC:
543 if (!fn) {
544 fn = let_exp->data.func;
545 }
546
547 if (fn->inner) {
548 size_t i = 0;
549 struct psi_let_exp *cb;
550
551 while (psi_plist_get(fn->inner, i++, &cb)) {
552 psi_ffi_callback_dtor(cb);
553 }
554 }
555 break;
556 default:
557 break;
558 }
559 }
560
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;
566 ffi_status rc;
567 size_t l = 0;
568
569 info->context = C;
570
571 rc = psi_ffi_prep_closure(&info->closure, &info->code,
572 &context->signature, psi_ffi_handler, impl);
573
574 if (FFI_OK != rc) {
575 free(info);
576 return NULL;
577 }
578
579 while (psi_plist_get(impl->stmts.let, l++, &let)) {
580 psi_ffi_callback_init(info, let->exp);
581 }
582
583 return impl->info = info;
584 }
585
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;
589 size_t j = 0;
590
591 while (psi_plist_get(impl->stmts.let, j++, &let)) {
592 psi_ffi_callback_dtor(let->exp);
593 }
594
595 if (info) {
596 if (info->closure) {
597 psi_ffi_closure_free(info->closure);
598 }
599 free(info);
600 impl->info = NULL;
601 }
602 }
603
604 static void psi_ffi_extvar_get(ffi_cif *sig, void *result, void **args, void *data) {
605 struct psi_decl_extvar *evar = data;
606
607 psi_decl_extvar_get(evar, result);
608 }
609
610 static void psi_ffi_extvar_set(ffi_cif *sig, void *result, void **args, void *data) {
611 struct psi_decl_extvar *evar = data;
612
613 psi_decl_extvar_set(evar, args[0]);
614 }
615
616 struct psi_ffi_extvar_info {
617 struct {
618 ffi_cif signature;
619 void *code;
620 ffi_closure *closure;
621 } get;
622 struct {
623 ffi_cif signature;
624 ffi_type *params[1];
625 void *code;
626 ffi_closure *closure;
627 } set;
628 };
629
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));
632 ffi_type *type;
633 ffi_status rc;
634
635 evar->info = info;
636
637 psi_ffi_decl_init(evar->getter);
638 psi_ffi_decl_init(evar->setter);
639
640 type = psi_ffi_decl_arg_type(evar->arg, evar->getter);
641
642 rc = ffi_prep_cif(&info->get.signature, FFI_DEFAULT_ABI, 0,
643 type, NULL);
644 if (FFI_OK != rc) {
645 return rc;
646 }
647 rc = psi_ffi_prep_closure(&info->get.closure, &info->get.code,
648 &info->get.signature, psi_ffi_extvar_get, evar);
649 if (FFI_OK != rc) {
650 return rc;
651 }
652
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);
656 if (FFI_OK != rc) {
657 return rc;
658 }
659 rc = psi_ffi_prep_closure(&info->set.closure, &info->set.code,
660 &info->set.signature, psi_ffi_extvar_set, evar);
661 if (FFI_OK != rc) {
662 return rc;
663 }
664
665 evar->getter->sym = info->get.code;
666 evar->setter->sym = info->set.code;
667
668 return FFI_OK;
669 }
670
671 static inline void psi_ffi_extvar_dtor(struct psi_decl_extvar *evar) {
672 if (evar->info) {
673 free(evar->info);
674 evar->info = NULL;
675 }
676 }
677
678 static inline struct psi_ffi_context *psi_ffi_context_init(struct psi_ffi_context *L) {
679 ffi_status rc;
680
681 if (!L) {
682 L = malloc(sizeof(*L));
683 }
684 memset(L, 0, sizeof(*L));
685
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);
690
691 return L;
692 }
693
694 static inline void psi_ffi_context_free(struct psi_ffi_context **L) {
695 if (*L) {
696 free(*L);
697 *L = NULL;
698 }
699 }
700
701 static void psi_ffi_init(struct psi_context *C)
702 {
703 C->context = psi_ffi_context_init(NULL);
704 }
705
706 static void psi_ffi_dtor(struct psi_context *C)
707 {
708 if (C->decls) {
709 size_t i = 0;
710 struct psi_decl *decl;
711
712 while (psi_plist_get(C->decls, i++, &decl)) {
713 psi_ffi_decl_dtor(decl);
714 }
715
716 }
717 if (C->vars) {
718 size_t i = 0;
719 struct psi_decl_extvar *evar;
720
721 while (psi_plist_get(C->vars, i++, &evar)) {
722 psi_ffi_extvar_dtor(evar);
723 }
724 }
725 if (C->impls) {
726 size_t i = 0;
727 struct psi_impl *impl;
728
729 while (psi_plist_get(C->impls, i++, &impl)) {
730 psi_ffi_impl_dtor(impl);
731 }
732 }
733 psi_ffi_context_free((void *) &C->context);
734 }
735
736
737 static zend_function_entry *psi_ffi_compile(struct psi_context *C)
738 {
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;
744
745 while (psi_plist_get(C->vars, v++, &evar)) {
746 if (FFI_OK == psi_ffi_extvar_init(evar)) {
747 /* */
748 }
749 }
750
751 if (C->impls) {
752 zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
753
754 while (psi_plist_get(C->impls, i++, &impl)) {
755 zend_function_entry *zf = &zfe[nf];
756
757 if (!impl->decl) {
758 continue;
759 }
760 if (!psi_ffi_decl_init(impl->decl)) {
761 continue;
762 }
763 if (!psi_ffi_impl_init(impl, C)) {
764 continue;
765 }
766
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);
771 ++nf;
772 }
773 }
774
775 while (psi_plist_get(C->decls, d++, &decl)) {
776 if (decl->info) {
777 continue;
778 }
779
780 psi_ffi_decl_init(decl);
781 }
782
783 return zfe;
784 }
785
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;
792
793 if (impl) {
794 impl_info = impl->info;
795 prev = impl_info->frame;
796 impl_info->frame = frame;
797 }
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));
801 if (impl) {
802 impl_info->frame = prev;
803 }
804 }
805
806 static inline void psi_ffi_call_va(struct psi_call_frame *frame) {
807 ffi_cif signature;
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;
815
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;
822
823 frame_arg = psi_call_frame_get_var_argument(frame, i);
824 param_types[argc + i] = psi_ffi_impl_type(frame_arg->va_type);
825 }
826
827 psi_ffi_prep_va(&decl_info->signature, &signature, argc, va_count, param_types);
828
829 if (impl) {
830 impl_info = impl->info;
831 prev = impl_info->frame;
832 impl_info->frame = frame;
833 }
834 ffi_call(&signature, FFI_FN(decl->sym),
835 psi_call_frame_get_rpointer(frame),
836 psi_call_frame_get_arg_pointers(frame));
837 if (impl) {
838 impl_info->frame = prev;
839 }
840
841 efree(param_types);
842 }
843
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);
847 } else {
848 psi_ffi_call_ex(frame);
849 }
850 }
851
852 static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void *arg) {
853 switch (q) {
854 case PSI_CONTEXT_QUERY_SELF:
855 return "ffi";
856 case PSI_CONTEXT_QUERY_TYPE:
857 return psi_ffi_impl_type(*(token_t *) arg);
858 }
859 return NULL;
860 }
861
862 static ZEND_RESULT_CODE psi_ffi_load()
863 {
864 #if HAVE_INT128
865 ffi_type *i128, *u128;
866
867 i128 = calloc(1, 3*sizeof(ffi_type));
868 i128->type = FFI_TYPE_STRUCT;
869 i128->size = 0;
870 i128->elements = (ffi_type **) (i128 + 1);
871 i128->elements[0] = &ffi_type_sint64;
872 i128->elements[1] = &ffi_type_sint64;
873
874 ffi_type_sint128 = i128;
875
876 u128 = calloc(1, 3*sizeof(ffi_type));
877 u128->type = FFI_TYPE_STRUCT;
878 u128->size = 0;
879 u128->elements = (ffi_type **) (u128 + 1);
880 u128->elements[0] = &ffi_type_uint64;
881 u128->elements[1] = &ffi_type_uint64;
882
883 ffi_type_uint128 = u128;
884 #endif
885 return SUCCESS;
886 }
887
888 static void psi_ffi_free()
889 {
890 #if HAVE_INT128
891 free(ffi_type_sint128);
892 free(ffi_type_uint128);
893 #endif
894 }
895
896 static struct psi_context_ops ops = {
897 psi_ffi_load,
898 psi_ffi_free,
899 psi_ffi_init,
900 psi_ffi_dtor,
901 psi_ffi_compile,
902 psi_ffi_call,
903 psi_ffi_query,
904 };
905
906 struct psi_context_ops *psi_libffi_ops(void)
907 {
908 return &ops;
909 }
910
911 #endif /* HAVE_LIBFFI */