decl_var: fix fqn
[m6w6/ext-psi] / src / libjit.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_LIBJIT
32
33 #include <jit/jit.h>
34
35 static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg);
36
37 static inline jit_type_t psi_jit_token_type(token_t t)
38 {
39 switch (t) {
40 default:
41 assert(0);
42 /* no break */
43 case PSI_T_VOID:
44 return jit_type_void;
45 case PSI_T_INT8:
46 return jit_type_sbyte;
47 case PSI_T_UINT8:
48 return jit_type_ubyte;
49 case PSI_T_INT16:
50 return jit_type_short;
51 case PSI_T_UINT16:
52 return jit_type_ushort;
53 case PSI_T_INT32:
54 return jit_type_int;
55 case PSI_T_UINT32:
56 return jit_type_uint;
57 case PSI_T_INT64:
58 return jit_type_long;
59 case PSI_T_UINT64:
60 return jit_type_ulong;
61 case PSI_T_BOOL:
62 return jit_type_sys_bool;
63 case PSI_T_ENUM:
64 return jit_type_sys_int;
65 case PSI_T_FLOAT:
66 return jit_type_sys_float;
67 case PSI_T_DOUBLE:
68 return jit_type_sys_double;
69 #ifdef HAVE_LONG_DOUBLE
70 case PSI_T_LONG_DOUBLE:
71 return jit_type_sys_long_double;
72 #endif
73 case PSI_T_POINTER:
74 case PSI_T_FUNCTION:
75 return jit_type_void_ptr;
76 }
77 }
78 static inline jit_type_t psi_jit_impl_type(token_t impl_type)
79 {
80 switch (impl_type) {
81 case PSI_T_BOOL:
82 return jit_type_sbyte;
83 case PSI_T_INT:
84 return jit_type_long;
85 case PSI_T_STRING:
86 return jit_type_void_ptr;
87 case PSI_T_FLOAT:
88 case PSI_T_DOUBLE:
89 return jit_type_sys_double;
90 EMPTY_SWITCH_DEFAULT_CASE()
91 ;
92 }
93 return NULL;
94 }
95
96 struct psi_jit_struct_type {
97 jit_type_t strct;
98 jit_type_t *fields;
99 };
100
101 static void psi_jit_struct_type_dtor(void *ptr)
102 {
103 struct psi_jit_struct_type *type = ptr;
104 unsigned i, n = jit_type_num_fields(type->strct);
105
106 for (i = 0; i < n; ++i) {
107 jit_type_free(jit_type_get_field(type->strct, i));
108 }
109 jit_type_free(type->strct);
110 free(type->fields);
111 free(type);
112 }
113
114 static size_t psi_jit_struct_type_pad(jit_type_t *els, size_t padding)
115 {
116 size_t i;
117
118 for (i = 0; i < padding; ++i) {
119 *els++ = jit_type_copy(jit_type_sys_char);
120 }
121
122 return padding;
123 }
124
125 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct *strct,
126 jit_type_t **fields)
127 {
128 size_t i = 0, argc = psi_plist_count(strct->args), nels = 0, offset = 0,
129 maxalign = 0, last_arg_pos = -1;
130 struct psi_decl_arg *darg;
131 jit_type_t *tmp;
132
133 *fields = calloc(argc + 1, sizeof(*fields));
134
135 while (psi_plist_get(strct->args, i++, &darg)) {
136 jit_type_t type;
137 size_t padding, alignment;
138
139 if (darg->layout->pos == last_arg_pos) {
140 /* skip bit fields */
141 continue;
142 }
143 last_arg_pos = darg->layout->pos;
144
145 type = jit_type_copy(psi_jit_decl_arg_type(darg));
146
147 if ((alignment = jit_type_get_alignment(type)) > maxalign) {
148 maxalign = alignment;
149 }
150
151 assert(jit_type_get_size(type) <= darg->layout->len);
152 if ((padding = psi_offset_padding(darg->layout->pos - offset, alignment))) {
153 if (nels + padding > argc) {
154 argc += padding;
155 tmp = realloc(*fields, (argc + 1) * sizeof(*fields));
156 if (tmp) {
157 *fields = tmp;
158 } else {
159 free(*fields);
160 return 0;
161 }
162 }
163 psi_jit_struct_type_pad(&(*fields)[nels], padding);
164 nels += padding;
165 offset += padding;
166 }
167 assert(offset == darg->layout->pos);
168
169 offset = (offset + darg->layout->len + alignment - 1)
170 & ~(alignment - 1);
171 (*fields)[nels++] = type;
172 }
173
174 /* apply struct alignment padding */
175 offset = (offset + maxalign - 1) & ~(maxalign - 1);
176
177 assert(offset <= strct->size);
178 if (offset < strct->size) {
179 nels += psi_jit_struct_type_pad(&(*fields)[nels], strct->size - offset);
180 }
181
182 return nels;
183 }
184 static inline jit_type_t psi_jit_decl_type(struct psi_decl_type *type)
185 {
186 struct psi_decl_type *real = psi_decl_type_get_real(type);
187
188 switch (real->type) {
189 case PSI_T_STRUCT:
190 if (!real->real.strct->engine.type) {
191 unsigned count;
192 struct psi_jit_struct_type *type = calloc(1, sizeof(*type));
193
194 count = psi_jit_struct_type_elements(real->real.strct, &type->fields);
195 type->strct = jit_type_create_struct(type->fields, count, 0);
196
197 real->real.strct->engine.type = type;
198 real->real.strct->engine.dtor = psi_jit_struct_type_dtor;
199 }
200
201 return ((struct psi_jit_struct_type *) real->real.strct->engine.type)->strct;
202
203 case PSI_T_UNION:
204 {
205 struct psi_decl_arg *arg;
206 psi_plist_get(real->real.unn->args, 0, &arg);
207 return psi_jit_decl_arg_type(arg);
208 }
209
210 default:
211 return psi_jit_token_type(real->type);
212 }
213 }
214 static inline jit_type_t psi_jit_decl_arg_type(struct psi_decl_arg *darg)
215 {
216 if (darg->var->pointer_level) {
217 return jit_type_void_ptr;
218 } else {
219 return psi_jit_decl_type(darg->type);
220 }
221 }
222
223 static inline jit_abi_t psi_jit_abi(const char *convention)
224 {
225 if (!strcasecmp(convention, "stdcall")) {
226 return jit_abi_stdcall;
227 }
228 if (!strcasecmp(convention, "fastcall")) {
229 return jit_abi_fastcall;
230 }
231 return jit_abi_cdecl;
232 }
233
234 struct psi_jit_context {
235 jit_context_t jit;
236 jit_type_t signature;
237 };
238
239 struct psi_jit_impl_info {
240 struct psi_context *context;
241 struct psi_call_frame *frame;
242
243 void *closure;
244 };
245
246 struct psi_jit_callback_info {
247 struct psi_jit_impl_info *impl_info;
248 struct psi_let_exp *let_exp;
249
250 void *closure;
251 };
252
253 struct psi_jit_decl_info {
254 jit_type_t signature;
255 void *params[1];
256 };
257
258 static inline struct psi_jit_decl_info *psi_jit_decl_init(struct psi_decl *decl) {
259 if (!decl->info) {
260 size_t i, c = psi_plist_count(decl->args);
261 struct psi_decl_arg *arg;
262 struct psi_jit_decl_info *info = calloc(1, sizeof(*info) + 2 * c * sizeof(void *));
263
264 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
265 info->params[i] = psi_jit_decl_arg_type(arg);
266 }
267 info->params[c] = NULL;
268
269 info->signature = jit_type_create_signature(
270 psi_jit_abi(decl->abi->convention),
271 psi_jit_decl_arg_type(decl->func),
272 (jit_type_t *) info->params,
273 c, 1);
274
275 if (!info->signature) {
276 free(info);
277 } else {
278 decl->info = info;
279 }
280 }
281
282 return decl->info;
283 }
284
285 static inline void psi_jit_decl_dtor(struct psi_decl *decl) {
286 if (decl->info) {
287 struct psi_jit_decl_info *info = decl->info;
288
289 jit_type_free(info->signature);
290 free(info);
291 decl->info = NULL;
292 }
293 }
294
295 static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
296 {
297 struct psi_impl *impl = data;
298 struct psi_jit_impl_info *info = impl->info;
299
300 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **) args[1], impl);
301 }
302
303 static void psi_jit_callback(jit_type_t sig, void *result, void **args, void *data)
304 {
305 struct psi_jit_callback_info *cb_info = data;
306 struct psi_call_frame_callback cb_data;
307
308 assert(cb_info->impl_info->frame);
309
310 cb_data.cb = cb_info->let_exp;
311 cb_data.argc = jit_type_num_params(sig);
312 cb_data.argv = args;
313 cb_data.rval = result;
314
315 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
316 }
317
318 static inline void psi_jit_callback_init(struct psi_jit_impl_info *impl_info,
319 struct psi_let_exp *let_exp)
320 {
321 struct psi_jit_context *context = impl_info->context->context;
322 struct psi_jit_callback_info *cb_info;
323 struct psi_jit_decl_info *decl_info;
324 struct psi_let_callback *cb;
325 struct psi_let_func *fn = NULL;
326
327 switch (let_exp->kind) {
328 case PSI_LET_CALLBACK:
329 cb = let_exp->data.callback;
330 if (cb->decl->info) {
331 decl_info = cb->decl->info;
332 } else {
333 decl_info = psi_jit_decl_init(cb->decl);
334 }
335
336 cb_info = calloc(1, sizeof(*cb_info));
337 cb_info->impl_info = impl_info;
338 cb_info->let_exp = let_exp;
339 cb_info->closure = jit_closure_create(context->jit, decl_info->signature,
340 &psi_jit_callback, cb_info);
341
342 if (!cb_info->closure) {
343 free(cb_info);
344 break;
345 }
346 cb->info = cb_info;
347
348 assert(!cb->decl->sym);
349 cb->decl->sym = cb_info->closure;
350 fn = cb->func;
351 /* no break */
352
353 case PSI_LET_FUNC:
354 if (!fn) {
355 fn = let_exp->data.func;
356 }
357 if (fn->inner) {
358 size_t i = 0;
359 struct psi_let_exp *inner_let;
360
361 while (psi_plist_get(fn->inner, i++, &inner_let)) {
362 psi_jit_callback_init(impl_info, inner_let);
363 }
364 }
365 break;
366 default:
367 break;
368 }
369 }
370
371 static inline void psi_jit_callback_dtor(struct psi_let_exp *let_exp) {
372 struct psi_let_callback *cb;
373 struct psi_let_func *fn = NULL;
374
375 switch (let_exp->kind) {
376 case PSI_LET_CALLBACK:
377 cb = let_exp->data.callback;
378
379 psi_jit_decl_dtor(cb->decl);
380
381 if (cb->info) {
382 struct psi_jit_callback_info *info = cb->info;
383
384 if (info->closure) {
385 /* The memory for the closure will be reclaimed when the context is destroyed.
386 free(info->closure); */
387 }
388 free(info);
389 cb->info = NULL;
390 }
391 fn = cb->func;
392 /* no break */
393 case PSI_LET_FUNC:
394 if (!fn) {
395 fn = let_exp->data.func;
396 }
397
398 if (fn->inner) {
399 size_t i = 0;
400 struct psi_let_exp *cb;
401
402 while (psi_plist_get(fn->inner, i++, &cb)) {
403 psi_jit_callback_dtor(cb);
404 }
405 }
406 break;
407 default:
408 break;
409 }
410 }
411
412 static inline struct psi_jit_impl_info *psi_jit_impl_init(struct psi_impl * impl,
413 struct psi_context *C)
414 {
415 struct psi_jit_context *context = C->context;
416 struct psi_jit_impl_info *info = calloc(1, sizeof(*info));
417 struct psi_let_stmt *let;
418 size_t l = 0;
419
420 info->context = C;
421 info->closure = jit_closure_create(context->jit, context->signature,
422 &psi_jit_handler, impl);
423
424 if (!info->closure) {
425 free(info);
426 return NULL;
427 }
428
429 while (psi_plist_get(impl->stmts.let, l++, &let)) {
430 psi_jit_callback_init(info, let->exp);
431 }
432
433 return impl->info = info;
434 }
435
436
437 static inline void psi_jit_impl_dtor(struct psi_impl *impl) {
438 struct psi_jit_impl_info *info = impl->info;
439 struct psi_let_stmt *let;
440 size_t j = 0;
441
442 while (psi_plist_get(impl->stmts.let, j++, &let)) {
443 psi_jit_callback_dtor(let->exp);
444 }
445
446 if (info) {
447 if (info->closure) {
448 /* The memory for the closure will be reclaimed when the context is destroyed.
449 free(info->closure); */
450 }
451 free(info);
452 impl->info = NULL;
453 }
454 }
455
456 static inline struct psi_jit_context *psi_jit_context_init(
457 struct psi_jit_context *L)
458 {
459 jit_type_t params[] = {jit_type_void_ptr, jit_type_void_ptr};
460
461 if (!L) {
462 L = malloc(sizeof(*L));
463 }
464 memset(L, 0, sizeof(*L));
465
466 L->jit = jit_context_create();
467 L->signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void,
468 params, 2, 1);
469
470 return L;
471 }
472
473 static inline void psi_jit_context_dtor(struct psi_jit_context *L)
474 {
475 jit_type_free(L->signature);
476 jit_context_destroy(L->jit);
477 }
478
479 static inline void psi_jit_context_free(struct psi_jit_context **L)
480 {
481 if (*L) {
482 psi_jit_context_dtor(*L);
483 free(*L);
484 *L = NULL;
485 }
486 }
487
488 static void psi_jit_init(struct psi_context *C)
489 {
490 C->context = psi_jit_context_init(NULL);
491 }
492
493 static void psi_jit_dtor(struct psi_context *C)
494 {
495 if (C->decls) {
496 size_t i = 0;
497 struct psi_decl *decl;
498
499 while (psi_plist_get(C->decls, i++, &decl)) {
500 psi_jit_decl_dtor(decl);
501 }
502 }
503 if (C->impls) {
504 size_t i = 0;
505 struct psi_impl *impl;
506
507 while (psi_plist_get(C->impls, i++, &impl)) {
508 psi_jit_impl_dtor(impl);
509 }
510 }
511 psi_jit_context_free((void *) &C->context);
512 }
513
514 static zend_function_entry *psi_jit_compile(struct psi_context *C)
515 {
516 size_t i = 0, d = 0, nf = 0;
517 struct psi_impl *impl;
518 struct psi_decl *decl;
519 zend_function_entry *zfe;
520 struct psi_jit_context *ctx = C->context;
521
522 if (!C->impls) {
523 return NULL;
524 }
525
526 zfe = calloc(psi_plist_count(C->impls) + 1, sizeof(*zfe));
527 jit_context_build_start(ctx->jit);
528
529 while (psi_plist_get(C->impls, i++, &impl)) {
530 zend_function_entry *zf = &zfe[nf];
531
532 if (!impl->decl) {
533 continue;
534 }
535 if (!psi_jit_decl_init(impl->decl)) {
536 continue;
537 }
538 if (!psi_jit_impl_init(impl, C)) {
539 continue;
540 }
541
542 zf->fname = impl->func->name + (impl->func->name[0] == '\\');
543 zf->handler = ((struct psi_jit_impl_info *) impl->info)->closure;
544 zf->num_args = psi_plist_count(impl->func->args);
545 zf->arg_info = psi_internal_arginfo(impl);
546 ++nf;
547 }
548
549 while (psi_plist_get(C->decls, d++, &decl)) {
550 if (decl->info) {
551 continue;
552 }
553
554 psi_jit_decl_init(decl);
555 }
556
557 jit_context_build_end(ctx->jit);
558
559 return zfe;
560 }
561
562 static inline void psi_jit_call_ex(struct psi_call_frame *frame) {
563 struct psi_decl *decl = psi_call_frame_get_decl(frame);
564 struct psi_impl *impl = psi_call_frame_get_impl(frame);
565 struct psi_jit_decl_info *decl_info = decl->info;
566 struct psi_jit_impl_info *impl_info;
567 struct psi_call_frame *prev;
568
569 if (impl) {
570 impl_info = impl->info;
571 prev = impl_info->frame;
572 impl_info->frame = frame;
573 }
574 jit_apply(decl_info->signature, decl->sym,
575 psi_call_frame_get_arg_pointers(frame), psi_plist_count(decl->args),
576 psi_call_frame_get_rpointer(frame));
577 if (impl) {
578 impl_info->frame = prev;
579 }
580 }
581
582 static inline void psi_jit_call_va(struct psi_call_frame *frame) {
583 jit_type_t signature;
584 struct psi_call_frame *prev;
585 struct psi_decl *decl = psi_call_frame_get_decl(frame);
586 struct psi_impl *impl = psi_call_frame_get_impl(frame);
587 struct psi_jit_decl_info *decl_info = decl->info;
588 struct psi_jit_impl_info *impl_info;
589 size_t i, va_count, argc;
590 jit_type_t *param_types;
591
592 argc = psi_plist_count(decl->args);
593 va_count = psi_call_frame_num_var_args(frame);
594 param_types = ecalloc(argc + va_count + 1, sizeof(jit_type_t));
595 memcpy(param_types, decl_info->params, argc * sizeof(jit_type_t));
596 for (i = 0; i < va_count; ++i) {
597 struct psi_call_frame_argument *frame_arg;
598
599 frame_arg = psi_call_frame_get_var_argument(frame, i);
600 param_types[argc + i] = psi_jit_impl_type(frame_arg->va_type);
601 }
602
603 signature = jit_type_create_signature(jit_abi_vararg,
604 jit_type_get_return(decl_info->signature),
605 param_types, argc + va_count,
606 1);
607 assert(signature);
608
609 if (impl) {
610 impl_info = impl->info;
611 prev = impl_info->frame;
612 impl_info->frame = frame;
613 }
614 jit_apply(signature, decl->sym,
615 psi_call_frame_get_arg_pointers(frame), argc,
616 psi_call_frame_get_rpointer(frame));
617 if (impl) {
618 impl_info->frame = prev;
619 }
620
621 jit_type_free(signature);
622
623 efree(param_types);
624 }
625
626 static void psi_jit_call(struct psi_call_frame *frame) {
627 if (psi_call_frame_num_var_args(frame)) {
628 psi_jit_call_va(frame);
629 } else {
630 psi_jit_call_ex(frame);
631 }
632 }
633
634 static void *psi_jit_query(struct psi_context *C, enum psi_context_query q,
635 void *arg)
636 {
637 switch (q) {
638 case PSI_CONTEXT_QUERY_SELF:
639 return "jit";
640 case PSI_CONTEXT_QUERY_TYPE:
641 return psi_jit_impl_type(*(token_t *) arg);
642 }
643 return NULL;
644 }
645
646 static struct psi_context_ops ops = {
647 psi_jit_init,
648 psi_jit_dtor,
649 psi_jit_compile,
650 psi_jit_call,
651 psi_jit_query
652 };
653
654 struct psi_context_ops *psi_libjit_ops(void)
655 {
656 return &ops;
657 }
658
659 #endif /* HAVE_LIBJIT */