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