libffi
[m6w6/ext-psi] / src / libffi.c
1 #include "php.h"
2 #include "php_psi.h"
3 #include "libffi.h"
4
5 #include <ffi.h>
6
7 static void handler(ffi_cif *signature, void *_result, void **_args, void *_data);
8
9 static inline ffi_abi psi_ffi_abi(const char *convention) {
10 return FFI_DEFAULT_ABI;
11 }
12 static inline ffi_type *psi_ffi_type(token_t t) {
13 switch (t) {
14 default:
15 ZEND_ASSERT(0);
16 /* no break */
17 case PSI_T_VOID:
18 return &ffi_type_void;
19 case PSI_T_SINT8:
20 return &ffi_type_sint8;
21 case PSI_T_UINT8:
22 return &ffi_type_uint8;
23 case PSI_T_SINT16:
24 return &ffi_type_sint16;
25 case PSI_T_UINT16:
26 return &ffi_type_uint16;
27 case PSI_T_SINT32:
28 return &ffi_type_sint32;
29 case PSI_T_UINT32:
30 return &ffi_type_uint32;
31 case PSI_T_SINT64:
32 return &ffi_type_sint64;
33 case PSI_T_UINT64:
34 return &ffi_type_uint64;
35 case PSI_T_BOOL:
36 return &ffi_type_uchar;
37 case PSI_T_CHAR:
38 return &ffi_type_schar;
39 case PSI_T_SHORT:
40 return &ffi_type_sshort;
41 case PSI_T_INT:
42 return &ffi_type_sint;
43 case PSI_T_LONG:
44 return &ffi_type_slong;
45 case PSI_T_FLOAT:
46 return &ffi_type_float;
47 case PSI_T_DOUBLE:
48 return &ffi_type_double;
49 }
50 }
51 static inline ffi_type *psi_ffi_decl_type(decl_type *type) {
52 return psi_ffi_type(real_decl_type(type)->type);
53 }
54 static inline ffi_type *psi_ffi_decl_arg_type(decl_arg *darg) {
55 if (darg->var->pointer_level) {
56 return &ffi_type_pointer;
57 } else {
58 return psi_ffi_decl_type(darg->type);
59 }
60 }
61
62 typedef struct PSI_LibffiContext {
63 ffi_cif signature;
64 ffi_type *params[2];
65 struct {
66 struct PSI_LibffiData **list;
67 size_t count;
68 } data;
69 } PSI_LibffiContext;
70
71 typedef struct PSI_LibffiData {
72 PSI_LibffiContext *context;
73 impl *impl;
74 zend_internal_arg_info *arginfo;
75 void *code;
76 ffi_closure *closure;
77 ffi_cif signature;
78 ffi_type *params[1];
79 } PSI_LibffiData;
80
81 static inline PSI_LibffiData *PSI_LibffiDataAlloc(PSI_LibffiContext *context, impl *impl) {
82 ffi_status rc;
83 size_t i, c = impl->decl->args->count;
84 PSI_LibffiData *data = malloc(sizeof(*data) + c * sizeof(ffi_type *));
85
86 data->context = context;
87 data->impl = impl;
88 data->arginfo = psi_internal_arginfo(impl);
89 for (i = 0; i < c; ++i) {
90 data->params[i] = psi_ffi_decl_arg_type(impl->decl->args->args[i]);
91 }
92 data->params[c] = NULL;
93
94 rc = ffi_prep_cif(
95 &data->signature,
96 psi_ffi_abi(data->impl->decl->abi->convention),
97 c,
98 psi_ffi_decl_arg_type(data->impl->decl->func),
99 data->params);
100 ZEND_ASSERT(FFI_OK == rc);
101 data->closure = ffi_closure_alloc(sizeof(ffi_closure), &data->code);
102 rc = ffi_prep_closure_loc(
103 data->closure,
104 &context->signature,
105 handler,
106 data,
107 data->code);
108 ZEND_ASSERT(FFI_OK == rc);
109
110 context->data.list = realloc(context->data.list, ++context->data.count * sizeof(*context->data.list));
111 context->data.list[context->data.count-1] = data;
112
113 return data;
114 }
115
116 static inline void PSI_LibffiDataFree(PSI_LibffiData *data) {
117 free(data->arginfo);
118 ffi_closure_free(data->closure);
119 free(data);
120 }
121
122 static inline PSI_LibffiContext *PSI_LibffiContextInit(PSI_LibffiContext *L) {
123 ffi_status rc;
124
125 if (!L) {
126 L = malloc(sizeof(*L));
127 }
128 memset(L, 0, sizeof(*L));
129
130 L->params[0] = &ffi_type_pointer;
131 L->params[1] = &ffi_type_pointer;
132 rc = ffi_prep_cif(&L->signature, FFI_DEFAULT_ABI, 2, &ffi_type_void, L->params);
133 ZEND_ASSERT(rc == FFI_OK);
134
135 return L;
136 }
137
138 static inline void PSI_LibffiContextDtor(PSI_LibffiContext *L) {
139 size_t i;
140
141 for (i = 0; i < L->data.count; ++i) {
142 PSI_LibffiDataFree(L->data.list[i]);
143 }
144 if (L->data.list) {
145 free(L->data.list);
146 }
147 }
148
149 static inline void PSI_LibffiContextFree(PSI_LibffiContext **L) {
150 if (*L) {
151 PSI_LibffiContextDtor(*L);
152 free(*L);
153 *L = NULL;
154 }
155 }
156
157 static void handler(ffi_cif *_sig, void *_result, void **_args, void *_data)
158 {
159 PSI_LibffiData *data = _data;
160 size_t i;
161 void **arg_ptr = NULL, **arg_prm = NULL;
162 impl_val ret_val;
163
164 if (SUCCESS != psi_parse_args(*(zend_execute_data **)_args[0], data->impl)) {
165 return;
166 }
167
168 if (data->impl->decl->args->count) {
169 arg_ptr = malloc(data->impl->decl->args->count * sizeof(*arg_ptr));
170 arg_prm = malloc(data->impl->decl->args->count * sizeof(*arg_prm));
171
172 for (i = 0; i < data->impl->decl->args->count; ++i) {
173 decl_arg *darg = data->impl->decl->args->args[i];
174
175 arg_ptr[i] = psi_do_let(darg);
176 arg_prm[i] = darg->let->val->is_reference ? &arg_ptr[i] : arg_ptr[i];
177
178 darg->let->ptr = arg_ptr[i];
179 }
180 }
181
182 ffi_call(&data->signature, FFI_FN(data->impl->decl->dlptr), &ret_val, arg_prm);
183
184 psi_do_return(data->impl, &ret_val, *(zval **)_args[1]);
185
186 for (i = 0; i < data->impl->stmts->set.count; ++i) {
187 set_stmt *set = data->impl->stmts->set.list[i];
188
189 psi_do_set(set->arg->_zv, set->val->func, set->val->vars);
190 }
191
192 for (i = 0; i < data->impl->stmts->fre.count; ++i) {
193 free_stmt *fre = data->impl->stmts->fre.list[i];
194
195 psi_do_free(fre);
196 }
197
198 psi_do_clean(data->impl);
199
200 if (arg_ptr) {
201 free(arg_ptr);
202 }
203 if (arg_prm) {
204 free(arg_prm);
205 }
206 }
207
208 static void init(PSI_Context *C)
209 {
210 C->context = PSI_LibffiContextInit(NULL);
211 }
212
213 static void dtor(PSI_Context *C)
214 {
215 PSI_LibffiContextFree((void *) &C->context);
216 }
217
218 static zend_function_entry *compile(PSI_Context *C, PSI_Data *D)
219 {
220 size_t i, j = 0;
221 zend_function_entry *zfe = calloc(D->impls->count + 1, sizeof(*zfe));
222 PSI_LibffiContext *ctx = C->context;
223
224 for (i = 0; i < D->impls->count; ++i) {
225 zend_function_entry *zf = &zfe[j];
226 PSI_LibffiData *data;
227
228 if (!D->impls->list[i]->decl) {
229 continue;
230 }
231
232 data = PSI_LibffiDataAlloc(ctx, D->impls->list[i]);
233 zf->fname = D->impls->list[i]->func->name + (D->impls->list[i]->func->name[0] == '\\');
234 zf->num_args = D->impls->list[i]->func->args->count;
235 zf->handler = data->code;
236 zf->arg_info = data->arginfo;
237 ++j;
238 }
239
240 return zfe;
241 }
242
243 static PSI_ContextOps ops = {
244 init,
245 dtor,
246 compile,
247 };
248
249 PSI_ContextOps *PSI_Libffi(void)
250 {
251 return &ops;
252 }