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