fbd79b0c844f0b815ac9a8f17ef95be3714066dd
[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
142 static inline ffi_type *psi_ffi_token_type(token_t t) {
143 switch (t) {
144 default:
145 assert(0);
146 /* no break */
147 case PSI_T_VOID:
148 return &ffi_type_void;
149 case PSI_T_INT8:
150 return &ffi_type_sint8;
151 case PSI_T_UINT8:
152 return &ffi_type_uint8;
153 case PSI_T_INT16:
154 return &ffi_type_sint16;
155 case PSI_T_UINT16:
156 return &ffi_type_uint16;
157 case PSI_T_INT32:
158 return &ffi_type_sint32;
159 case PSI_T_UINT32:
160 return &ffi_type_uint32;
161 case PSI_T_INT64:
162 return &ffi_type_sint64;
163 case PSI_T_UINT64:
164 return &ffi_type_uint64;
165 #if HAVE_INT128
166 case PSI_T_INT128:
167 return ffi_type_sint128;
168 case PSI_T_UINT128:
169 return ffi_type_uint128;
170 #endif
171 case PSI_T_BOOL:
172 return &ffi_type_uchar;
173 case PSI_T_ENUM:
174 return &ffi_type_sint;
175 case PSI_T_FLOAT:
176 return &ffi_type_float;
177 case PSI_T_DOUBLE:
178 return &ffi_type_double;
179 #ifdef HAVE_LONG_DOUBLE
180 case PSI_T_LONG_DOUBLE:
181 return &ffi_type_longdouble;
182 #endif
183 case PSI_T_POINTER:
184 case PSI_T_FUNCTION:
185 return &ffi_type_pointer;
186 }
187 }
188 static inline ffi_type *psi_ffi_impl_type(token_t impl_type) {
189 switch (impl_type) {
190 case PSI_T_BOOL:
191 return &ffi_type_sint8;
192 case PSI_T_INT:
193 return &ffi_type_sint64;
194 case PSI_T_STRING:
195 return &ffi_type_pointer;
196 case PSI_T_FLOAT:
197 case PSI_T_DOUBLE:
198 return &ffi_type_double;
199 EMPTY_SWITCH_DEFAULT_CASE();
200 }
201 return NULL;
202 }
203 static void psi_ffi_type_dtor(void *type) {
204 ffi_type *strct = type;
205
206 if (strct->elements) {
207 ffi_type **ptr;
208
209 for (ptr = strct->elements; *ptr; ++ptr) {
210 free(*ptr);
211 }
212 free(strct->elements);
213 }
214 free(strct);
215 }
216
217 static size_t psi_ffi_struct_type_pad(ffi_type **els, size_t padding) {
218 size_t i;
219
220 for (i = 0; i < padding; ++i) {
221 ffi_type *pad = malloc(sizeof(*pad));
222
223 memcpy(pad, &ffi_type_schar, sizeof(*pad));
224 *els++ = pad;
225 }
226
227 return padding;
228 }
229
230 struct psi_ffi_struct_element_storage {
231 ffi_type **els;
232 size_t nels;
233 size_t argc;
234 size_t offset;
235 size_t max_align;
236 size_t last_arg_pos;
237 };
238
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) {
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 = *darg_type;
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, psi_ffi_decl_arg_type(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);
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 ffi_type *type;
358 size_t i;
359
360 if (info->rv_array) {
361 return info->rv_array;
362 }
363
364 s.last_arg_pos = -1;
365 s.argc = fn->func->var->array_size;
366 s.els = calloc(s.argc + 1, sizeof(*s.els));
367
368 info->rv_array = calloc(1, sizeof(ffi_type));
369 info->rv_array->type = FFI_TYPE_STRUCT;
370 info->rv_array->size = 0;
371 info->rv_array->elements = s.els;
372
373 l.pos = 0;
374 if (fn->func->var->pointer_level > 1) {
375 l.len = SIZEOF_VOID_P;
376 type = &ffi_type_pointer;
377 } else {
378 l.len = psi_decl_type_get_size(fn->func->type, NULL);
379 type = psi_ffi_decl_type(fn->func->type);
380 }
381
382 assert(!fn->func->layout);
383 fn->func->layout = &l;
384 for (i = 0; i < fn->func->var->array_size; ++i) {
385 psi_ffi_struct_type_element(&s, fn->func, type);
386 info->rv_array->elements = s.els;
387 l.pos += l.len;
388 }
389 fn->func->layout = NULL;
390
391 return info->rv_array;
392 }
393
394 static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg) {
395 if (darg->var->pointer_level) {
396 return &ffi_type_pointer;
397 } else {
398 return psi_ffi_decl_type(darg->type);
399 }
400 }
401
402 static inline ffi_type *psi_ffi_decl_func_type(struct psi_decl *fn) {
403 struct psi_decl_arg *darg = fn->func;
404
405 if (darg->var->pointer_level) {
406 if (darg->var->array_size) {
407 /* mimic a struct resembling the array return type of fn */
408 return psi_ffi_decl_func_array_type(fn);
409 }
410 return &ffi_type_pointer;
411 } else {
412 return psi_ffi_decl_type(darg->type);
413 }
414 }
415
416 static inline ffi_abi psi_ffi_abi(zend_string *convention) {
417 if (FFI_LAST_ABI - 2 != FFI_FIRST_ABI) {
418 #ifdef HAVE_FFI_STDCALL
419 if (zend_string_equals_literal(convention, "stdcall")) {
420 return FFI_STDCALL;
421 }
422 #endif
423 #ifdef HAVE_FFI_FASTCALL
424 if (zend_string_equals_literal(convention, "fastcall")) {
425 return FFI_FASTCALL;
426 }
427 #endif
428 }
429 return FFI_DEFAULT_ABI;
430 }
431
432 static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) {
433 if (!decl->info) {
434 int rc;
435 size_t i, c = psi_plist_count(decl->args);
436 struct psi_decl_arg *arg;
437 struct psi_ffi_decl_info *info = calloc(1, sizeof(*info) + 2 * c * sizeof(void *));
438
439 decl->info = info;
440
441 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
442 info->params[i] = psi_ffi_decl_arg_type(arg);
443 }
444 info->params[c] = NULL;
445
446 rc = ffi_prep_cif(&info->signature, psi_ffi_abi(decl->abi->convention),
447 c, psi_ffi_decl_func_type(decl), info->params);
448
449 if (FFI_OK != rc) {
450 free(info);
451 decl->info = NULL;
452 }
453 }
454
455 return decl->info;
456 }
457
458 static inline void psi_ffi_decl_dtor(struct psi_decl *decl) {
459 if (decl->info) {
460 struct psi_ffi_decl_info *info = decl->info;
461
462 if (info->rv_array) {
463 psi_ffi_type_dtor(info->rv_array);
464 }
465 free(decl->info);
466 decl->info = NULL;
467 }
468 }
469
470 static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
471 {
472 struct psi_impl *impl = data;
473 struct psi_ffi_impl_info *info = impl->info;
474
475 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **)args[1], impl);
476 }
477
478 static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
479 {
480 struct psi_ffi_callback_info *cb_info = data;
481 struct psi_call_frame_callback cb_data;
482
483 assert(cb_info->impl_info->frame);
484
485 cb_data.cb = cb_info->let_exp;
486 cb_data.argc = sig->nargs;
487 cb_data.argv = args;
488 cb_data.rval = result;
489
490 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
491 }
492
493 static inline void psi_ffi_callback_init(struct psi_ffi_impl_info *impl_info,
494 struct psi_let_exp *let_exp) {
495 struct psi_ffi_callback_info *cb_info;
496 struct psi_ffi_decl_info *decl_info;
497 struct psi_let_callback *cb;
498 struct psi_let_func *fn = NULL;
499 ffi_status rc;
500
501 switch (let_exp->kind) {
502 case PSI_LET_CALLBACK:
503 cb = let_exp->data.callback;
504 if (cb->decl->info) {
505 decl_info = cb->decl->info;
506 } else {
507 decl_info = psi_ffi_decl_init(cb->decl);
508 }
509
510 cb_info = calloc(1, sizeof(*cb_info));
511 cb_info->impl_info = impl_info;
512 cb_info->let_exp = let_exp;
513 rc = psi_ffi_prep_closure(&cb_info->closure, &cb_info->code,
514 &decl_info->signature, psi_ffi_callback, cb_info);
515
516 if (FFI_OK != rc) {
517 free(cb_info);
518 break;
519 }
520 cb->info = cb_info;
521
522 assert(!cb->decl->sym);
523 cb->decl->sym = cb_info->code;
524 fn = cb->func;
525 /* no break */
526
527 case PSI_LET_FUNC:
528 if (!fn) {
529 fn = let_exp->data.func;
530 }
531 if (fn->inner) {
532 size_t i = 0;
533 struct psi_let_exp *inner_let;
534
535 while (psi_plist_get(fn->inner, i++, &inner_let)) {
536 psi_ffi_callback_init(impl_info, inner_let);
537 }
538 }
539 break;
540 default:
541 break;
542 }
543 }
544
545 static inline void psi_ffi_callback_dtor(struct psi_let_exp *let_exp) {
546 struct psi_let_callback *cb;
547 struct psi_let_func *fn = NULL;
548
549 switch (let_exp->kind) {
550 case PSI_LET_CALLBACK:
551 cb = let_exp->data.callback;
552
553 psi_ffi_decl_dtor(cb->decl);
554
555 if (cb->info) {
556 struct psi_ffi_callback_info *info = cb->info;
557
558 if (info->closure) {
559 psi_ffi_closure_free(info->closure);
560 }
561 free(info);
562 cb->info = NULL;
563 }
564 fn = cb->func;
565 /* no break */
566 case PSI_LET_FUNC:
567 if (!fn) {
568 fn = let_exp->data.func;
569 }
570
571 if (fn->inner) {
572 size_t i = 0;
573 struct psi_let_exp *cb;
574
575 while (psi_plist_get(fn->inner, i++, &cb)) {
576 psi_ffi_callback_dtor(cb);
577 }
578 }
579 break;
580 default:
581 break;
582 }
583 }
584
585 static inline struct psi_ffi_impl_info *psi_ffi_impl_init(struct psi_impl *impl,
586 struct psi_context *C) {
587 struct psi_ffi_context *context = C->context;
588 struct psi_ffi_impl_info *info = calloc(1, sizeof(*info));
589 struct psi_let_stmt *let;
590 ffi_status rc;
591 size_t l = 0;
592
593 info->context = C;
594
595 rc = psi_ffi_prep_closure(&info->closure, &info->code,
596 &context->signature, psi_ffi_handler, impl);
597
598 if (FFI_OK != rc) {
599 free(info);
600 return NULL;
601 }
602
603 while (psi_plist_get(impl->stmts.let, l++, &let)) {
604 psi_ffi_callback_init(info, let->exp);
605 }
606
607 return impl->info = info;
608 }
609
610 static inline void psi_ffi_impl_dtor(struct psi_impl *impl) {
611 struct psi_ffi_impl_info *info = impl->info;
612 struct psi_let_stmt *let;
613 size_t j = 0;
614
615 while (psi_plist_get(impl->stmts.let, j++, &let)) {
616 psi_ffi_callback_dtor(let->exp);
617 }
618
619 if (info) {
620 if (info->closure) {
621 psi_ffi_closure_free(info->closure);
622 }
623 free(info);
624 impl->info = NULL;
625 }
626 }
627
628 static void psi_ffi_extvar_get(ffi_cif *sig, void *result, void **args, void *data) {
629 struct psi_decl_extvar *evar = data;
630
631 psi_decl_extvar_get(evar, result);
632 }
633
634 static void psi_ffi_extvar_set(ffi_cif *sig, void *result, void **args, void *data) {
635 struct psi_decl_extvar *evar = data;
636
637 psi_decl_extvar_set(evar, args[0]);
638 }
639
640 struct psi_ffi_extvar_info {
641 struct {
642 ffi_cif signature;
643 void *code;
644 ffi_closure *closure;
645 } get;
646 struct {
647 ffi_cif signature;
648 ffi_type *params[1];
649 void *code;
650 ffi_closure *closure;
651 } set;
652 };
653
654 static inline ffi_status psi_ffi_extvar_init(struct psi_decl_extvar *evar) {
655 struct psi_ffi_extvar_info *info = calloc(1, sizeof(*info));
656 ffi_status rc;
657
658 evar->info = info;
659
660 psi_ffi_decl_init(evar->getter);
661 psi_ffi_decl_init(evar->setter);
662
663 rc = ffi_prep_cif(&info->get.signature, FFI_DEFAULT_ABI, 0,
664 psi_ffi_decl_func_type(evar->getter), NULL);
665 if (FFI_OK != rc) {
666 return rc;
667 }
668 rc = psi_ffi_prep_closure(&info->get.closure, &info->get.code,
669 &info->get.signature, psi_ffi_extvar_get, evar);
670 if (FFI_OK != rc) {
671 return rc;
672 }
673
674 info->set.params[0] = psi_ffi_decl_arg_type(evar->arg);
675 rc = ffi_prep_cif(&info->set.signature, FFI_DEFAULT_ABI, 1,
676 &ffi_type_void, info->set.params);
677 if (FFI_OK != rc) {
678 return rc;
679 }
680 rc = psi_ffi_prep_closure(&info->set.closure, &info->set.code,
681 &info->set.signature, psi_ffi_extvar_set, evar);
682 if (FFI_OK != rc) {
683 return rc;
684 }
685
686 evar->getter->sym = info->get.code;
687 evar->setter->sym = info->set.code;
688
689 return FFI_OK;
690 }
691
692 static inline void psi_ffi_extvar_dtor(struct psi_decl_extvar *evar) {
693 if (evar->info) {
694 free(evar->info);
695 evar->info = NULL;
696 }
697 }
698
699 static inline struct psi_ffi_context *psi_ffi_context_init(struct psi_ffi_context *L) {
700 ffi_status rc;
701
702 if (!L) {
703 L = malloc(sizeof(*L));
704 }
705 memset(L, 0, sizeof(*L));
706
707 L->params[0] = &ffi_type_pointer;
708 L->params[1] = &ffi_type_pointer;
709 rc = ffi_prep_cif(&L->signature, FFI_DEFAULT_ABI, 2, &ffi_type_void, L->params);
710 assert(rc == FFI_OK);
711
712 return L;
713 }
714
715 static inline void psi_ffi_context_free(struct psi_ffi_context **L) {
716 if (*L) {
717 free(*L);
718 *L = NULL;
719 }
720 }
721
722 static void psi_ffi_init(struct psi_context *C)
723 {
724 C->context = psi_ffi_context_init(NULL);
725 }
726
727 static void psi_ffi_dtor(struct psi_context *C)
728 {
729 if (C->decls) {
730 size_t i = 0;
731 struct psi_decl *decl;
732
733 while (psi_plist_get(C->decls, i++, &decl)) {
734 psi_ffi_decl_dtor(decl);
735 }
736
737 }
738 if (C->vars) {
739 size_t i = 0;
740 struct psi_decl_extvar *evar;
741
742 while (psi_plist_get(C->vars, i++, &evar)) {
743 psi_ffi_extvar_dtor(evar);
744 }
745 }
746 if (C->impls) {
747 size_t i = 0;
748 struct psi_impl *impl;
749
750 while (psi_plist_get(C->impls, i++, &impl)) {
751 psi_ffi_impl_dtor(impl);
752 }
753 }
754 psi_ffi_context_free((void *) &C->context);
755 }
756
757
758 static zend_function_entry *psi_ffi_compile(struct psi_context *C)
759 {
760 size_t i = 0, d = 0, v = 0, nf = 0;
761 struct psi_impl *impl;
762 struct psi_decl *decl;
763 struct psi_decl_extvar *evar;
764 zend_function_entry *zfe = NULL;
765
766 while (psi_plist_get(C->vars, v++, &evar)) {
767 if (FFI_OK == psi_ffi_extvar_init(evar)) {
768 /* */
769 }
770 }
771
772 if (C->impls) {
773 zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
774
775 while (psi_plist_get(C->impls, i++, &impl)) {
776 zend_function_entry *zf = &zfe[nf];
777
778 if (!impl->decl) {
779 continue;
780 }
781 if (!psi_ffi_decl_init(impl->decl)) {
782 continue;
783 }
784 if (!psi_ffi_impl_init(impl, C)) {
785 continue;
786 }
787
788 zf->fname = impl->func->name->val + (impl->func->name->val[0] == '\\');
789 zf->handler = ((struct psi_ffi_impl_info *) impl->info)->code;
790 zf->num_args = psi_plist_count(impl->func->args);
791 zf->arg_info = psi_internal_arginfo(impl);
792 ++nf;
793 }
794 }
795
796 while (psi_plist_get(C->decls, d++, &decl)) {
797 if (decl->info) {
798 continue;
799 }
800
801 psi_ffi_decl_init(decl);
802 }
803
804 return zfe;
805 }
806
807 static inline void psi_ffi_call_ex(struct psi_call_frame *frame) {
808 struct psi_decl *decl = psi_call_frame_get_decl(frame);
809 struct psi_impl *impl = psi_call_frame_get_impl(frame);
810 struct psi_ffi_decl_info *decl_info = decl->info;
811 struct psi_ffi_impl_info *impl_info;
812 struct psi_call_frame *prev;
813
814 if (impl) {
815 impl_info = impl->info;
816 prev = impl_info->frame;
817 impl_info->frame = frame;
818 }
819 ffi_call(&decl_info->signature, FFI_FN(decl->sym),
820 psi_call_frame_get_rpointer(frame),
821 psi_call_frame_get_arg_pointers(frame));
822 if (impl) {
823 impl_info->frame = prev;
824 }
825 }
826
827 static inline void psi_ffi_call_va(struct psi_call_frame *frame) {
828 ffi_cif signature;
829 struct psi_call_frame *prev;
830 struct psi_decl *decl = psi_call_frame_get_decl(frame);
831 struct psi_impl *impl = psi_call_frame_get_impl(frame);
832 struct psi_ffi_decl_info *decl_info = decl->info;
833 struct psi_ffi_impl_info *impl_info;
834 size_t i, va_count, argc;
835 ffi_type **param_types;
836
837 argc = psi_plist_count(decl->args);
838 va_count = psi_call_frame_num_var_args(frame);
839 param_types = ecalloc(argc + va_count + 1, sizeof(ffi_type *));
840 memcpy(param_types, decl_info->params, argc * sizeof(ffi_type *));
841 for (i = 0; i < va_count; ++i) {
842 struct psi_call_frame_argument *frame_arg;
843
844 frame_arg = psi_call_frame_get_var_argument(frame, i);
845 param_types[argc + i] = psi_ffi_impl_type(frame_arg->va_type);
846 }
847
848 psi_ffi_prep_va(&decl_info->signature, &signature, argc, va_count, param_types);
849
850 if (impl) {
851 impl_info = impl->info;
852 prev = impl_info->frame;
853 impl_info->frame = frame;
854 }
855 ffi_call(&signature, FFI_FN(decl->sym),
856 psi_call_frame_get_rpointer(frame),
857 psi_call_frame_get_arg_pointers(frame));
858 if (impl) {
859 impl_info->frame = prev;
860 }
861
862 efree(param_types);
863 }
864
865 static void psi_ffi_call(struct psi_call_frame *frame) {
866 if (psi_call_frame_num_var_args(frame)) {
867 psi_ffi_call_va(frame);
868 } else {
869 psi_ffi_call_ex(frame);
870 }
871 }
872
873 static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void *arg) {
874 switch (q) {
875 case PSI_CONTEXT_QUERY_SELF:
876 return "ffi";
877 case PSI_CONTEXT_QUERY_TYPE:
878 return psi_ffi_impl_type(*(token_t *) arg);
879 }
880 return NULL;
881 }
882
883 static ZEND_RESULT_CODE psi_ffi_load()
884 {
885 #if HAVE_INT128
886 ffi_type *i128, *u128;
887
888 i128 = calloc(1, 3*sizeof(ffi_type));
889 i128->type = FFI_TYPE_STRUCT;
890 i128->size = 0;
891 i128->elements = (ffi_type **) (i128 + 1);
892 i128->elements[0] = &ffi_type_sint64;
893 i128->elements[1] = &ffi_type_sint64;
894
895 ffi_type_sint128 = i128;
896
897 u128 = calloc(1, 3*sizeof(ffi_type));
898 u128->type = FFI_TYPE_STRUCT;
899 u128->size = 0;
900 u128->elements = (ffi_type **) (u128 + 1);
901 u128->elements[0] = &ffi_type_uint64;
902 u128->elements[1] = &ffi_type_uint64;
903
904 ffi_type_uint128 = u128;
905 #endif
906 return SUCCESS;
907 }
908
909 static void psi_ffi_free()
910 {
911 #if HAVE_INT128
912 free(ffi_type_sint128);
913 free(ffi_type_uint128);
914 #endif
915 }
916
917 static struct psi_context_ops ops = {
918 psi_ffi_load,
919 psi_ffi_free,
920 psi_ffi_init,
921 psi_ffi_dtor,
922 psi_ffi_compile,
923 psi_ffi_call,
924 psi_ffi_query,
925 };
926
927 struct psi_context_ops *psi_libffi_ops(void)
928 {
929 return &ops;
930 }
931
932 #endif /* HAVE_LIBFFI */