administrativa
[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 = pemalloc(sizeof(*pad), 1);
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;
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 = pemalloc(sizeof(*type), 1);
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 s->els = safe_perealloc(s->els, (s->argc + 1), sizeof(*s->els), 0, 1);
264 s->els[s->argc] = NULL;
265 }
266 psi_ffi_struct_type_pad(&s->els[s->nels], padding);
267 s->nels += padding;
268 s->offset += padding;
269 }
270 assert(s->offset == darg->layout->pos);
271
272 s->offset = (s->offset + darg->layout->len + type->alignment - 1) & ~(type->alignment - 1);
273 s->els[s->nels++] = type;
274 }
275
276 static ffi_type **psi_ffi_struct_type_elements(struct psi_decl_struct *strct) {
277 size_t i = 0;
278 struct psi_decl_arg *darg;
279 struct psi_ffi_struct_element_storage s = {0};
280
281 s.last_arg_pos = -1;
282 s.argc = psi_plist_count(strct->args);
283 s.els = pecalloc(s.argc + 1, sizeof(*s.els), 1);
284
285 while (psi_plist_get(strct->args, i++, &darg)) {
286 psi_ffi_struct_type_element(&s, darg, psi_ffi_decl_arg_type(darg));
287 }
288
289 /* apply struct alignment padding */
290 s.offset = (s.offset + s.max_align - 1) & ~(s.max_align - 1);
291
292 assert(s.offset <= strct->size);
293 if (s.offset < strct->size) { /* WTF? */
294 size_t padding = strct->size - s.offset;
295
296 s.els = safe_perealloc(s.els, (padding + s.argc + 1), sizeof(*s.els), 0, 1);
297 psi_ffi_struct_type_pad(&s.els[s.nels], padding);
298 s.els[s.argc + padding] = NULL;
299 }
300
301 return s.els;
302 }
303
304 static inline ffi_type *psi_ffi_decl_type(struct psi_decl_type *type) {
305 struct psi_decl_type *real = psi_decl_type_get_real(type);
306
307 if (real != type && type->real.def->var->pointer_level) {
308 return &ffi_type_pointer;
309 }
310
311 switch (real->type) {
312 case PSI_T_STRUCT:
313 if (!real->real.strct->engine.type) {
314 ffi_type *strct = pecalloc(1, sizeof(ffi_type), 1);
315
316 strct->type = FFI_TYPE_STRUCT;
317 strct->size = 0;
318 strct->elements = psi_ffi_struct_type_elements(real->real.strct);
319
320 real->real.strct->engine.type = strct;
321 real->real.strct->engine.dtor = psi_ffi_type_dtor;
322 }
323
324 return real->real.strct->engine.type;
325
326 case PSI_T_UNION:
327 {
328 struct psi_decl_arg *arg;
329 psi_plist_get(real->real.unn->args, 0, &arg);
330 return psi_ffi_decl_arg_type(arg);
331 }
332
333 default:
334 break;
335 }
336
337 return psi_ffi_token_type(real->type);
338 }
339
340 static inline ffi_type *psi_ffi_decl_func_array_type(struct psi_decl *fn) {
341 struct psi_ffi_decl_info *info = fn->info;
342 struct psi_ffi_struct_element_storage s = {0};
343 struct psi_layout l;
344 ffi_type *type;
345 size_t i;
346
347 if (info->rv_array) {
348 return info->rv_array;
349 }
350
351 s.last_arg_pos = -1;
352 s.argc = fn->func->var->array_size;
353 s.els = pecalloc(s.argc + 1, sizeof(*s.els), 1);
354
355 info->rv_array = pecalloc(1, sizeof(ffi_type), 1);
356 info->rv_array->type = FFI_TYPE_STRUCT;
357 info->rv_array->size = 0;
358 info->rv_array->elements = s.els;
359
360 l.pos = 0;
361 if (fn->func->var->pointer_level > 1) {
362 l.len = SIZEOF_VOID_P;
363 type = &ffi_type_pointer;
364 } else {
365 l.len = psi_decl_type_get_size(fn->func->type, NULL);
366 type = psi_ffi_decl_type(fn->func->type);
367 }
368
369 assert(!fn->func->layout);
370 fn->func->layout = &l;
371 for (i = 0; i < fn->func->var->array_size; ++i) {
372 psi_ffi_struct_type_element(&s, fn->func, type);
373 info->rv_array->elements = s.els;
374 l.pos += l.len;
375 }
376 fn->func->layout = NULL;
377
378 return info->rv_array;
379 }
380
381 static inline ffi_type *psi_ffi_decl_arg_type(struct psi_decl_arg *darg) {
382 if (darg->var->pointer_level) {
383 return &ffi_type_pointer;
384 } else {
385 return psi_ffi_decl_type(darg->type);
386 }
387 }
388
389 static inline ffi_type *psi_ffi_decl_func_type(struct psi_decl *fn) {
390 struct psi_decl_arg *darg = fn->func;
391
392 if (darg->var->pointer_level) {
393 if (darg->var->array_size) {
394 /* mimic a struct resembling the array return type of fn */
395 return psi_ffi_decl_func_array_type(fn);
396 }
397 return &ffi_type_pointer;
398 } else {
399 return psi_ffi_decl_type(darg->type);
400 }
401 }
402
403 static inline ffi_abi psi_ffi_abi(zend_string *convention) {
404 if (FFI_LAST_ABI - 2 != FFI_FIRST_ABI) {
405 #ifdef HAVE_FFI_STDCALL
406 if (zend_string_equals_literal(convention, "stdcall")) {
407 return FFI_STDCALL;
408 }
409 #endif
410 #ifdef HAVE_FFI_FASTCALL
411 if (zend_string_equals_literal(convention, "fastcall")) {
412 return FFI_FASTCALL;
413 }
414 #endif
415 }
416 return FFI_DEFAULT_ABI;
417 }
418
419 static inline struct psi_ffi_decl_info *psi_ffi_decl_init(struct psi_decl *decl) {
420 if (!decl->info) {
421 int rc;
422 size_t i, c = psi_plist_count(decl->args);
423 struct psi_decl_arg *arg;
424 struct psi_ffi_decl_info *info = pecalloc(1, sizeof(*info) + 2 * c * sizeof(void *), 1);
425
426 decl->info = info;
427
428 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
429 info->params[i] = psi_ffi_decl_arg_type(arg);
430 }
431 info->params[c] = NULL;
432
433 rc = ffi_prep_cif(&info->signature, psi_ffi_abi(decl->abi->convention),
434 c, psi_ffi_decl_func_type(decl), info->params);
435
436 if (FFI_OK != rc) {
437 free(info);
438 decl->info = NULL;
439 }
440 }
441
442 return decl->info;
443 }
444
445 static inline void psi_ffi_decl_dtor(struct psi_decl *decl) {
446 if (decl->info) {
447 struct psi_ffi_decl_info *info = decl->info;
448
449 if (info->rv_array) {
450 psi_ffi_type_dtor(info->rv_array);
451 }
452 free(decl->info);
453 decl->info = NULL;
454 }
455 }
456
457 static void psi_ffi_handler(ffi_cif *sig, void *result, void **args, void *data)
458 {
459 struct psi_impl *impl = data;
460 struct psi_ffi_impl_info *info = impl->info;
461
462 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **)args[1], impl);
463 }
464
465 static void psi_ffi_callback(ffi_cif *sig, void *result, void **args, void *data)
466 {
467 struct psi_ffi_callback_info *cb_info = data;
468 struct psi_call_frame_callback cb_data;
469
470 assert(cb_info->impl_info->frame);
471
472 cb_data.cb = cb_info->let_exp;
473 cb_data.argc = sig->nargs;
474 cb_data.argv = args;
475 cb_data.rval = result;
476
477 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
478 }
479
480 static inline void psi_ffi_callback_init(struct psi_ffi_impl_info *impl_info,
481 struct psi_let_exp *let_exp) {
482 struct psi_ffi_callback_info *cb_info;
483 struct psi_ffi_decl_info *decl_info;
484 struct psi_let_callback *cb;
485 struct psi_let_func *fn = NULL;
486 ffi_status rc;
487
488 switch (let_exp->kind) {
489 case PSI_LET_CALLBACK:
490 cb = let_exp->data.callback;
491 if (cb->decl->info) {
492 decl_info = cb->decl->info;
493 } else {
494 decl_info = psi_ffi_decl_init(cb->decl);
495 }
496
497 cb_info = pecalloc(1, sizeof(*cb_info), 1);
498 cb_info->impl_info = impl_info;
499 cb_info->let_exp = let_exp;
500 rc = psi_ffi_prep_closure(&cb_info->closure, &cb_info->code,
501 &decl_info->signature, psi_ffi_callback, cb_info);
502
503 if (FFI_OK != rc) {
504 free(cb_info);
505 break;
506 }
507 cb->info = cb_info;
508
509 assert(!cb->decl->sym);
510 cb->decl->sym = cb_info->code;
511 fn = cb->func;
512 /* no break */
513
514 case PSI_LET_FUNC:
515 if (!fn) {
516 fn = let_exp->data.func;
517 }
518 if (fn->inner) {
519 size_t i = 0;
520 struct psi_let_exp *inner_let;
521
522 while (psi_plist_get(fn->inner, i++, &inner_let)) {
523 psi_ffi_callback_init(impl_info, inner_let);
524 }
525 }
526 break;
527 default:
528 break;
529 }
530 }
531
532 static inline void psi_ffi_callback_dtor(struct psi_let_exp *let_exp) {
533 struct psi_let_callback *cb;
534 struct psi_let_func *fn = NULL;
535
536 switch (let_exp->kind) {
537 case PSI_LET_CALLBACK:
538 cb = let_exp->data.callback;
539
540 psi_ffi_decl_dtor(cb->decl);
541
542 if (cb->info) {
543 struct psi_ffi_callback_info *info = cb->info;
544
545 if (info->closure) {
546 psi_ffi_closure_free(info->closure);
547 }
548 free(info);
549 cb->info = NULL;
550 }
551 fn = cb->func;
552 /* no break */
553 case PSI_LET_FUNC:
554 if (!fn) {
555 fn = let_exp->data.func;
556 }
557
558 if (fn->inner) {
559 size_t i = 0;
560 struct psi_let_exp *cb;
561
562 while (psi_plist_get(fn->inner, i++, &cb)) {
563 psi_ffi_callback_dtor(cb);
564 }
565 }
566 break;
567 default:
568 break;
569 }
570 }
571
572 static inline struct psi_ffi_impl_info *psi_ffi_impl_init(struct psi_impl *impl,
573 struct psi_context *C) {
574 struct psi_ffi_context *context = C->context;
575 struct psi_ffi_impl_info *info = pecalloc(1, sizeof(*info), 1);
576 struct psi_let_stmt *let;
577 ffi_status rc;
578 size_t l = 0;
579
580 info->context = C;
581
582 rc = psi_ffi_prep_closure(&info->closure, &info->code,
583 &context->signature, psi_ffi_handler, impl);
584
585 if (FFI_OK != rc) {
586 free(info);
587 return NULL;
588 }
589
590 while (psi_plist_get(impl->stmts.let, l++, &let)) {
591 psi_ffi_callback_init(info, let->exp);
592 }
593
594 return impl->info = info;
595 }
596
597 static inline void psi_ffi_impl_dtor(struct psi_impl *impl) {
598 struct psi_ffi_impl_info *info = impl->info;
599 struct psi_let_stmt *let;
600 size_t j = 0;
601
602 while (psi_plist_get(impl->stmts.let, j++, &let)) {
603 psi_ffi_callback_dtor(let->exp);
604 }
605
606 if (info) {
607 if (info->closure) {
608 psi_ffi_closure_free(info->closure);
609 }
610 free(info);
611 impl->info = NULL;
612 }
613 }
614
615 static void psi_ffi_extvar_get(ffi_cif *sig, void *result, void **args, void *data) {
616 struct psi_decl_extvar *evar = data;
617
618 psi_decl_extvar_get(evar, result);
619 }
620
621 static void psi_ffi_extvar_set(ffi_cif *sig, void *result, void **args, void *data) {
622 struct psi_decl_extvar *evar = data;
623
624 psi_decl_extvar_set(evar, args[0]);
625 }
626
627 struct psi_ffi_extvar_info {
628 struct {
629 ffi_cif signature;
630 void *code;
631 ffi_closure *closure;
632 } get;
633 struct {
634 ffi_cif signature;
635 ffi_type *params[1];
636 void *code;
637 ffi_closure *closure;
638 } set;
639 };
640
641 static inline ffi_status psi_ffi_extvar_init(struct psi_decl_extvar *evar) {
642 struct psi_ffi_extvar_info *info = pecalloc(1, sizeof(*info), 1);
643 ffi_status rc;
644
645 evar->info = info;
646
647 psi_ffi_decl_init(evar->getter);
648 psi_ffi_decl_init(evar->setter);
649
650 rc = ffi_prep_cif(&info->get.signature, FFI_DEFAULT_ABI, 0,
651 psi_ffi_decl_func_type(evar->getter), NULL);
652 if (FFI_OK != rc) {
653 return rc;
654 }
655 rc = psi_ffi_prep_closure(&info->get.closure, &info->get.code,
656 &info->get.signature, psi_ffi_extvar_get, evar);
657 if (FFI_OK != rc) {
658 return rc;
659 }
660
661 info->set.params[0] = psi_ffi_decl_arg_type(evar->arg);
662 rc = ffi_prep_cif(&info->set.signature, FFI_DEFAULT_ABI, 1,
663 &ffi_type_void, info->set.params);
664 if (FFI_OK != rc) {
665 return rc;
666 }
667 rc = psi_ffi_prep_closure(&info->set.closure, &info->set.code,
668 &info->set.signature, psi_ffi_extvar_set, evar);
669 if (FFI_OK != rc) {
670 return rc;
671 }
672
673 evar->getter->sym = info->get.code;
674 evar->setter->sym = info->set.code;
675
676 return FFI_OK;
677 }
678
679 static inline void psi_ffi_extvar_dtor(struct psi_decl_extvar *evar) {
680 if (evar->info) {
681 free(evar->info);
682 evar->info = NULL;
683 }
684 }
685
686 static inline struct psi_ffi_context *psi_ffi_context_init(struct psi_ffi_context *L) {
687 ffi_status rc;
688
689 if (!L) {
690 L = pemalloc(sizeof(*L), 1);
691 }
692 memset(L, 0, sizeof(*L));
693
694 L->params[0] = &ffi_type_pointer;
695 L->params[1] = &ffi_type_pointer;
696 rc = ffi_prep_cif(&L->signature, FFI_DEFAULT_ABI, 2, &ffi_type_void, L->params);
697 assert(rc == FFI_OK);
698
699 return L;
700 }
701
702 static inline void psi_ffi_context_free(struct psi_ffi_context **L) {
703 if (*L) {
704 free(*L);
705 *L = NULL;
706 }
707 }
708
709 static void psi_ffi_init(struct psi_context *C)
710 {
711 C->context = psi_ffi_context_init(NULL);
712 }
713
714 static void psi_ffi_dtor(struct psi_context *C)
715 {
716 if (C->decls) {
717 size_t i = 0;
718 struct psi_decl *decl;
719
720 while (psi_plist_get(C->decls, i++, &decl)) {
721 psi_ffi_decl_dtor(decl);
722 }
723
724 }
725 if (C->vars) {
726 size_t i = 0;
727 struct psi_decl_extvar *evar;
728
729 while (psi_plist_get(C->vars, i++, &evar)) {
730 psi_ffi_extvar_dtor(evar);
731 }
732 }
733 if (C->impls) {
734 size_t i = 0;
735 struct psi_impl *impl;
736
737 while (psi_plist_get(C->impls, i++, &impl)) {
738 psi_ffi_impl_dtor(impl);
739 }
740 }
741 psi_ffi_context_free((void *) &C->context);
742 }
743
744
745 static zend_function_entry *psi_ffi_compile(struct psi_context *C)
746 {
747 size_t i = 0, d = 0, v = 0, nf = 0;
748 struct psi_impl *impl;
749 struct psi_decl *decl;
750 struct psi_decl_extvar *evar;
751 zend_function_entry *zfe = NULL;
752
753 while (psi_plist_get(C->vars, v++, &evar)) {
754 if (FFI_OK == psi_ffi_extvar_init(evar)) {
755 /* */
756 }
757 }
758
759 if (C->impls) {
760 zfe = pecalloc(psi_plist_count(C->impls) + 1, sizeof(*zfe), 1);
761
762 while (psi_plist_get(C->impls, i++, &impl)) {
763 zend_function_entry *zf = &zfe[nf];
764
765 if (!impl->decl) {
766 continue;
767 }
768 if (!psi_ffi_decl_init(impl->decl)) {
769 continue;
770 }
771 if (!psi_ffi_impl_init(impl, C)) {
772 continue;
773 }
774
775 zf->fname = impl->func->name->val + (impl->func->name->val[0] == '\\');
776 zf->handler = ((struct psi_ffi_impl_info *) impl->info)->code;
777 zf->num_args = psi_plist_count(impl->func->args);
778 zf->arg_info = psi_internal_arginfo(impl);
779 ++nf;
780 }
781 }
782
783 while (psi_plist_get(C->decls, d++, &decl)) {
784 if (decl->info) {
785 continue;
786 }
787
788 psi_ffi_decl_init(decl);
789 }
790
791 return zfe;
792 }
793
794 static inline void psi_ffi_call_ex(struct psi_call_frame *frame) {
795 struct psi_decl *decl = psi_call_frame_get_decl(frame);
796 struct psi_impl *impl = psi_call_frame_get_impl(frame);
797 struct psi_ffi_decl_info *decl_info = decl->info;
798 struct psi_ffi_impl_info *impl_info;
799 struct psi_call_frame *prev;
800
801 if (impl) {
802 impl_info = impl->info;
803 prev = impl_info->frame;
804 impl_info->frame = frame;
805 }
806 ffi_call(&decl_info->signature, FFI_FN(decl->sym),
807 psi_call_frame_get_rpointer(frame),
808 psi_call_frame_get_arg_pointers(frame));
809 if (impl) {
810 impl_info->frame = prev;
811 }
812 }
813
814 static inline void psi_ffi_call_va(struct psi_call_frame *frame) {
815 ffi_cif signature;
816 struct psi_call_frame *prev;
817 struct psi_decl *decl = psi_call_frame_get_decl(frame);
818 struct psi_impl *impl = psi_call_frame_get_impl(frame);
819 struct psi_ffi_decl_info *decl_info = decl->info;
820 struct psi_ffi_impl_info *impl_info;
821 size_t i, va_count, argc;
822 ffi_type **param_types;
823
824 argc = psi_plist_count(decl->args);
825 va_count = psi_call_frame_num_var_args(frame);
826 param_types = ecalloc(argc + va_count + 1, sizeof(ffi_type *));
827 memcpy(param_types, decl_info->params, argc * sizeof(ffi_type *));
828 for (i = 0; i < va_count; ++i) {
829 struct psi_call_frame_argument *frame_arg;
830
831 frame_arg = psi_call_frame_get_var_argument(frame, i);
832 param_types[argc + i] = psi_ffi_impl_type(frame_arg->va_type);
833 }
834
835 psi_ffi_prep_va(&decl_info->signature, &signature, argc, va_count, param_types);
836
837 if (impl) {
838 impl_info = impl->info;
839 prev = impl_info->frame;
840 impl_info->frame = frame;
841 }
842 ffi_call(&signature, FFI_FN(decl->sym),
843 psi_call_frame_get_rpointer(frame),
844 psi_call_frame_get_arg_pointers(frame));
845 if (impl) {
846 impl_info->frame = prev;
847 }
848
849 efree(param_types);
850 }
851
852 static void psi_ffi_call(struct psi_call_frame *frame) {
853 if (psi_call_frame_num_var_args(frame)) {
854 psi_ffi_call_va(frame);
855 } else {
856 psi_ffi_call_ex(frame);
857 }
858 }
859
860 static void *psi_ffi_query(struct psi_context *C, enum psi_context_query q, void *arg) {
861 switch (q) {
862 case PSI_CONTEXT_QUERY_SELF:
863 return "ffi";
864 case PSI_CONTEXT_QUERY_TYPE:
865 return psi_ffi_impl_type(*(token_t *) arg);
866 }
867 return NULL;
868 }
869
870 static ZEND_RESULT_CODE psi_ffi_load()
871 {
872 #if HAVE_INT128
873 ffi_type *i128, *u128;
874
875 i128 = pecalloc(1, 3*sizeof(ffi_type), 1);
876 i128->type = FFI_TYPE_STRUCT;
877 i128->size = 0;
878 i128->elements = (ffi_type **) (i128 + 1);
879 i128->elements[0] = &ffi_type_sint64;
880 i128->elements[1] = &ffi_type_sint64;
881
882 ffi_type_sint128 = i128;
883
884 u128 = pecalloc(1, 3*sizeof(ffi_type), 1);
885 u128->type = FFI_TYPE_STRUCT;
886 u128->size = 0;
887 u128->elements = (ffi_type **) (u128 + 1);
888 u128->elements[0] = &ffi_type_uint64;
889 u128->elements[1] = &ffi_type_uint64;
890
891 ffi_type_uint128 = u128;
892 #endif
893 return SUCCESS;
894 }
895
896 static void psi_ffi_free()
897 {
898 #if HAVE_INT128
899 free(ffi_type_sint128);
900 free(ffi_type_uint128);
901 #endif
902 }
903
904 static struct psi_context_ops ops = {
905 psi_ffi_load,
906 psi_ffi_free,
907 psi_ffi_init,
908 psi_ffi_dtor,
909 psi_ffi_compile,
910 psi_ffi_call,
911 psi_ffi_query,
912 };
913
914 struct psi_context_ops *psi_libffi_ops(void)
915 {
916 return &ops;
917 }
918
919 #endif /* HAVE_LIBFFI */