update readme
[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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #else
29 # include "php_config.h"
30 #endif
31 #include "context.h"
32 #include "call.h"
33 #include "php.h"
34
35 #ifdef HAVE_LIBJIT
36
37 #include "libjit.h"
38 #include <jit/jit.h>
39
40 #if HAVE_INT128
41 static jit_type_t jit_type_llong;
42 static jit_type_t jit_type_ullong;
43 #endif
44
45 struct psi_jit_context {
46 jit_context_t jit;
47 jit_type_t signature;
48 };
49
50 struct psi_jit_callback_info {
51 struct psi_jit_impl_info *impl_info;
52 struct psi_let_exp *let_exp;
53
54 void *closure;
55 };
56
57 struct psi_jit_decl_info {
58 jit_type_t signature;
59 struct psi_jit_struct_info *rv_array;
60 void *params[1];
61 };
62
63 struct psi_jit_extvar_info {
64 struct {
65 jit_type_t signature;
66 void *closure;
67 } get;
68 struct {
69 jit_type_t signature;
70 jit_type_t params[1];
71 void *closure;
72 } set;
73 };
74
75 struct psi_jit_impl_info {
76 struct psi_context *context;
77 struct psi_call_frame *frame;
78
79 void *closure;
80 };
81
82 struct psi_jit_struct_info {
83 jit_type_t strct;
84 struct psi_plist *eles;
85 };
86
87 static inline jit_type_t psi_jit_token_type(token_t t)
88 {
89 switch (t) {
90 default:
91 assert(0);
92 /* no break */
93 case PSI_T_VOID:
94 return jit_type_void;
95 case PSI_T_INT8:
96 return jit_type_sbyte;
97 case PSI_T_UINT8:
98 return jit_type_ubyte;
99 case PSI_T_INT16:
100 return jit_type_short;
101 case PSI_T_UINT16:
102 return jit_type_ushort;
103 case PSI_T_INT32:
104 return jit_type_int;
105 case PSI_T_UINT32:
106 return jit_type_uint;
107 case PSI_T_INT64:
108 return jit_type_long;
109 case PSI_T_UINT64:
110 return jit_type_ulong;
111 #if HAVE_INT128
112 case PSI_T_INT128:
113 return jit_type_llong;
114 case PSI_T_UINT128:
115 return jit_type_ullong;
116 #endif
117 case PSI_T_BOOL:
118 return jit_type_sys_bool;
119 case PSI_T_ENUM:
120 return jit_type_sys_int;
121 case PSI_T_FLOAT:
122 return jit_type_sys_float;
123 case PSI_T_DOUBLE:
124 return jit_type_sys_double;
125 #ifdef HAVE_LONG_DOUBLE
126 case PSI_T_LONG_DOUBLE:
127 return jit_type_sys_long_double;
128 #endif
129 case PSI_T_POINTER:
130 case PSI_T_FUNCTION:
131 return jit_type_void_ptr;
132 }
133 }
134 static inline jit_type_t psi_jit_impl_type(token_t impl_type)
135 {
136 switch (impl_type) {
137 case PSI_T_BOOL:
138 return jit_type_sbyte;
139 case PSI_T_INT:
140 return jit_type_long;
141 case PSI_T_STRING:
142 return jit_type_void_ptr;
143 case PSI_T_FLOAT:
144 case PSI_T_DOUBLE:
145 return jit_type_sys_double;
146 EMPTY_SWITCH_DEFAULT_CASE();
147 }
148 return NULL;
149 }
150
151 static void psi_jit_type_free(jit_type_t *typ_ptr)
152 {
153 jit_type_free(*typ_ptr);
154 }
155
156 static inline jit_abi_t psi_jit_abi(zend_string *convention)
157 {
158 if (zend_string_equals_literal(convention, "stdcall")) {
159 return jit_abi_stdcall;
160 }
161 if (zend_string_equals_literal(convention, "fastcall")) {
162 return jit_abi_fastcall;
163 }
164 return jit_abi_cdecl;
165 }
166
167 static void psi_jit_handler(jit_type_t sig, void *result, void **args, void *data)
168 {
169 struct psi_impl *impl = data;
170 struct psi_jit_impl_info *info = impl->info;
171
172 psi_context_call(info->context, *(zend_execute_data **)args[0], *(zval **) args[1], impl);
173 }
174
175 static void psi_jit_callback(jit_type_t sig, void *result, void **args, void *data)
176 {
177 struct psi_jit_callback_info *cb_info = data;
178 struct psi_call_frame_callback cb_data;
179
180 assert(cb_info->impl_info->frame);
181
182 cb_data.cb = cb_info->let_exp;
183 cb_data.argc = jit_type_num_params(sig);
184 cb_data.argv = args;
185 cb_data.rval = result;
186
187 psi_call_frame_do_callback(cb_info->impl_info->frame, &cb_data);
188 }
189
190 static bool psi_jit_load(void)
191 {
192 #if HAVE_INT128
193 jit_type_t ll_fields[2], ull_fields[2];
194
195 ll_fields[0] = ll_fields[1] = jit_type_long;
196 jit_type_llong = jit_type_create_struct(ll_fields, 2, 1);
197
198 ull_fields[0] = ull_fields[1] = jit_type_ulong;
199 jit_type_ullong = jit_type_create_struct(ull_fields, 2, 1);
200 #endif
201 return true;
202 }
203
204 static void psi_jit_free(void)
205 {
206 #if HAVE_INT128
207 jit_type_free(jit_type_llong);
208 jit_type_free(jit_type_ullong);
209 #endif
210 }
211
212 static bool psi_jit_init(struct psi_context *C)
213 {
214 struct psi_jit_context *context = pecalloc(1, sizeof(*context), 1);
215 jit_type_t params[] = {jit_type_void_ptr, jit_type_void_ptr};
216
217 context->jit = jit_context_create();
218 if (!context->jit) {
219 pefree(context, 1);
220 return false;
221 }
222
223 context->signature = jit_type_create_signature(jit_abi_fastcall, jit_type_void,
224 params, 2, 1);
225 if (!context->signature) {
226 jit_context_destroy(context->jit);
227 pefree(context, 1);
228 return false;
229 }
230
231 C->context = context;
232 return true;
233 }
234
235 static void psi_jit_dtor(struct psi_context *C)
236 {
237 if (C->context) {
238 struct psi_jit_context *context = C->context;
239
240 jit_type_free(context->signature);
241 jit_context_destroy(context->jit);
242
243 pefree(C->context, 1);
244 C->context = NULL;
245 }
246 }
247
248
249 static bool psi_jit_composite_init(struct psi_context *C,
250 struct psi_decl_arg *darg)
251 {
252 struct psi_jit_struct_info *info;
253
254 if (darg->engine.type) {
255 return true;
256 }
257
258 info = pecalloc(1, sizeof(*info), 1);
259 info->eles = psi_plist_init((psi_plist_dtor) psi_jit_type_free);
260 psi_context_composite_type_elements(C, darg, &info->eles);
261 info->strct = jit_type_create_struct((jit_type_t *)
262 psi_plist_eles(info->eles),
263 psi_plist_count(info->eles), 0);
264
265 darg->engine.info = info;
266 darg->engine.type = info->strct;
267
268 return true;
269 }
270
271 static void psi_jit_composite_dtor(struct psi_context *C,
272 struct psi_decl_arg *darg)
273 {
274 struct psi_jit_struct_info *info = darg->engine.info;
275
276 if (info) {
277 darg->engine.info = NULL;
278 darg->engine.type = NULL;
279
280 jit_type_free(info->strct);
281 /* just free */
282 pefree(info->eles, 1);
283 pefree(info, 1);
284 }
285 }
286
287 static void psi_jit_extvar_get(jit_type_t sig, void *result, void **args, void *data)
288 {
289 struct psi_decl_extvar *evar = data;
290
291 psi_decl_extvar_get(evar, result);
292 }
293
294 static void psi_jit_extvar_set(jit_type_t sig, void *result, void **args, void *data)
295 {
296 struct psi_decl_extvar *evar = data;
297
298 psi_decl_extvar_set(evar, args[0]);
299 }
300
301 static bool psi_jit_decl_init(struct psi_context *, struct psi_decl *);
302
303 static bool psi_jit_extvar_init(struct psi_context *C,
304 struct psi_decl_extvar *evar)
305 {
306 struct psi_jit_context *ctx = C->context;
307 struct psi_jit_extvar_info *info = pecalloc(1, sizeof(*info), 1);
308
309 evar->info = info;
310
311 psi_jit_decl_init(C, evar->getter);
312 psi_jit_decl_init(C, evar->setter);
313
314 jit_context_build_start(ctx->jit);
315
316 info->get.signature = jit_type_create_signature(jit_abi_cdecl,
317 psi_context_decl_arg_call_type(C, evar->getter->func), NULL, 0, 1);
318 if (!info->get.signature) {
319 goto failure;
320 }
321 info->get.closure = jit_closure_create(ctx->jit, info->get.signature,
322 psi_jit_extvar_get, evar);
323 if (!info->get.closure) {
324 goto failure;
325 }
326
327 info->set.params[0] = psi_context_decl_arg_call_type(C, evar->arg);
328 info->set.signature = jit_type_create_signature(jit_abi_cdecl,
329 psi_context_decl_arg_call_type(C, evar->setter->func),
330 info->set.params, 1, 1);
331 if (!info->set.signature) {
332 goto failure;
333 }
334 info->set.closure = jit_closure_create(ctx->jit, info->set.signature,
335 psi_jit_extvar_set, evar);
336 if (!info->set.closure) {
337 goto failure;
338 }
339
340 evar->getter->sym = info->get.closure;
341 evar->setter->sym = info->set.closure;
342
343 jit_context_build_end(ctx->jit);
344 return true;
345 failure: ;
346 jit_context_build_end(ctx->jit);
347 return false;
348 }
349
350 static void psi_jit_extvar_dtor(struct psi_context *C,
351 struct psi_decl_extvar *evar) {
352 if (evar->info) {
353 pefree(evar->info, 1);
354 evar->info = NULL;
355 }
356 }
357
358 static bool psi_jit_decl_init(struct psi_context *C, struct psi_decl *decl)
359 {
360 if (!decl->info) {
361 struct psi_jit_context *ctx = C->context;
362 size_t i, c = psi_plist_count(decl->args);
363 struct psi_decl_arg *arg;
364 struct psi_jit_decl_info *info = pecalloc(1,
365 sizeof(*info) + 2 * c * sizeof(void *), 1);
366
367 decl->info = info;
368
369 jit_context_build_start(ctx->jit);
370
371 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
372 info->params[i] = psi_context_decl_arg_call_type(C, arg);
373 }
374 info->params[c] = NULL;
375
376 info->signature = jit_type_create_signature(
377 psi_jit_abi(decl->abi->convention),
378 psi_context_decl_arg_full_type(C, decl->func),
379 (jit_type_t *) info->params, c, 1);
380
381 jit_context_build_end(ctx->jit);
382
383 if (!info->signature) {
384 pefree(info, 1);
385 decl->info = NULL;
386 return false;
387 }
388 }
389
390 return true;
391 }
392
393 static void psi_jit_decl_dtor(struct psi_context *C, struct psi_decl *decl) {
394 if (decl->info) {
395 struct psi_jit_decl_info *info = decl->info;
396
397 jit_type_free(info->signature);
398 pefree(info, 1);
399 decl->info = NULL;
400 }
401 }
402
403 static bool psi_jit_impl_init(struct psi_context *C,
404 struct psi_impl *impl, zif_handler *zh)
405 {
406 struct psi_jit_context *context = C->context;
407 struct psi_jit_impl_info *info = calloc(1, sizeof(*info));
408
409 impl->info = info;
410 info->context = C;
411
412 info->closure = jit_closure_create(context->jit, context->signature,
413 &psi_jit_handler, impl);
414
415 if (!info->closure) {
416 goto failure;
417 }
418
419 *zh = info->closure;
420 return true;
421
422 failure: ;
423 impl->info = NULL;
424 pefree(info, 1);
425 return false;
426 }
427
428
429 static void psi_jit_impl_dtor(struct psi_context *C, struct psi_impl *impl) {
430 struct psi_jit_impl_info *info = impl->info;
431
432 if (info) {
433 /* The memory for the closure will be reclaimed
434 * when the context is destroyed.
435 */
436 pefree(info, 1);
437 impl->info = NULL;
438 }
439 }
440
441 static bool psi_jit_cb_init(struct psi_context *C,
442 struct psi_let_exp *exp, struct psi_impl *impl)
443 {
444 struct psi_jit_context *context = C->context;
445 struct psi_jit_callback_info *cb_info;
446 struct psi_jit_decl_info *decl_info;
447
448 assert(exp->kind == PSI_LET_CALLBACK);
449
450 if (!psi_jit_decl_init(C, exp->data.callback->decl)) {
451 return false;
452 }
453
454 cb_info = pecalloc(1, sizeof(*cb_info), 1);
455 cb_info->impl_info = impl->info;
456 cb_info->let_exp = exp;
457
458 decl_info = exp->data.callback->decl->info;
459 cb_info->closure = jit_closure_create(context->jit, decl_info->signature,
460 &psi_jit_callback, cb_info);
461
462 if (!cb_info->closure) {
463 free(cb_info);
464 return false;
465 }
466
467 assert(!exp->data.callback->decl->sym);
468 exp->data.callback->info = cb_info;
469 exp->data.callback->decl->sym = cb_info->closure;
470
471 return true;
472 }
473
474 static void psi_jit_cb_dtor(struct psi_context *C,
475 struct psi_let_exp *let_exp, struct psi_impl *impl)
476 {
477 assert(let_exp->kind == PSI_LET_CALLBACK);
478
479 psi_jit_decl_dtor(C, let_exp->data.callback->decl);
480
481 if (let_exp->data.callback->info) {
482 struct psi_jit_callback_info *info = let_exp->data.callback->info;
483
484 /* The memory for the closure will be reclaimed
485 * when the context is destroyed.
486 */
487 pefree(info, 1);
488 let_exp->data.callback->info = NULL;
489 }
490 }
491
492 static void psi_jit_call(struct psi_call_frame *frame) {
493 struct psi_decl *decl = psi_call_frame_get_decl(frame);
494 struct psi_impl *impl = psi_call_frame_get_impl(frame);
495 struct psi_jit_decl_info *decl_info = decl->info;
496 struct psi_jit_impl_info *impl_info;
497 struct psi_call_frame *prev;
498
499 if (impl) {
500 impl_info = impl->info;
501 prev = impl_info->frame;
502 impl_info->frame = frame;
503 }
504 jit_apply(decl_info->signature, decl->sym,
505 psi_call_frame_get_arg_pointers(frame), psi_plist_count(decl->args),
506 psi_call_frame_get_rpointer(frame));
507 if (impl) {
508 impl_info->frame = prev;
509 }
510 }
511
512 static void psi_jit_call_va(struct psi_call_frame *frame) {
513 jit_type_t signature;
514 struct psi_call_frame *prev;
515 struct psi_decl *decl = psi_call_frame_get_decl(frame);
516 struct psi_impl *impl = psi_call_frame_get_impl(frame);
517 struct psi_jit_decl_info *decl_info = decl->info;
518 struct psi_jit_impl_info *impl_info;
519 size_t i, va_count, argc;
520 jit_type_t *param_types;
521
522 argc = psi_plist_count(decl->args);
523 va_count = psi_call_frame_num_var_args(frame);
524 param_types = ecalloc(argc + va_count + 1, sizeof(jit_type_t));
525 memcpy(param_types, decl_info->params, argc * sizeof(jit_type_t));
526 for (i = 0; i < va_count; ++i) {
527 struct psi_call_frame_argument *frame_arg;
528
529 frame_arg = psi_call_frame_get_var_argument(frame, i);
530 param_types[argc + i] = psi_jit_impl_type(frame_arg->va_type);
531 }
532
533 signature = jit_type_create_signature(jit_abi_vararg,
534 jit_type_get_return(decl_info->signature),
535 param_types, argc + va_count, 1);
536 assert(signature);
537
538 if (impl) {
539 impl_info = impl->info;
540 prev = impl_info->frame;
541 impl_info->frame = frame;
542 }
543 jit_apply(signature, decl->sym,
544 psi_call_frame_get_arg_pointers(frame), argc,
545 psi_call_frame_get_rpointer(frame));
546 if (impl) {
547 impl_info->frame = prev;
548 }
549
550 jit_type_free(signature);
551
552 efree(param_types);
553 }
554
555 static void *psi_jit_typeof_impl(struct psi_context *C, token_t impl_type)
556 {
557 return psi_jit_impl_type(impl_type);
558 }
559
560 static void *psi_jit_typeof_decl(struct psi_context *C, token_t decl_type)
561 {
562 return psi_jit_token_type(decl_type);
563 }
564
565 static void *psi_jit_copyof_type(struct psi_context *C, void *orig_type)
566 {
567 return jit_type_copy(orig_type);
568 }
569
570 static void psi_jit_layoutof_type(struct psi_context *C, void *orig_type,
571 struct psi_layout *l)
572 {
573 l->pos = jit_type_get_alignment(orig_type);
574 l->len = jit_type_get_size(orig_type);
575
576 assert(l->pos);
577 assert(l->len);
578 }
579
580 static struct psi_context_ops ops = {
581 "libjit",
582 psi_jit_load,
583 psi_jit_free,
584 psi_jit_init,
585 psi_jit_dtor,
586 psi_jit_composite_init,
587 psi_jit_composite_dtor,
588 psi_jit_extvar_init,
589 psi_jit_extvar_dtor,
590 psi_jit_decl_init,
591 psi_jit_decl_dtor,
592 psi_jit_impl_init,
593 psi_jit_impl_dtor,
594 psi_jit_cb_init,
595 psi_jit_cb_dtor,
596 psi_jit_call,
597 psi_jit_call_va,
598 psi_jit_typeof_impl,
599 psi_jit_typeof_decl,
600 psi_jit_copyof_type,
601 psi_jit_layoutof_type,
602 };
603
604 struct psi_context_ops *psi_libjit_ops(void)
605 {
606 return &ops;
607 }
608
609 #endif /* HAVE_LIBJIT */