1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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.
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 *******************************************************************************/
26 #include "php_psi_stdinc.h"
36 static jit_type_t jit_type_llong
;
37 static jit_type_t jit_type_ullong
;
40 struct psi_jit_context
{
45 struct psi_jit_callback_info
{
46 struct psi_jit_impl_info
*impl_info
;
47 struct psi_let_exp
*let_exp
;
52 struct psi_jit_decl_info
{
54 struct psi_jit_struct_info
*rv_array
;
58 struct psi_jit_extvar_info
{
70 struct psi_jit_impl_info
{
71 struct psi_context
*context
;
72 struct psi_call_frame
*frame
;
77 struct psi_jit_struct_info
{
79 struct psi_plist
*eles
;
82 static inline jit_type_t
psi_jit_token_type(token_t t
)
91 return jit_type_sbyte
;
93 return jit_type_ubyte
;
95 return jit_type_short
;
97 return jit_type_ushort
;
101 return jit_type_uint
;
103 return jit_type_long
;
105 return jit_type_ulong
;
108 return jit_type_llong
;
110 return jit_type_ullong
;
113 return jit_type_sys_bool
;
115 return jit_type_sys_int
;
117 return jit_type_sys_float
;
119 return jit_type_sys_double
;
120 #ifdef HAVE_LONG_DOUBLE
121 case PSI_T_LONG_DOUBLE
:
122 return jit_type_sys_long_double
;
126 return jit_type_void_ptr
;
129 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
133 return jit_type_sbyte
;
135 return jit_type_long
;
137 return jit_type_void_ptr
;
140 return jit_type_sys_double
;
141 EMPTY_SWITCH_DEFAULT_CASE();
146 static void psi_jit_type_free(jit_type_t
*typ_ptr
)
148 jit_type_free(*typ_ptr
);
151 static inline jit_abi_t
psi_jit_abi(zend_string
*convention
)
153 if (zend_string_equals_literal(convention
, "stdcall")) {
154 return jit_abi_stdcall
;
156 if (zend_string_equals_literal(convention
, "fastcall")) {
157 return jit_abi_fastcall
;
159 return jit_abi_cdecl
;
162 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
164 struct psi_impl
*impl
= data
;
165 struct psi_jit_impl_info
*info
= impl
->info
;
167 psi_context_call(info
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], impl
);
170 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
, void *data
)
172 struct psi_jit_callback_info
*cb_info
= data
;
173 struct psi_call_frame_callback cb_data
;
175 assert(cb_info
->impl_info
->frame
);
177 cb_data
.cb
= cb_info
->let_exp
;
178 cb_data
.argc
= jit_type_num_params(sig
);
180 cb_data
.rval
= result
;
182 psi_call_frame_do_callback(cb_info
->impl_info
->frame
, &cb_data
);
185 static bool psi_jit_load(void)
188 jit_type_t ll_fields
[2], ull_fields
[2];
190 ll_fields
[0] = ll_fields
[1] = jit_type_long
;
191 jit_type_llong
= jit_type_create_struct(ll_fields
, 2, 1);
193 ull_fields
[0] = ull_fields
[1] = jit_type_ulong
;
194 jit_type_ullong
= jit_type_create_struct(ull_fields
, 2, 1);
199 static void psi_jit_free(void)
202 jit_type_free(jit_type_llong
);
203 jit_type_free(jit_type_ullong
);
207 static bool psi_jit_init(struct psi_context
*C
)
209 struct psi_jit_context
*context
= pecalloc(1, sizeof(*context
), 1);
210 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
212 context
->jit
= jit_context_create();
218 context
->signature
= jit_type_create_signature(jit_abi_cdecl
, jit_type_void
,
220 if (!context
->signature
) {
221 jit_context_destroy(context
->jit
);
226 C
->context
= context
;
230 static void psi_jit_dtor(struct psi_context
*C
)
233 struct psi_jit_context
*context
= C
->context
;
235 jit_type_free(context
->signature
);
236 jit_context_destroy(context
->jit
);
238 pefree(C
->context
, 1);
244 static bool psi_jit_composite_init(struct psi_context
*C
,
245 struct psi_decl_arg
*darg
)
247 struct psi_jit_struct_info
*info
;
249 if (darg
->engine
.type
) {
253 info
= pecalloc(1, sizeof(*info
), 1);
254 info
->eles
= psi_plist_init((psi_plist_dtor
) psi_jit_type_free
);
255 info
->strct
= jit_type_create_struct((jit_type_t
*)
256 psi_context_composite_type_elements(C
, darg
, &info
->eles
),
257 psi_plist_count(info
->eles
), 0);
259 darg
->engine
.info
= info
;
260 darg
->engine
.type
= info
->strct
;
265 static void psi_jit_composite_dtor(struct psi_context
*C
,
266 struct psi_decl_arg
*darg
)
268 struct psi_jit_struct_info
*info
= darg
->engine
.info
;
271 darg
->engine
.info
= NULL
;
272 darg
->engine
.type
= NULL
;
274 jit_type_free(info
->strct
);
275 psi_plist_free(info
->eles
);
280 static void psi_jit_extvar_get(jit_type_t sig
, void *result
, void **args
, void *data
)
282 struct psi_decl_extvar
*evar
= data
;
284 psi_decl_extvar_get(evar
, result
);
287 static void psi_jit_extvar_set(jit_type_t sig
, void *result
, void **args
, void *data
)
289 struct psi_decl_extvar
*evar
= data
;
291 psi_decl_extvar_set(evar
, args
[0]);
294 static bool psi_jit_decl_init(struct psi_context
*, struct psi_decl
*);
296 static bool psi_jit_extvar_init(struct psi_context
*C
,
297 struct psi_decl_extvar
*evar
)
299 struct psi_jit_context
*ctx
= C
->context
;
300 struct psi_jit_extvar_info
*info
= pecalloc(1, sizeof(*info
), 1);
304 psi_jit_decl_init(C
, evar
->getter
);
305 psi_jit_decl_init(C
, evar
->setter
);
307 jit_context_build_start(ctx
->jit
);
309 info
->get
.signature
= jit_type_create_signature(jit_abi_cdecl
,
310 psi_context_decl_arg_full_type(C
, evar
->getter
->func
), NULL
, 0, 1);
311 if (!info
->get
.signature
) {
314 info
->get
.closure
= jit_closure_create(ctx
->jit
, info
->get
.signature
,
315 psi_jit_extvar_get
, evar
);
316 if (!info
->get
.closure
) {
320 info
->set
.params
[0] = psi_context_decl_arg_call_type(C
, evar
->arg
);
321 info
->set
.signature
= jit_type_create_signature(jit_abi_cdecl
,
322 psi_context_decl_arg_full_type(C
, evar
->setter
->func
),
323 info
->set
.params
, 1, 1);
324 if (!info
->set
.signature
) {
327 info
->set
.closure
= jit_closure_create(ctx
->jit
, info
->set
.signature
,
328 psi_jit_extvar_set
, evar
);
329 if (!info
->set
.closure
) {
333 evar
->getter
->sym
= info
->get
.closure
;
334 evar
->setter
->sym
= info
->set
.closure
;
336 jit_context_build_end(ctx
->jit
);
339 jit_context_build_end(ctx
->jit
);
343 static void psi_jit_extvar_dtor(struct psi_context
*C
,
344 struct psi_decl_extvar
*evar
) {
346 pefree(evar
->info
, 1);
351 static bool psi_jit_decl_init(struct psi_context
*C
, struct psi_decl
*decl
)
354 struct psi_jit_context
*ctx
= C
->context
;
355 size_t i
, c
= psi_plist_count(decl
->args
);
356 struct psi_decl_arg
*arg
;
357 struct psi_jit_decl_info
*info
= pecalloc(1,
358 sizeof(*info
) + 2 * c
* sizeof(void *), 1);
362 jit_context_build_start(ctx
->jit
);
364 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
365 info
->params
[i
] = psi_context_decl_arg_call_type(C
, arg
);
367 info
->params
[c
] = NULL
;
369 info
->signature
= jit_type_create_signature(
370 psi_jit_abi(decl
->abi
->convention
),
371 psi_context_decl_arg_full_type(C
, decl
->func
),
372 (jit_type_t
*) info
->params
, c
, 1);
374 jit_context_build_end(ctx
->jit
);
376 if (!info
->signature
) {
386 static void psi_jit_decl_dtor(struct psi_context
*C
, struct psi_decl
*decl
) {
388 struct psi_jit_decl_info
*info
= decl
->info
;
390 jit_type_free(info
->signature
);
396 static bool psi_jit_impl_init(struct psi_context
*C
,
397 struct psi_impl
*impl
, zif_handler
*zh
)
399 struct psi_jit_context
*context
= C
->context
;
400 struct psi_jit_impl_info
*info
= calloc(1, sizeof(*info
));
405 info
->closure
= jit_closure_create(context
->jit
, context
->signature
,
406 &psi_jit_handler
, impl
);
408 if (!info
->closure
) {
422 static void psi_jit_impl_dtor(struct psi_context
*C
, struct psi_impl
*impl
) {
423 struct psi_jit_impl_info
*info
= impl
->info
;
426 /* The memory for the closure will be reclaimed
427 * when the context is destroyed.
434 static bool psi_jit_cb_init(struct psi_context
*C
,
435 struct psi_let_exp
*exp
, struct psi_impl
*impl
)
437 struct psi_jit_context
*context
= C
->context
;
438 struct psi_jit_callback_info
*cb_info
;
439 struct psi_jit_decl_info
*decl_info
;
441 assert(exp
->kind
== PSI_LET_CALLBACK
);
443 if (!psi_jit_decl_init(C
, exp
->data
.callback
->decl
)) {
447 cb_info
= pecalloc(1, sizeof(*cb_info
), 1);
448 cb_info
->impl_info
= impl
->info
;
449 cb_info
->let_exp
= exp
;
451 decl_info
= exp
->data
.callback
->decl
->info
;
452 cb_info
->closure
= jit_closure_create(context
->jit
, decl_info
->signature
,
453 &psi_jit_callback
, cb_info
);
455 if (!cb_info
->closure
) {
460 assert(!exp
->data
.callback
->decl
->sym
);
461 exp
->data
.callback
->info
= cb_info
;
462 exp
->data
.callback
->decl
->sym
= cb_info
->closure
;
467 static void psi_jit_cb_dtor(struct psi_context
*C
,
468 struct psi_let_exp
*let_exp
, struct psi_impl
*impl
)
470 assert(let_exp
->kind
== PSI_LET_CALLBACK
);
472 psi_jit_decl_dtor(C
, let_exp
->data
.callback
->decl
);
474 if (let_exp
->data
.callback
->info
) {
475 struct psi_jit_callback_info
*info
= let_exp
->data
.callback
->info
;
477 /* The memory for the closure will be reclaimed
478 * when the context is destroyed.
481 let_exp
->data
.callback
->info
= NULL
;
485 static void psi_jit_call(struct psi_call_frame
*frame
) {
486 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
487 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
488 struct psi_jit_decl_info
*decl_info
= decl
->info
;
489 struct psi_jit_impl_info
*impl_info
;
490 struct psi_call_frame
*prev
;
493 impl_info
= impl
->info
;
494 prev
= impl_info
->frame
;
495 impl_info
->frame
= frame
;
497 jit_apply(decl_info
->signature
, decl
->sym
,
498 psi_call_frame_get_arg_pointers(frame
), psi_plist_count(decl
->args
),
499 psi_call_frame_get_rpointer(frame
));
501 impl_info
->frame
= prev
;
505 static void psi_jit_call_va(struct psi_call_frame
*frame
) {
506 jit_type_t signature
;
507 struct psi_call_frame
*prev
;
508 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
509 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
510 struct psi_jit_decl_info
*decl_info
= decl
->info
;
511 struct psi_jit_impl_info
*impl_info
;
512 size_t i
, va_count
, argc
;
513 jit_type_t
*param_types
;
515 argc
= psi_plist_count(decl
->args
);
516 va_count
= psi_call_frame_num_var_args(frame
);
517 param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
518 memcpy(param_types
, decl_info
->params
, argc
* sizeof(jit_type_t
));
519 for (i
= 0; i
< va_count
; ++i
) {
520 struct psi_call_frame_argument
*frame_arg
;
522 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
523 param_types
[argc
+ i
] = psi_jit_impl_type(frame_arg
->va_type
);
526 signature
= jit_type_create_signature(jit_abi_vararg
,
527 jit_type_get_return(decl_info
->signature
),
528 param_types
, argc
+ va_count
, 1);
532 impl_info
= impl
->info
;
533 prev
= impl_info
->frame
;
534 impl_info
->frame
= frame
;
536 jit_apply(signature
, decl
->sym
,
537 psi_call_frame_get_arg_pointers(frame
), argc
,
538 psi_call_frame_get_rpointer(frame
));
540 impl_info
->frame
= prev
;
543 jit_type_free(signature
);
548 static void *psi_jit_typeof_impl(struct psi_context
*C
, token_t impl_type
)
550 return psi_jit_impl_type(impl_type
);
553 static void *psi_jit_typeof_decl(struct psi_context
*C
, token_t decl_type
)
555 return psi_jit_token_type(decl_type
);
558 static void *psi_jit_copyof_type(struct psi_context
*C
, void *orig_type
)
560 return jit_type_copy(orig_type
);
563 static void psi_jit_layoutof_type(struct psi_context
*C
, void *orig_type
,
564 struct psi_layout
*l
)
566 l
->pos
= jit_type_get_alignment(orig_type
);
567 l
->len
= jit_type_get_size(orig_type
);
570 static struct psi_context_ops ops
= {
576 psi_jit_composite_init
,
577 psi_jit_composite_dtor
,
591 psi_jit_layoutof_type
,
594 struct psi_context_ops
*psi_libjit_ops(void)
599 #endif /* HAVE_LIBJIT */