types refactoring
[m6w6/ext-psi] / src / libjit.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #else
4 # include "php_config.h"
5 #endif
6
7 #include "php.h"
8
9 #ifdef HAVE_LIBJIT
10
11 #include "php_psi.h"
12 #include "libjit.h"
13 #include "engine.h"
14
15 #include <jit/jit.h>
16
17 static void psi_jit_handler(jit_type_t _sig, void *_result, void **_args, void *_data)
18 {
19 psi_call(*(zend_execute_data **)_args[0], *(zval **)_args[1], _data);
20 }
21
22 static void psi_jit_callback(jit_type_t _sig, void *_result, void **_args, void *_data)
23 {
24 psi_callback(_data, _result, jit_type_num_params(_sig), _args);
25 }
26
27 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg);
28
29 static inline jit_abi_t psi_jit_abi(const char *convention) {
30 return jit_abi_cdecl;
31 }
32 static inline jit_type_t psi_jit_token_type(token_t t) {
33 switch (t) {
34 default:
35 ZEND_ASSERT(0);
36 /* no break */
37 case PSI_T_VOID:
38 return jit_type_void;
39 case PSI_T_INT8:
40 return jit_type_sbyte;
41 case PSI_T_UINT8:
42 return jit_type_ubyte;
43 case PSI_T_INT16:
44 return jit_type_short;
45 case PSI_T_UINT16:
46 return jit_type_ushort;
47 case PSI_T_INT32:
48 return jit_type_int;
49 case PSI_T_UINT32:
50 return jit_type_uint;
51 case PSI_T_INT64:
52 return jit_type_long;
53 case PSI_T_UINT64:
54 return jit_type_ulong;
55 case PSI_T_BOOL:
56 return jit_type_sys_bool;
57 case PSI_T_INT:
58 case PSI_T_ENUM:
59 return jit_type_sys_int;
60 case PSI_T_LONG:
61 return jit_type_sys_long;
62 case PSI_T_FLOAT:
63 return jit_type_sys_float;
64 case PSI_T_DOUBLE:
65 return jit_type_sys_double;
66 #ifdef HAVE_LONG_DOUBLE
67 case PSI_T_LONG_DOUBLE:
68 return jit_type_sys_long_double;
69 #endif
70 case PSI_T_POINTER:
71 case PSI_T_FUNCTION:
72 return jit_type_void_ptr;
73 }
74 }
75 static inline jit_type_t psi_jit_impl_type(token_t impl_type) {
76 switch (impl_type) {
77 case PSI_T_BOOL:
78 return jit_type_sbyte;
79 case PSI_T_INT:
80 return jit_type_long;
81 case PSI_T_STRING:
82 return jit_type_void_ptr;
83 case PSI_T_FLOAT:
84 case PSI_T_DOUBLE:
85 return jit_type_sys_double;
86 EMPTY_SWITCH_DEFAULT_CASE();
87 }
88 return NULL;
89 }
90
91 static void psi_jit_struct_type_dtor(void *type) {
92 jit_type_t strct = type;
93
94 jit_type_free(strct);
95 }
96
97 static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding) {
98 size_t i;
99
100 for (i = 0; i < padding; ++i) {
101 *els++ = jit_type_copy(jit_type_sys_char);
102 }
103
104 return padding;
105 }
106
107 static unsigned psi_jit_struct_type_elements(decl_struct *strct, jit_type_t **fields) {
108 size_t i, argc = strct->args->count, nels = 0, offset = 0, maxalign;
109 *fields = calloc(argc + 1, sizeof(*fields));
110
111 for (i = 0; i < strct->args->count; ++i) {
112 decl_arg *darg = strct->args->args[i];
113 jit_type_t type = jit_type_copy(psi_jit_decl_arg_type(darg));
114 size_t padding, alignment;
115
116 ZEND_ASSERT(jit_type_get_size(type) == darg->layout->len);
117
118 if ((alignment = jit_type_get_alignment(type)) > maxalign) {
119 maxalign = alignment;
120 }
121
122 if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
123 if (nels + padding > argc) {
124 argc += padding;
125 *fields = realloc(*fields, (argc + 1) * sizeof(*fields));
126 }
127 psi_jit_struct_type_pad(&(*fields)[nels], padding);
128 nels += padding;
129 offset += padding;
130 }
131 ZEND_ASSERT(offset == darg->layout->pos);
132
133 offset = (offset + darg->layout->len + alignment - 1) & ~(alignment - 1);
134 (*fields)[nels++] = type;
135 }
136
137 /* apply struct alignment padding */
138 offset = (offset + maxalign - 1) & ~(maxalign - 1);
139
140 ZEND_ASSERT(offset <= strct->size);
141 if (offset < strct->size) {
142 nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset);
143 }
144
145 return nels;
146 }
147 static inline jit_type_t psi_jit_decl_type(decl_type *type) {
148 decl_type *real = real_decl_type(type);
149
150 switch (real->type) {
151 case PSI_T_STRUCT:
152 if (!real->real.strct->engine.type) {
153 unsigned count;
154 jit_type_t strct, *fields = NULL;
155
156 count = psi_jit_struct_type_elements(real->real.strct, &fields);
157 strct = jit_type_create_struct(fields, count, 0);
158
159 real->real.strct->engine.type = strct;
160 real->real.strct->engine.dtor = psi_jit_struct_type_dtor;
161 }
162
163 return real->real.strct->engine.type;
164
165 case PSI_T_UNION:
166 return psi_jit_decl_arg_type(real->real.unn->args->args[0]);
167
168 default:
169 return psi_jit_token_type(real->type);
170 }
171 }
172 static inline jit_type_t psi_jit_decl_arg_type(decl_arg *darg) {
173 if (darg->var->pointer_level) {
174 return jit_type_void_ptr;
175 } else {
176 return psi_jit_decl_type(darg->type);
177 }
178 }
179
180 struct psi_jit_context {
181 jit_context_t jit;
182 jit_type_t signature;
183 struct {
184 struct psi_jit_data **list;
185 size_t count;
186 } data;
187 };
188
189 struct psi_jit_call {
190 void *closure;
191 jit_type_t signature;
192 void *params[1]; /* [type1, type2, NULL, arg1, arg2] ... */
193 };
194
195 struct psi_jit_data {
196 struct psi_jit_context *context;
197 impl *impl;
198 zend_internal_arg_info *arginfo;
199 };
200
201 static inline struct psi_jit_call *psi_jit_call_alloc(struct psi_context *C, decl *decl) {
202 size_t i, c = decl->args ? decl->args->count : 0;
203 struct psi_jit_call *call = calloc(1, sizeof(*call) + 2 * c * sizeof(void *));
204
205 for (i = 0; i < c; ++i) {
206 call->params[i] = psi_jit_decl_arg_type(decl->args->args[i]);
207 }
208 call->params[c] = NULL;
209
210 decl->call.info = call;
211 decl->call.rval = &decl->func->ptr;
212 decl->call.argc = c;
213 decl->call.args = (void **) &call->params[c+1];
214
215 call->signature = jit_type_create_signature(
216 psi_jit_abi(decl->abi->convention),
217 psi_jit_decl_arg_type(decl->func),
218 (jit_type_t *) call->params, c, 1);
219 ZEND_ASSERT(call->signature);
220
221 return call;
222 }
223
224 static inline void *psi_jit_call_init_closure(struct psi_context *C, struct psi_jit_call *call, impl *impl) {
225 struct psi_jit_context *context = C->context;
226 return call->closure = jit_closure_create(context->jit, context->signature,
227 &psi_jit_handler, impl);
228 }
229
230 static inline void *psi_jit_call_init_callback_closure(struct psi_context *C, struct psi_jit_call *call, let_callback *cb) {
231 struct psi_jit_context *context = C->context;
232 return call->closure = jit_closure_create(context->jit, call->signature,
233 &psi_jit_callback, cb);
234 }
235
236 static inline void psi_jit_call_free(struct psi_jit_call *call) {
237 jit_type_free(call->signature);
238 free(call);
239 }
240
241 static inline struct psi_jit_context *psi_jit_context_init(struct psi_jit_context *L) {
242 jit_type_t params[] = {
243 jit_type_void_ptr,
244 jit_type_void_ptr
245 };
246
247 if (!L) {
248 L = malloc(sizeof(*L));
249 }
250 memset(L, 0, sizeof(*L));
251
252 L->jit = jit_context_create();
253 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
254 params, 2, 1);
255
256 return L;
257 }
258
259 static inline void psi_jit_context_dtor(struct psi_jit_context *L) {
260 jit_type_free(L->signature);
261 jit_context_destroy(L->jit);
262 }
263
264 static inline void psi_jit_context_free(struct psi_jit_context **L) {
265 if (*L) {
266 psi_jit_context_dtor(*L);
267 free(*L);
268 *L = NULL;
269 }
270 }
271
272 static void psi_jit_init(struct psi_context *C)
273 {
274 C->context = psi_jit_context_init(NULL);
275 }
276
277 static inline void psi_jit_destroy_callbacks(struct psi_context *C, let_val *let_val) {
278 let_callback *cb;
279 let_func *fn = NULL;
280
281 switch (let_val->kind) {
282 case PSI_LET_CALLBACK:
283 cb = let_val->data.callback;
284
285 if (cb->decl && cb->decl->call.info) {
286 psi_jit_call_free(cb->decl->call.info);
287 }
288 fn = cb->func;
289 /* no break */
290 case PSI_LET_FUNC:
291 if (!fn) {
292 fn = let_val->data.func;
293 }
294
295 if (fn->inner) {
296 size_t i;
297
298 for (i = 0; i < fn->inner->count; ++i) {
299 psi_jit_destroy_callbacks(C, fn->inner->vals[i]);
300 }
301 }
302 break;
303 default:
304 break;
305 }
306 }
307
308 static void psi_jit_dtor(struct psi_context *C)
309 {
310 if (C->decls) {
311 size_t i;
312
313 for (i = 0; i < C->decls->count; ++i) {
314 decl *decl = C->decls->list[i];
315
316 if (decl->call.info) {
317 psi_jit_call_free(decl->call.info);
318 }
319 }
320 }
321 if (C->impls) {
322 size_t i, j;
323
324 for (i = 0; i < C->impls->count; ++i) {
325 impl *impl = C->impls->list[i];
326
327 for (j = 0; j < impl->stmts->let.count; ++j) {
328 psi_jit_destroy_callbacks(C, impl->stmts->let.list[j]->val);
329 }
330 }
331 }
332 psi_jit_context_free((void *) &C->context);
333 }
334
335 static inline void psi_jit_compile_callbacks(struct psi_context *C, let_val *let_val) {
336 struct psi_jit_call *call;
337 let_callback *cb;
338 let_func *fn = NULL;
339
340 switch (let_val->kind) {
341 case PSI_LET_CALLBACK:
342 cb = let_val->data.callback;
343 if ((call = psi_jit_call_alloc(C, cb->decl))) {
344 if (!psi_jit_call_init_callback_closure(C, call, cb)) {
345 psi_jit_call_free(call);
346 break;
347 }
348
349 cb->decl->call.sym = call->closure;
350 }
351 fn = cb->func;
352 /* no break */
353 case PSI_LET_FUNC:
354 if (!fn) {
355 fn = let_val->data.func;
356 }
357 if (fn->inner) {
358 size_t i;
359
360 for (i = 0; i < fn->inner->count; ++i) {
361 psi_jit_compile_callbacks(C, fn->inner->vals[i]);
362 }
363 }
364 break;
365 default:
366 break;
367 }
368 }
369
370 static zend_function_entry *psi_jit_compile(struct psi_context *C)
371 {
372 size_t c, i, j = 0;
373 zend_function_entry *zfe;
374 struct psi_jit_context *ctx = C->context;
375
376 if (!C->impls) {
377 return NULL;
378 }
379
380 zfe = calloc(C->impls->count + 1, sizeof(*zfe));
381 jit_context_build_start(ctx->jit);
382
383 for (i = 0; i < C->impls->count; ++i) {
384 zend_function_entry *zf = &zfe[j];
385 struct psi_jit_call *call;
386 impl *impl = C->impls->list[i];
387
388 if (!impl->decl) {
389 continue;
390 }
391
392 if ((call = psi_jit_call_alloc(C, impl->decl))) {
393 if (!psi_jit_call_init_closure(C, call, impl)) {
394 psi_jit_call_free(call);
395 continue;
396 }
397 }
398
399 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
400 zf->num_args = impl->func->args->count;
401 zf->handler = call->closure;
402 zf->arg_info = psi_internal_arginfo(impl);
403 ++j;
404
405 for (c = 0; c < impl->stmts->let.count; ++c) {
406 psi_jit_compile_callbacks(C, impl->stmts->let.list[c]->val);
407 }
408 }
409
410 for (i = 0; i < C->decls->count; ++i) {
411 decl *decl = C->decls->list[i];
412
413 if (decl->call.info) {
414 continue;
415 }
416
417 psi_jit_call_alloc(C, decl);
418 }
419
420 jit_context_build_end(ctx->jit);
421
422 return zfe;
423 }
424
425 static void psi_jit_call(struct psi_context *C, decl_callinfo *decl_call, impl_vararg *va) {
426 struct psi_jit_call *call = decl_call->info;
427
428 if (va) {
429 jit_type_t signature;
430 size_t i, nfixedargs = decl_call->argc, ntotalargs = nfixedargs + va->args->count;
431 void **params = calloc(2 * ntotalargs + 2, sizeof(void *));
432
433 for (i = 0; i < nfixedargs; ++i) {
434 params[i] = call->params[i];
435 params[i + ntotalargs + 1] = call->params[i + nfixedargs + 1];
436 }
437 for (i = 0; i < va->args->count; ++i) {
438 params[nfixedargs + i] = psi_jit_impl_type(va->types[i]);
439 params[nfixedargs + i + ntotalargs + 1] = &va->values[i];
440 }
441
442 signature = jit_type_create_signature(
443 jit_type_get_abi(call->signature),
444 jit_type_get_return(call->signature),
445 (jit_type_t *) params, ntotalargs, 1);
446 ZEND_ASSERT(signature);
447
448 jit_apply(signature, decl_call->sym, &params[ntotalargs + 1],
449 nfixedargs, *decl_call->rval);
450 jit_type_free(signature);
451 free(params);
452 } else {
453 jit_apply(call->signature, decl_call->sym, decl_call->args,
454 decl_call->argc, *decl_call->rval);
455 }
456 }
457
458 static struct psi_context_ops ops = {
459 psi_jit_init,
460 psi_jit_dtor,
461 psi_jit_compile,
462 psi_jit_call,
463 };
464
465 struct psi_context_ops *psi_libjit_ops(void)
466 {
467 return &ops;
468 }
469
470 #endif /* HAVE_LIBJIT */