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 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
);
42 static inline jit_type_t
psi_jit_token_type(token_t t
)
51 return jit_type_sbyte
;
53 return jit_type_ubyte
;
55 return jit_type_short
;
57 return jit_type_ushort
;
65 return jit_type_ulong
;
68 return jit_type_llong
;
70 return jit_type_ullong
;
73 return jit_type_sys_bool
;
75 return jit_type_sys_int
;
77 return jit_type_sys_float
;
79 return jit_type_sys_double
;
80 #ifdef HAVE_LONG_DOUBLE
81 case PSI_T_LONG_DOUBLE
:
82 return jit_type_sys_long_double
;
86 return jit_type_void_ptr
;
89 static inline jit_type_t
psi_jit_impl_type(token_t impl_type
)
93 return jit_type_sbyte
;
97 return jit_type_void_ptr
;
100 return jit_type_sys_double
;
101 EMPTY_SWITCH_DEFAULT_CASE()
107 struct psi_jit_struct_type
{
112 static void psi_jit_struct_type_dtor(void *ptr
)
114 struct psi_jit_struct_type
*type
= ptr
;
115 unsigned i
, n
= jit_type_num_fields(type
->strct
);
117 for (i
= 0; i
< n
; ++i
) {
118 jit_type_free(jit_type_get_field(type
->strct
, i
));
120 jit_type_free(type
->strct
);
125 static size_t psi_jit_struct_type_pad(jit_type_t
*els
, size_t padding
)
129 for (i
= 0; i
< padding
; ++i
) {
130 *els
++ = jit_type_copy(jit_type_sys_char
);
136 static unsigned psi_jit_struct_type_elements(struct psi_decl_struct
*strct
,
139 size_t i
= 0, argc
= psi_plist_count(strct
->args
), nels
= 0, offset
= 0,
140 maxalign
= 0, last_arg_pos
= -1;
141 struct psi_decl_arg
*darg
;
144 *fields
= calloc(argc
+ 1, sizeof(*fields
));
146 while (psi_plist_get(strct
->args
, i
++, &darg
)) {
148 size_t padding
, alignment
;
150 if (darg
->layout
->pos
== last_arg_pos
) {
151 /* skip bit fields */
154 last_arg_pos
= darg
->layout
->pos
;
156 type
= jit_type_copy(psi_jit_decl_arg_type(darg
));
158 if ((alignment
= jit_type_get_alignment(type
)) > maxalign
) {
159 maxalign
= alignment
;
162 assert(jit_type_get_size(type
) <= darg
->layout
->len
);
163 if ((padding
= psi_offset_padding(darg
->layout
->pos
- offset
, alignment
))) {
164 if (nels
+ padding
> argc
) {
166 tmp
= realloc(*fields
, (argc
+ 1) * sizeof(*fields
));
174 psi_jit_struct_type_pad(&(*fields
)[nels
], padding
);
178 assert(offset
== darg
->layout
->pos
);
180 offset
= (offset
+ darg
->layout
->len
+ alignment
- 1)
182 (*fields
)[nels
++] = type
;
185 /* apply struct alignment padding */
186 offset
= (offset
+ maxalign
- 1) & ~(maxalign
- 1);
188 assert(offset
<= strct
->size
);
189 if (offset
< strct
->size
) {
190 nels
+= psi_jit_struct_type_pad(&(*fields
)[nels
], strct
->size
- offset
);
195 static inline jit_type_t
psi_jit_decl_type(struct psi_decl_type
*type
)
197 struct psi_decl_type
*real
= psi_decl_type_get_real(type
);
199 switch (real
->type
) {
201 if (!real
->real
.strct
->engine
.type
) {
203 struct psi_jit_struct_type
*type
= calloc(1, sizeof(*type
));
205 count
= psi_jit_struct_type_elements(real
->real
.strct
, &type
->fields
);
206 type
->strct
= jit_type_create_struct(type
->fields
, count
, 0);
208 real
->real
.strct
->engine
.type
= type
;
209 real
->real
.strct
->engine
.dtor
= psi_jit_struct_type_dtor
;
212 return ((struct psi_jit_struct_type
*) real
->real
.strct
->engine
.type
)->strct
;
216 struct psi_decl_arg
*arg
;
217 psi_plist_get(real
->real
.unn
->args
, 0, &arg
);
218 return psi_jit_decl_arg_type(arg
);
222 return psi_jit_token_type(real
->type
);
225 static inline jit_type_t
psi_jit_decl_arg_type(struct psi_decl_arg
*darg
)
227 if (darg
->var
->pointer_level
) {
228 return jit_type_void_ptr
;
230 return psi_jit_decl_type(darg
->type
);
234 static inline jit_abi_t
psi_jit_abi(zend_string
*convention
)
236 if (zend_string_equals_literal(convention
, "stdcall")) {
237 return jit_abi_stdcall
;
239 if (zend_string_equals_literal(convention
, "fastcall")) {
240 return jit_abi_fastcall
;
242 return jit_abi_cdecl
;
245 struct psi_jit_context
{
247 jit_type_t signature
;
250 struct psi_jit_impl_info
{
251 struct psi_context
*context
;
252 struct psi_call_frame
*frame
;
257 struct psi_jit_callback_info
{
258 struct psi_jit_impl_info
*impl_info
;
259 struct psi_let_exp
*let_exp
;
264 struct psi_jit_decl_info
{
265 jit_type_t signature
;
269 static inline struct psi_jit_decl_info
*psi_jit_decl_init(struct psi_decl
*decl
) {
271 size_t i
, c
= psi_plist_count(decl
->args
);
272 struct psi_decl_arg
*arg
;
273 struct psi_jit_decl_info
*info
= calloc(1, sizeof(*info
) + 2 * c
* sizeof(void *));
275 for (i
= 0; psi_plist_get(decl
->args
, i
, &arg
); ++i
) {
276 info
->params
[i
] = psi_jit_decl_arg_type(arg
);
278 info
->params
[c
] = NULL
;
280 info
->signature
= jit_type_create_signature(
281 psi_jit_abi(decl
->abi
->convention
),
282 psi_jit_decl_arg_type(decl
->func
),
283 (jit_type_t
*) info
->params
,
286 if (!info
->signature
) {
296 static inline void psi_jit_decl_dtor(struct psi_decl
*decl
) {
298 struct psi_jit_decl_info
*info
= decl
->info
;
300 jit_type_free(info
->signature
);
306 static void psi_jit_handler(jit_type_t sig
, void *result
, void **args
, void *data
)
308 struct psi_impl
*impl
= data
;
309 struct psi_jit_impl_info
*info
= impl
->info
;
311 psi_context_call(info
->context
, *(zend_execute_data
**)args
[0], *(zval
**) args
[1], impl
);
314 static void psi_jit_callback(jit_type_t sig
, void *result
, void **args
, void *data
)
316 struct psi_jit_callback_info
*cb_info
= data
;
317 struct psi_call_frame_callback cb_data
;
319 assert(cb_info
->impl_info
->frame
);
321 cb_data
.cb
= cb_info
->let_exp
;
322 cb_data
.argc
= jit_type_num_params(sig
);
324 cb_data
.rval
= result
;
326 psi_call_frame_do_callback(cb_info
->impl_info
->frame
, &cb_data
);
329 static inline void psi_jit_callback_init(struct psi_jit_impl_info
*impl_info
,
330 struct psi_let_exp
*let_exp
)
332 struct psi_jit_context
*context
= impl_info
->context
->context
;
333 struct psi_jit_callback_info
*cb_info
;
334 struct psi_jit_decl_info
*decl_info
;
335 struct psi_let_callback
*cb
;
336 struct psi_let_func
*fn
= NULL
;
338 switch (let_exp
->kind
) {
339 case PSI_LET_CALLBACK
:
340 cb
= let_exp
->data
.callback
;
341 if (cb
->decl
->info
) {
342 decl_info
= cb
->decl
->info
;
344 decl_info
= psi_jit_decl_init(cb
->decl
);
347 cb_info
= calloc(1, sizeof(*cb_info
));
348 cb_info
->impl_info
= impl_info
;
349 cb_info
->let_exp
= let_exp
;
350 cb_info
->closure
= jit_closure_create(context
->jit
, decl_info
->signature
,
351 &psi_jit_callback
, cb_info
);
353 if (!cb_info
->closure
) {
359 assert(!cb
->decl
->sym
);
360 cb
->decl
->sym
= cb_info
->closure
;
366 fn
= let_exp
->data
.func
;
370 struct psi_let_exp
*inner_let
;
372 while (psi_plist_get(fn
->inner
, i
++, &inner_let
)) {
373 psi_jit_callback_init(impl_info
, inner_let
);
382 static inline void psi_jit_callback_dtor(struct psi_let_exp
*let_exp
) {
383 struct psi_let_callback
*cb
;
384 struct psi_let_func
*fn
= NULL
;
386 switch (let_exp
->kind
) {
387 case PSI_LET_CALLBACK
:
388 cb
= let_exp
->data
.callback
;
390 psi_jit_decl_dtor(cb
->decl
);
393 struct psi_jit_callback_info
*info
= cb
->info
;
396 /* The memory for the closure will be reclaimed when the context is destroyed.
397 free(info->closure); */
406 fn
= let_exp
->data
.func
;
411 struct psi_let_exp
*cb
;
413 while (psi_plist_get(fn
->inner
, i
++, &cb
)) {
414 psi_jit_callback_dtor(cb
);
423 static inline struct psi_jit_impl_info
*psi_jit_impl_init(struct psi_impl
* impl
,
424 struct psi_context
*C
)
426 struct psi_jit_context
*context
= C
->context
;
427 struct psi_jit_impl_info
*info
= calloc(1, sizeof(*info
));
428 struct psi_let_stmt
*let
;
432 info
->closure
= jit_closure_create(context
->jit
, context
->signature
,
433 &psi_jit_handler
, impl
);
435 if (!info
->closure
) {
440 while (psi_plist_get(impl
->stmts
.let
, l
++, &let
)) {
441 psi_jit_callback_init(info
, let
->exp
);
444 return impl
->info
= info
;
448 static inline void psi_jit_impl_dtor(struct psi_impl
*impl
) {
449 struct psi_jit_impl_info
*info
= impl
->info
;
450 struct psi_let_stmt
*let
;
453 while (psi_plist_get(impl
->stmts
.let
, j
++, &let
)) {
454 psi_jit_callback_dtor(let
->exp
);
459 /* The memory for the closure will be reclaimed when the context is destroyed.
460 free(info->closure); */
467 static inline struct psi_jit_context
*psi_jit_context_init(
468 struct psi_jit_context
*L
)
470 jit_type_t params
[] = {jit_type_void_ptr
, jit_type_void_ptr
};
473 L
= malloc(sizeof(*L
));
475 memset(L
, 0, sizeof(*L
));
477 L
->jit
= jit_context_create();
478 L
->signature
= jit_type_create_signature(jit_abi_cdecl
, jit_type_void
,
484 static inline void psi_jit_context_dtor(struct psi_jit_context
*L
)
486 jit_type_free(L
->signature
);
487 jit_context_destroy(L
->jit
);
490 static inline void psi_jit_context_free(struct psi_jit_context
**L
)
493 psi_jit_context_dtor(*L
);
499 static void psi_jit_init(struct psi_context
*C
)
501 C
->context
= psi_jit_context_init(NULL
);
504 static void psi_jit_dtor(struct psi_context
*C
)
508 struct psi_decl
*decl
;
510 while (psi_plist_get(C
->decls
, i
++, &decl
)) {
511 psi_jit_decl_dtor(decl
);
516 struct psi_impl
*impl
;
518 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
519 psi_jit_impl_dtor(impl
);
522 psi_jit_context_free((void *) &C
->context
);
525 static zend_function_entry
*psi_jit_compile(struct psi_context
*C
)
527 size_t i
= 0, d
= 0, nf
= 0;
528 struct psi_impl
*impl
;
529 struct psi_decl
*decl
;
530 zend_function_entry
*zfe
;
531 struct psi_jit_context
*ctx
= C
->context
;
537 zfe
= calloc(psi_plist_count(C
->impls
) + 1, sizeof(*zfe
));
538 jit_context_build_start(ctx
->jit
);
540 while (psi_plist_get(C
->impls
, i
++, &impl
)) {
541 zend_function_entry
*zf
= &zfe
[nf
];
546 if (!psi_jit_decl_init(impl
->decl
)) {
549 if (!psi_jit_impl_init(impl
, C
)) {
553 zf
->fname
= impl
->func
->name
->val
+ (impl
->func
->name
->val
[0] == '\\');
554 zf
->handler
= ((struct psi_jit_impl_info
*) impl
->info
)->closure
;
555 zf
->num_args
= psi_plist_count(impl
->func
->args
);
556 zf
->arg_info
= psi_internal_arginfo(impl
);
560 while (psi_plist_get(C
->decls
, d
++, &decl
)) {
565 psi_jit_decl_init(decl
);
568 jit_context_build_end(ctx
->jit
);
573 static inline void psi_jit_call_ex(struct psi_call_frame
*frame
) {
574 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
575 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
576 struct psi_jit_decl_info
*decl_info
= decl
->info
;
577 struct psi_jit_impl_info
*impl_info
;
578 struct psi_call_frame
*prev
;
581 impl_info
= impl
->info
;
582 prev
= impl_info
->frame
;
583 impl_info
->frame
= frame
;
585 jit_apply(decl_info
->signature
, decl
->sym
,
586 psi_call_frame_get_arg_pointers(frame
), psi_plist_count(decl
->args
),
587 psi_call_frame_get_rpointer(frame
));
589 impl_info
->frame
= prev
;
593 static inline void psi_jit_call_va(struct psi_call_frame
*frame
) {
594 jit_type_t signature
;
595 struct psi_call_frame
*prev
;
596 struct psi_decl
*decl
= psi_call_frame_get_decl(frame
);
597 struct psi_impl
*impl
= psi_call_frame_get_impl(frame
);
598 struct psi_jit_decl_info
*decl_info
= decl
->info
;
599 struct psi_jit_impl_info
*impl_info
;
600 size_t i
, va_count
, argc
;
601 jit_type_t
*param_types
;
603 argc
= psi_plist_count(decl
->args
);
604 va_count
= psi_call_frame_num_var_args(frame
);
605 param_types
= ecalloc(argc
+ va_count
+ 1, sizeof(jit_type_t
));
606 memcpy(param_types
, decl_info
->params
, argc
* sizeof(jit_type_t
));
607 for (i
= 0; i
< va_count
; ++i
) {
608 struct psi_call_frame_argument
*frame_arg
;
610 frame_arg
= psi_call_frame_get_var_argument(frame
, i
);
611 param_types
[argc
+ i
] = psi_jit_impl_type(frame_arg
->va_type
);
614 signature
= jit_type_create_signature(jit_abi_vararg
,
615 jit_type_get_return(decl_info
->signature
),
616 param_types
, argc
+ va_count
,
621 impl_info
= impl
->info
;
622 prev
= impl_info
->frame
;
623 impl_info
->frame
= frame
;
625 jit_apply(signature
, decl
->sym
,
626 psi_call_frame_get_arg_pointers(frame
), argc
,
627 psi_call_frame_get_rpointer(frame
));
629 impl_info
->frame
= prev
;
632 jit_type_free(signature
);
637 static void psi_jit_call(struct psi_call_frame
*frame
) {
638 if (psi_call_frame_num_var_args(frame
)) {
639 psi_jit_call_va(frame
);
641 psi_jit_call_ex(frame
);
645 static void *psi_jit_query(struct psi_context
*C
, enum psi_context_query q
,
649 case PSI_CONTEXT_QUERY_SELF
:
651 case PSI_CONTEXT_QUERY_TYPE
:
652 return psi_jit_impl_type(*(token_t
*) arg
);
657 static ZEND_RESULT_CODE
psi_jit_load(void)
660 jit_type_t ll_fields
[2], ull_fields
[2];
662 ll_fields
[0] = ll_fields
[1] = jit_type_long
;
663 jit_type_llong
= jit_type_create_struct(ll_fields
, 2, 1);
665 ull_fields
[0] = ull_fields
[1] = jit_type_ulong
;
666 jit_type_ullong
= jit_type_create_struct(ull_fields
, 2, 1);
671 static void psi_jit_free(void)
674 jit_type_free(jit_type_llong
);
675 jit_type_free(jit_type_ullong
);
679 static struct psi_context_ops ops
= {
689 struct psi_context_ops
*psi_libjit_ops(void)
694 #endif /* HAVE_LIBJIT */