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